<commit_before>/*
 * Cymbalum, Molecular Simulation in Rust
 * Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
*/

use ::constants::K_BOLTZMANN;
use ::types::Vector3D;
use ::universe::Universe;

/// The compute trait allow to compute properties of an universe, whithout
/// modifying this universe. The Output type is the type of the computed
/// property.
pub trait Compute {
    type Output;
    /// Compute the property
    fn compute(&self, universe: &Universe) -> Self::Output;
}

/// Compute all the forces acting on the system, and return a vector of
/// force acting on each particles
pub struct Forces;
impl Compute for Forces {
    type Output = Vec<Vector3D>;
    fn compute(&self, universe: &Universe) -> Vec<Vector3D> {
        let mut res: Vec<Vector3D> = Vec::with_capacity(universe.size());
        for _ in 0..universe.size() {
            res.push(Vector3D::new(0.0, 0.0, 0.0));
        }

        for i in 0..universe.size() {
            for j in (i+1)..universe.size() {
                for potential in universe.pairs(i, j) {
                    let d = universe.wrap_vector(i, j);
                    let dn = d.normalized();
                    let f = potential.force(d.norm());
                    res[i] = res[i] + f * dn;
                    res[j] = res[j] - f * dn;
                }
            }
        }
        return res;
    }
}

/// Compute the potential energy of the system
pub struct PotentialEnergy;
impl Compute for PotentialEnergy {
    type Output = f64;
    fn compute(&self, universe: &Universe) -> f64 {
        let mut res = 0.0;
        for i in 0..universe.size() {
            for j in (i+1)..universe.size() {
                for potential in universe.pairs(i, j) {
                    let d = universe.wrap_vector(i, j);
                    res += potential.force(d.norm());
                }
            }
        }
        return res;
    }
}

/// Compute the kinetic energy of the system
pub struct KineticEnergy;
impl Compute for KineticEnergy {
    type Output = f64;
    fn compute(&self, universe: &Universe) -> f64 {
        let mut res = 0.0;
        for i in 0..universe.size() {
            let part = &universe[i];
            res += 0.5 * part.mass() * part.velocity().norm2();
        }
        return res;
    }
}

/// Compute the total energy of the system
pub struct TotalEnergy;
impl Compute for TotalEnergy {
    type Output = f64;
    fn compute(&self, universe: &Universe) -> f64 {
        let kinetic = KineticEnergy.compute(universe);
        let potential = PotentialEnergy.compute(universe);
        return kinetic + potential;
    }
}

/// Compute the instananeous temperature of the system
pub struct Temperature;
impl Compute for Temperature {
    type Output = f64;
    fn compute(&self, universe: &Universe) -> f64 {
        let kinetic = KineticEnergy.compute(universe);
        let natoms = universe.size() as f64;
        return 1.0/K_BOLTZMANN * 2.0 * kinetic/(3.0 * natoms);
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use ::types::Vector3D;
    use ::universe::{Universe, Particle};
    use ::potentials::Harmonic;
    use ::units;

    const EPS : f64 = 1e-8;

    fn testing_universe() -> Universe {
        let mut universe = Universe::new();
        universe.add_particle(Particle::new("F"));
        universe[0].set_position(Vector3D::new(0.0, 0.0, 0.0));
        universe[0].set_velocity(Vector3D::new(0.0, 0.02, 0.0));

        universe.add_particle(Particle::new("F"));
        universe[1].set_position(Vector3D::new(1.3, 0.0, 0.0));
        universe[1].set_velocity(Vector3D::new(0.01, 0.0, 0.0));

        universe.add_pair_interaction("F", "F",
            Harmonic{k: units::from(300.0, "kJ/mol/A^2").unwrap(), r0: units::from(1.2, "A").unwrap()});
        return universe;
    }

    #[test]
    fn forces() {
        let universe = &testing_universe();
        let res = Forces.compute(universe);

        let mut forces_tot = Vector3D::new(0.0, 0.0, 0.0);
        forces_tot.x += res[0].x + res[1].x;
        forces_tot.x += res[0].y + res[1].y;
        forces_tot.x += res[0].z + res[1].z;

        assert_eq!(forces_tot, Vector3D::new(0.0, 0.0, 0.0));

        assert_approx_eq!(res[0].x, 3e-3, EPS);
        assert_approx_eq!(res[0].y, 0.0, EPS);
        assert_approx_eq!(res[0].y, 0.0, EPS);

        assert_approx_eq!(res[1].x, -3e-3, EPS);
        assert_approx_eq!(res[1].y, 0.0, EPS);
        assert_approx_eq!(res[1].y, 0.0, EPS);
    }

    #[test]
    fn energy() {
        let universe = &testing_universe();
        let kinetic = KineticEnergy.compute(universe);
        let potential = PotentialEnergy.compute(universe);
        let total = TotalEnergy.compute(universe);

        assert_eq!(kinetic + potential, total);
        assert_eq!(kinetic, 0.004749600887298584);
        assert_approx_eq!(potential, -3e-3, EPS);

        assert_eq!(kinetic, universe.kinetic_energy());
        assert_eq!(potential, universe.potential_energy());
        assert_eq!(total, universe.total_energy());
    }

    #[test]
    fn temperature() {
        let universe = &testing_universe();
        let T = Temperature.compute(universe);
        assert_eq!(T, 1904.1522295848426);
        assert_eq!(T, universe.temperature());
    }
}
<commit_msg>Fix typo<commit_after>/*
 * Cymbalum, Molecular Simulation in Rust
 * Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
*/

use ::constants::K_BOLTZMANN;
use ::types::Vector3D;
use ::universe::Universe;

/// The compute trait allow to compute properties of an universe, whithout
/// modifying this universe. The Output type is the type of the computed
/// property.
pub trait Compute {
    type Output;
    /// Compute the property
    fn compute(&self, universe: &Universe) -> Self::Output;
}

/// Compute all the forces acting on the system, and return a vector of
/// force acting on each particles
pub struct Forces;
impl Compute for Forces {
    type Output = Vec<Vector3D>;
    fn compute(&self, universe: &Universe) -> Vec<Vector3D> {
        let mut res: Vec<Vector3D> = Vec::with_capacity(universe.size());
        for _ in 0..universe.size() {
            res.push(Vector3D::new(0.0, 0.0, 0.0));
        }

        for i in 0..universe.size() {
            for j in (i+1)..universe.size() {
                for potential in universe.pairs(i, j) {
                    let d = universe.wrap_vector(i, j);
                    let dn = d.normalized();
                    let f = potential.force(d.norm());
                    res[i] = res[i] + f * dn;
                    res[j] = res[j] - f * dn;
                }
            }
        }
        return res;
    }
}

/// Compute the potential energy of the system
pub struct PotentialEnergy;
impl Compute for PotentialEnergy {
    type Output = f64;
    fn compute(&self, universe: &Universe) -> f64 {
        let mut res = 0.0;
        for i in 0..universe.size() {
            for j in (i+1)..universe.size() {
                for potential in universe.pairs(i, j) {
                    let d = universe.wrap_vector(i, j);
                    res += potential.energy(d.norm());
                }
            }
        }
        return res;
    }
}

/// Compute the kinetic energy of the system
pub struct KineticEnergy;
impl Compute for KineticEnergy {
    type Output = f64;
    fn compute(&self, universe: &Universe) -> f64 {
        let mut res = 0.0;
        for i in 0..universe.size() {
            let part = &universe[i];
            res += 0.5 * part.mass() * part.velocity().norm2();
        }
        return res;
    }
}

/// Compute the total energy of the system
pub struct TotalEnergy;
impl Compute for TotalEnergy {
    type Output = f64;
    fn compute(&self, universe: &Universe) -> f64 {
        let kinetic = KineticEnergy.compute(universe);
        let potential = PotentialEnergy.compute(universe);
        return kinetic + potential;
    }
}

/// Compute the instananeous temperature of the system
pub struct Temperature;
impl Compute for Temperature {
    type Output = f64;
    fn compute(&self, universe: &Universe) -> f64 {
        let kinetic = KineticEnergy.compute(universe);
        let natoms = universe.size() as f64;
        return 1.0/K_BOLTZMANN * 2.0 * kinetic/(3.0 * natoms);
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use ::types::Vector3D;
    use ::universe::{Universe, Particle};
    use ::potentials::Harmonic;
    use ::units;

    const EPS : f64 = 1e-8;

    fn testing_universe() -> Universe {
        let mut universe = Universe::new();
        universe.add_particle(Particle::new("F"));
        universe[0].set_position(Vector3D::new(0.0, 0.0, 0.0));
        universe[0].set_velocity(Vector3D::new(0.0, 0.02, 0.0));

        universe.add_particle(Particle::new("F"));
        universe[1].set_position(Vector3D::new(1.3, 0.0, 0.0));
        universe[1].set_velocity(Vector3D::new(0.01, 0.0, 0.0));

        universe.add_pair_interaction("F", "F",
            Harmonic{k: units::from(300.0, "kJ/mol/A^2").unwrap(), r0: units::from(1.2, "A").unwrap()});
        return universe;
    }

    #[test]
    fn forces() {
        let universe = &testing_universe();
        let res = Forces.compute(universe);

        let mut forces_tot = Vector3D::new(0.0, 0.0, 0.0);
        forces_tot.x += res[0].x + res[1].x;
        forces_tot.x += res[0].y + res[1].y;
        forces_tot.x += res[0].z + res[1].z;

        assert_eq!(forces_tot, Vector3D::new(0.0, 0.0, 0.0));

        assert_approx_eq!(res[0].x, 3e-3, EPS);
        assert_approx_eq!(res[0].y, 0.0, EPS);
        assert_approx_eq!(res[0].y, 0.0, EPS);

        assert_approx_eq!(res[1].x, -3e-3, EPS);
        assert_approx_eq!(res[1].y, 0.0, EPS);
        assert_approx_eq!(res[1].y, 0.0, EPS);
    }

    #[test]
    fn energy() {
        let universe = &testing_universe();
        let kinetic = KineticEnergy.compute(universe);
        let potential = PotentialEnergy.compute(universe);
        let total = TotalEnergy.compute(universe);

        assert_eq!(kinetic + potential, total);
        assert_eq!(kinetic, 0.004749600887298584);
        assert_approx_eq!(potential, 1.5e-4, EPS);

        assert_eq!(kinetic, universe.kinetic_energy());
        assert_eq!(potential, universe.potential_energy());
        assert_eq!(total, universe.total_energy());
    }

    #[test]
    fn temperature() {
        let universe = &testing_universe();
        let T = Temperature.compute(universe);
        assert_eq!(T, 1904.1522295848426);
        assert_eq!(T, universe.temperature());
    }
}
<|endoftext|>


<commit_before>//! TODO Documentation

use std::{panic, ptr};
use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;

use wayland_sys::server::WAYLAND_SERVER_HANDLE;
use wayland_sys::server::signal::wl_signal_add;
use wlroots_sys::{timespec, wlr_subsurface, wlr_surface, wlr_surface_get_main_surface,
                  wlr_surface_get_matrix, wlr_surface_has_buffer, wlr_surface_make_subsurface,
                  wlr_surface_send_enter, wlr_surface_send_frame_done, wlr_surface_send_leave,
                  wlr_surface_subsurface_at};

use super::{Subsurface, SubsurfaceHandle, SubsurfaceManager, SurfaceState};
use Output;
use errors::{UpgradeHandleErr, UpgradeHandleResult};
use render::Texture;
use utils::c_to_rust_string;

/// The state stored in the wlr_surface user data.
struct InternalSurfaceState {
    /// Used to reconstruct a SurfaceHandle from just an *mut wlr_surface.
    handle: Weak<AtomicBool>,
    /// Weak reference to the manager for the list of subsurfaces.
    /// This is here so that we can reconstruct the Surface from a SurfaceHandle.
    subsurfaces_manager: Weak<Box<SubsurfaceManager>>
}

/// A Wayland object that represents the data that we display on the screen.
///
/// Most surfaces come from Wayland clients, though they can also be created
/// by the compositor directly.
#[derive(Debug)]
pub struct Surface {
    /// The structe that ensures weak handles to this structure are still alive.
    ///
    /// They contain weak handles, and will safely not use dead memory when this
    /// is freed by wlroots.
    ///
    /// If this is `None`, then this is from an upgraded `SurfaceHandle`, and
    /// the operations are **unchecked**.
    /// This is means safe operations might fail, but only if you use the unsafe
    /// marked function `upgrade` on a `SurfaceHandle`.
    liveliness: Option<Rc<AtomicBool>>,
    /// The manager of the list of subsurfaces for this surface.
    ///
    /// When the subsurface destruction event fires the manager will deal with
    /// updating the list.
    ///
    /// When you have a reference to the Surface you can access its children
    /// through the getter for this list.
    subsurfaces_manager: Rc<Box<SubsurfaceManager>>,
    /// The pointer to the wlroots object that wraps a wl_surface.
    surface: *mut wlr_surface
}

/// See `Surface` for more information on how to use this structure.
#[derive(Clone, Debug)]
pub struct SurfaceHandle {
    /// The Rc that ensures that this handle is still alive.
    ///
    /// When wlroots deallocates the pointer associated with this handle,
    /// this can no longer be used.
    handle: Weak<AtomicBool>,
    /// Weak reference to the manager of the list of subsurfaces for this surface.
    ///
    /// Used when reconstructing a `Surface` so that we can access
    /// the list of subsurfaces.
    subsurfaces_manager: Weak<Box<SubsurfaceManager>>,
    /// The pointer to the wlroots object that wraps a wl_surface.
    surface: *mut wlr_surface
}

impl Surface {
    pub(crate) unsafe fn new(surface: *mut wlr_surface) -> Self {
        if !(*surface).data.is_null() {
            panic!("Tried to construct a Surface from an already initialized wlr_surface");
        }
        let liveliness = Rc::new(AtomicBool::new(false));
        let handle = Rc::downgrade(&liveliness);
        let subsurfaces_manager = Rc::new(Surface::create_manager(surface));
        let weak_manager = Rc::downgrade(&subsurfaces_manager);
        (*surface).data = Box::into_raw(Box::new(InternalSurfaceState { handle,
                                                                        subsurfaces_manager:
                                                                            weak_manager }))
                          as _;
        let liveliness = Some(liveliness);
        Surface { liveliness,
                  subsurfaces_manager,
                  surface }
    }

    /// Create the subsurface manager and ensures theat the listeners are
    /// set up correctly to listen for subsurface creation and deletion.
    fn create_manager(surface: *mut wlr_surface) -> Box<SubsurfaceManager> {
        unsafe {
            let mut subsurfaces = vec![];
            wl_list_for_each!((*surface).subsurface_list, parent_link,
                              (subsurface: wlr_subsurface) => {
                                  subsurfaces.push(Subsurface::new(subsurface))
                              });
            let mut manager = SubsurfaceManager::new(subsurfaces);
            for sub_surface in &mut manager.subsurfaces() {
                wl_signal_add(&mut (*sub_surface.as_ptr()).events.destroy as *mut _ as _,
                              manager.subsurface_destroyed_listener() as _);
            }
            wl_signal_add(&mut (*surface).events.new_subsurface as *mut _ as _,
                          manager.subsurface_created_listener() as _);
            manager
        }
    }

    pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_surface {
        self.surface
    }

    /// Get the surface state.
    pub fn current_state<'surface>(&'surface mut self) -> SurfaceState<'surface> {
        unsafe {
            let state = (*self.surface).current;
            SurfaceState::new(state)
        }
    }

    /// Get the pending surface state.
    pub fn pending_state<'surface>(&'surface mut self) -> SurfaceState<'surface> {
        unsafe {
            let state = (*self.surface).current;
            SurfaceState::new(state)
        }
    }

    /// Gets a list of handles to the `Subsurface`s of this `Surface`.
    pub fn subsurfaces(&self) -> Vec<SubsurfaceHandle> {
        self.subsurfaces_manager.subsurfaces()
    }

    /// Get the texture of this surface.
    pub fn texture(&self) -> Texture {
        unsafe { Texture::from_ptr((*self.surface).texture) }
    }

    /// Get the lifetime bound role (if one exists) for this surface.
    pub fn role(&self) -> Option<String> {
        unsafe { c_to_rust_string((*self.surface).role) }
    }

    /// Gets a matrix you can pass into wlr_render_with_matrix to display this
    /// surface.
    ///
    /// `matrix` is the output matrix, `projection` is the wlr_output
    /// projection matrix, and `transform` is any additional transformations you want
    /// to perform on the surface (or None/the identity matrix if you don't).
    ///
    /// `transform` is used before the surface is scaled, so its geometry extends
    /// from 0 to 1 in both dimensions.
    pub fn get_matrix<'a, T>(&mut self,
                             matrix: &mut [f32; 16],
                             projection: &[f32; 16],
                             transform: T)
        where T: Into<Option<&'a [f32; 16]>>
    {
        let transform = transform.into()
                                 .map(|transform| transform as *const _)
                                 .unwrap_or_else(|| ptr::null());
        unsafe { wlr_surface_get_matrix(self.surface, matrix, projection, transform) }
    }

    /// Whether or not this surface currently has an attached buffer.
    ///
    /// A surface has an attached buffer when it commits with a non-null buffer in its pending
    /// state.
    ///
    /// A surface will not have a buffer if it has never committed one, has
    /// committed a null buffer, or something went wrong with uploading the buffer.
    pub fn has_buffer(&self) -> bool {
        unsafe { wlr_surface_has_buffer(self.surface) }
    }

    /// Find a subsurface within this surface at the surface-local coordinates.
    ///
    /// Returns the surface and coordinates in the topmost surface coordinate system
    /// or None if no subsurface is found at that location.
    pub fn subsurface_at(&mut self,
                         sx: f64,
                         sy: f64,
                         sub_x: &mut f64,
                         sub_y: &mut f64)
                         -> Option<SubsurfaceHandle> {
        unsafe {
            let surface = wlr_surface_subsurface_at(self.surface, sx, sy, sub_x, sub_y);
            if surface.is_null() {
                return None
            }
            for subsurface in self.subsurfaces() {
                if subsurface.as_ptr() == surface {
                    return Some(subsurface)
                }
            }
            return None
        }
    }

    /// Create the subsurface implementation for this surface.
    pub fn make_subsurface(&mut self, parent: &mut Surface, id: u32) {
        unsafe { wlr_surface_make_subsurface(self.surface, parent.as_ptr(), id) }
    }

    /// Get the top of the subsurface tree for this surface.
    pub fn get_main_surface(&self) -> Option<SurfaceHandle> {
        unsafe {
            let surface = wlr_surface_get_main_surface(self.surface);
            if surface.is_null() {
                None
            } else {
                Some(SurfaceHandle::from_ptr(surface))
            }
        }
    }

    pub fn send_enter(&mut self, output: &mut Output) {
        unsafe { wlr_surface_send_enter(self.surface, output.as_ptr()) }
    }

    pub fn send_leave(&mut self, output: &mut Output) {
        unsafe { wlr_surface_send_leave(self.surface, output.as_ptr()) }
    }

    /// Send the frame done event.
    pub fn send_frame_done(&mut self, duration: Duration) {
        unsafe {
            // FIXME
            // This is converting from a u64 -> i64
            // Something bad could happen!
            let when = timespec { tv_sec: duration.as_secs() as i64,
                                  tv_nsec: duration.subsec_nanos() as i64 };
            wlr_surface_send_frame_done(self.surface, &when);
        }
    }

    /// Get the matrix used to convert the internal byte buffer to use in the
    /// surface.
    pub fn buffer_to_surface_matrix(&self) -> [f32; 16] {
        unsafe { (*self.surface).buffer_to_surface_matrix }
    }

    /// Get the matrix used to convert the surface back to the internal byte
    /// buffer.
    pub fn surface_to_buffer_matrix(&self) -> [f32; 16] {
        unsafe { (*self.surface).surface_to_buffer_matrix }
    }

    /// Creates a weak reference to a `Surface`.
    ///
    /// # Panics
    /// If this `Surface` is a previously upgraded `SurfaceHandle`
    /// then this function will panic.
    pub fn weak_reference(&self) -> SurfaceHandle {
        let arc = self.liveliness.as_ref()
                      .expect("Cannot downgrade a previously upgraded OutputHandle");
        SurfaceHandle { handle: Rc::downgrade(arc),
                        surface: self.surface,
                        subsurfaces_manager: Rc::downgrade(&self.subsurfaces_manager) }
    }

    /// Manually set the lock used to determine if a double-borrow is
    /// occuring on this structure.
    ///
    /// # Panics
    /// Panics when trying to set the lock on an upgraded handle.
    pub(crate) unsafe fn set_lock(&self, val: bool) {
        self.liveliness.as_ref()
            .expect("Tried to set lock on borrowed Surface")
            .store(val, Ordering::Release);
    }

    unsafe fn from_handle(handle: &SurfaceHandle) -> Self {
        let data = (*handle.surface).data as *mut InternalSurfaceState;
        let subsurfaces_manager = (*data).subsurfaces_manager
                                         .clone()
                                         .upgrade()
                                         .expect("Could not upgrade subsurfaces list");
        Surface { liveliness: None,
                  subsurfaces_manager,
                  surface: handle.surface }
    }
}

impl SurfaceHandle {
    /// Creates an SurfaceHandle from the raw pointer, using the saved
    /// user data to recreate the memory model.
    pub(crate) unsafe fn from_ptr(surface: *mut wlr_surface) -> Self {
        let data = (*surface).data as *mut InternalSurfaceState;
        let handle = (*data).handle.clone();
        let subsurfaces_manager = (*data).subsurfaces_manager.clone();
        SurfaceHandle { handle,
                        surface,
                        subsurfaces_manager }
    }

    /// Upgrades the surface handle to a reference to the backing `Surface`.
    ///
    /// # Unsafety
    /// This function is unsafe, because it creates an unbound `Surface`
    /// which may live forever..
    /// But no surface lives forever and might be disconnected at any time.
    pub(crate) unsafe fn upgrade(&self) -> UpgradeHandleResult<Surface> {
        self.handle.upgrade()
            .ok_or(UpgradeHandleErr::AlreadyDropped)
            // NOTE
            // We drop the Rc here because having two would allow a dangling
            // pointer to exist!
            .and_then(|check| {
                if check.load(Ordering::Acquire) {
                    return Err(UpgradeHandleErr::AlreadyBorrowed)
                }
                check.store(true, Ordering::Release);
                Ok(Surface::from_handle(self))
            })
    }

    /// Run a function on the referenced Surface, if it still exists
    ///
    /// Returns the result of the function, if successful
    ///
    /// # Safety
    /// By enforcing a rather harsh limit on the lifetime of the surface
    /// to a short lived scope of an anonymous function,
    /// this function ensures the Surface does not live longer
    /// than it exists.
    ///
    /// # Panics
    /// This function will panic if multiple mutable borrows are detected.
    /// This will happen if you call `upgrade` directly within this callback,
    /// or if you run this function within the another run to the same `Surface`.
    ///
    /// So don't nest `run` calls and everything will be ok :).
    pub fn run<F, R>(&mut self, runner: F) -> UpgradeHandleResult<R>
        where F: FnOnce(&mut Surface) -> R
    {
        let mut surface = unsafe { self.upgrade()? };
        let res = panic::catch_unwind(panic::AssertUnwindSafe(|| runner(&mut surface)));
        self.handle.upgrade().map(|check| {
                                      // Sanity check that it hasn't been tampered with.
                                      if !check.load(Ordering::Acquire) {
                                          wlr_log!(L_ERROR,
                                                   "After running surface callback, mutable lock \
                                                    was false for: {:?}",
                                                   surface);
                                          panic!("Lock in incorrect state!");
                                      }
                                      check.store(false, Ordering::Release);
                                  });
        match res {
            Ok(res) => Ok(res),
            Err(err) => panic::resume_unwind(err)
        }
    }
}

impl Drop for Surface {
    fn drop(&mut self) {
        match self.liveliness {
            None => return,
            Some(ref liveliness) => {
                if Rc::strong_count(liveliness) != 1 {
                    return
                }
                wlr_log!(L_DEBUG, "Dropped surface {:p}", self.surface);
                let weak_count = Rc::weak_count(liveliness);
                if weak_count > 0 {
                    wlr_log!(L_DEBUG,
                             "Still {} weak pointers to Surface {:p}",
                             weak_count,
                             self.surface);
                }
            }
        }
        unsafe {
            let _ = Box::from_raw((*self.surface).data as *mut InternalSurfaceState);
            let manager = Rc::into_raw(self.subsurfaces_manager.clone()) as *mut SubsurfaceManager;
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*(*manager).subsurface_created_listener()).link as *mut _ as _);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*(*manager).subsurface_destroyed_listener()).link as *mut _ as _);
        }
    }
}
<commit_msg>Fixed subsurface manager destruction<commit_after>//! TODO Documentation

use std::{panic, ptr};
use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;

use wayland_sys::server::WAYLAND_SERVER_HANDLE;
use wayland_sys::server::signal::wl_signal_add;
use wlroots_sys::{timespec, wlr_subsurface, wlr_surface, wlr_surface_get_main_surface,
                  wlr_surface_get_matrix, wlr_surface_has_buffer, wlr_surface_make_subsurface,
                  wlr_surface_send_enter, wlr_surface_send_frame_done, wlr_surface_send_leave,
                  wlr_surface_subsurface_at};

use super::{Subsurface, SubsurfaceHandle, SubsurfaceManager, SurfaceState};
use Output;
use errors::{UpgradeHandleErr, UpgradeHandleResult};
use render::Texture;
use utils::c_to_rust_string;

/// The state stored in the wlr_surface user data.
struct InternalSurfaceState {
    /// Used to reconstruct a SurfaceHandle from just an *mut wlr_surface.
    handle: Weak<AtomicBool>,
    /// Weak reference to the manager for the list of subsurfaces.
    /// This is here so that we can reconstruct the Surface from a SurfaceHandle.
    subsurfaces_manager: Weak<Box<SubsurfaceManager>>
}

/// A Wayland object that represents the data that we display on the screen.
///
/// Most surfaces come from Wayland clients, though they can also be created
/// by the compositor directly.
#[derive(Debug)]
pub struct Surface {
    /// The structe that ensures weak handles to this structure are still alive.
    ///
    /// They contain weak handles, and will safely not use dead memory when this
    /// is freed by wlroots.
    ///
    /// If this is `None`, then this is from an upgraded `SurfaceHandle`, and
    /// the operations are **unchecked**.
    /// This is means safe operations might fail, but only if you use the unsafe
    /// marked function `upgrade` on a `SurfaceHandle`.
    liveliness: Option<Rc<AtomicBool>>,
    /// The manager of the list of subsurfaces for this surface.
    ///
    /// When the subsurface destruction event fires the manager will deal with
    /// updating the list.
    ///
    /// When you have a reference to the Surface you can access its children
    /// through the getter for this list.
    subsurfaces_manager: Rc<Box<SubsurfaceManager>>,
    /// The pointer to the wlroots object that wraps a wl_surface.
    surface: *mut wlr_surface
}

/// See `Surface` for more information on how to use this structure.
#[derive(Clone, Debug)]
pub struct SurfaceHandle {
    /// The Rc that ensures that this handle is still alive.
    ///
    /// When wlroots deallocates the pointer associated with this handle,
    /// this can no longer be used.
    handle: Weak<AtomicBool>,
    /// Weak reference to the manager of the list of subsurfaces for this surface.
    ///
    /// Used when reconstructing a `Surface` so that we can access
    /// the list of subsurfaces.
    subsurfaces_manager: Weak<Box<SubsurfaceManager>>,
    /// The pointer to the wlroots object that wraps a wl_surface.
    surface: *mut wlr_surface
}

impl Surface {
    pub(crate) unsafe fn new(surface: *mut wlr_surface) -> Self {
        if !(*surface).data.is_null() {
            panic!("Tried to construct a Surface from an already initialized wlr_surface");
        }
        let liveliness = Rc::new(AtomicBool::new(false));
        let handle = Rc::downgrade(&liveliness);
        let subsurfaces_manager = Rc::new(Surface::create_manager(surface));
        let weak_manager = Rc::downgrade(&subsurfaces_manager);
        (*surface).data = Box::into_raw(Box::new(InternalSurfaceState { handle,
                                                                        subsurfaces_manager:
                                                                            weak_manager }))
                          as _;
        let liveliness = Some(liveliness);
        Surface { liveliness,
                  subsurfaces_manager,
                  surface }
    }

    /// Create the subsurface manager and ensures theat the listeners are
    /// set up correctly to listen for subsurface creation and deletion.
    fn create_manager(surface: *mut wlr_surface) -> Box<SubsurfaceManager> {
        unsafe {
            let mut subsurfaces = vec![];
            wl_list_for_each!((*surface).subsurface_list, parent_link,
                              (subsurface: wlr_subsurface) => {
                                  subsurfaces.push(Subsurface::new(subsurface))
                              });
            let mut manager = SubsurfaceManager::new(subsurfaces);
            for sub_surface in &mut manager.subsurfaces() {
                wl_signal_add(&mut (*sub_surface.as_ptr()).events.destroy as *mut _ as _,
                              manager.subsurface_destroyed_listener() as _);
            }
            wl_signal_add(&mut (*surface).events.new_subsurface as *mut _ as _,
                          manager.subsurface_created_listener() as _);
            manager
        }
    }

    pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_surface {
        self.surface
    }

    /// Get the surface state.
    pub fn current_state<'surface>(&'surface mut self) -> SurfaceState<'surface> {
        unsafe {
            let state = (*self.surface).current;
            SurfaceState::new(state)
        }
    }

    /// Get the pending surface state.
    pub fn pending_state<'surface>(&'surface mut self) -> SurfaceState<'surface> {
        unsafe {
            let state = (*self.surface).current;
            SurfaceState::new(state)
        }
    }

    /// Gets a list of handles to the `Subsurface`s of this `Surface`.
    pub fn subsurfaces(&self) -> Vec<SubsurfaceHandle> {
        self.subsurfaces_manager.subsurfaces()
    }

    /// Get the texture of this surface.
    pub fn texture(&self) -> Texture {
        unsafe { Texture::from_ptr((*self.surface).texture) }
    }

    /// Get the lifetime bound role (if one exists) for this surface.
    pub fn role(&self) -> Option<String> {
        unsafe { c_to_rust_string((*self.surface).role) }
    }

    /// Gets a matrix you can pass into wlr_render_with_matrix to display this
    /// surface.
    ///
    /// `matrix` is the output matrix, `projection` is the wlr_output
    /// projection matrix, and `transform` is any additional transformations you want
    /// to perform on the surface (or None/the identity matrix if you don't).
    ///
    /// `transform` is used before the surface is scaled, so its geometry extends
    /// from 0 to 1 in both dimensions.
    pub fn get_matrix<'a, T>(&mut self,
                             matrix: &mut [f32; 16],
                             projection: &[f32; 16],
                             transform: T)
        where T: Into<Option<&'a [f32; 16]>>
    {
        let transform = transform.into()
                                 .map(|transform| transform as *const _)
                                 .unwrap_or_else(|| ptr::null());
        unsafe { wlr_surface_get_matrix(self.surface, matrix, projection, transform) }
    }

    /// Whether or not this surface currently has an attached buffer.
    ///
    /// A surface has an attached buffer when it commits with a non-null buffer in its pending
    /// state.
    ///
    /// A surface will not have a buffer if it has never committed one, has
    /// committed a null buffer, or something went wrong with uploading the buffer.
    pub fn has_buffer(&self) -> bool {
        unsafe { wlr_surface_has_buffer(self.surface) }
    }

    /// Find a subsurface within this surface at the surface-local coordinates.
    ///
    /// Returns the surface and coordinates in the topmost surface coordinate system
    /// or None if no subsurface is found at that location.
    pub fn subsurface_at(&mut self,
                         sx: f64,
                         sy: f64,
                         sub_x: &mut f64,
                         sub_y: &mut f64)
                         -> Option<SubsurfaceHandle> {
        unsafe {
            let surface = wlr_surface_subsurface_at(self.surface, sx, sy, sub_x, sub_y);
            if surface.is_null() {
                return None
            }
            for subsurface in self.subsurfaces() {
                if subsurface.as_ptr() == surface {
                    return Some(subsurface)
                }
            }
            return None
        }
    }

    /// Create the subsurface implementation for this surface.
    pub fn make_subsurface(&mut self, parent: &mut Surface, id: u32) {
        unsafe { wlr_surface_make_subsurface(self.surface, parent.as_ptr(), id) }
    }

    /// Get the top of the subsurface tree for this surface.
    pub fn get_main_surface(&self) -> Option<SurfaceHandle> {
        unsafe {
            let surface = wlr_surface_get_main_surface(self.surface);
            if surface.is_null() {
                None
            } else {
                Some(SurfaceHandle::from_ptr(surface))
            }
        }
    }

    pub fn send_enter(&mut self, output: &mut Output) {
        unsafe { wlr_surface_send_enter(self.surface, output.as_ptr()) }
    }

    pub fn send_leave(&mut self, output: &mut Output) {
        unsafe { wlr_surface_send_leave(self.surface, output.as_ptr()) }
    }

    /// Send the frame done event.
    pub fn send_frame_done(&mut self, duration: Duration) {
        unsafe {
            // FIXME
            // This is converting from a u64 -> i64
            // Something bad could happen!
            let when = timespec { tv_sec: duration.as_secs() as i64,
                                  tv_nsec: duration.subsec_nanos() as i64 };
            wlr_surface_send_frame_done(self.surface, &when);
        }
    }

    /// Get the matrix used to convert the internal byte buffer to use in the
    /// surface.
    pub fn buffer_to_surface_matrix(&self) -> [f32; 16] {
        unsafe { (*self.surface).buffer_to_surface_matrix }
    }

    /// Get the matrix used to convert the surface back to the internal byte
    /// buffer.
    pub fn surface_to_buffer_matrix(&self) -> [f32; 16] {
        unsafe { (*self.surface).surface_to_buffer_matrix }
    }

    /// Creates a weak reference to a `Surface`.
    ///
    /// # Panics
    /// If this `Surface` is a previously upgraded `SurfaceHandle`
    /// then this function will panic.
    pub fn weak_reference(&self) -> SurfaceHandle {
        let arc = self.liveliness.as_ref()
                      .expect("Cannot downgrade a previously upgraded OutputHandle");
        SurfaceHandle { handle: Rc::downgrade(arc),
                        surface: self.surface,
                        subsurfaces_manager: Rc::downgrade(&self.subsurfaces_manager) }
    }

    /// Manually set the lock used to determine if a double-borrow is
    /// occuring on this structure.
    ///
    /// # Panics
    /// Panics when trying to set the lock on an upgraded handle.
    pub(crate) unsafe fn set_lock(&self, val: bool) {
        self.liveliness.as_ref()
            .expect("Tried to set lock on borrowed Surface")
            .store(val, Ordering::Release);
    }

    unsafe fn from_handle(handle: &SurfaceHandle) -> Self {
        let data = (*handle.surface).data as *mut InternalSurfaceState;
        let subsurfaces_manager = (*data).subsurfaces_manager
                                         .clone()
                                         .upgrade()
                                         .expect("Could not upgrade subsurfaces list");
        Surface { liveliness: None,
                  subsurfaces_manager,
                  surface: handle.surface }
    }
}

impl SurfaceHandle {
    /// Creates an SurfaceHandle from the raw pointer, using the saved
    /// user data to recreate the memory model.
    pub(crate) unsafe fn from_ptr(surface: *mut wlr_surface) -> Self {
        let data = (*surface).data as *mut InternalSurfaceState;
        let handle = (*data).handle.clone();
        let subsurfaces_manager = (*data).subsurfaces_manager.clone();
        SurfaceHandle { handle,
                        surface,
                        subsurfaces_manager }
    }

    /// Upgrades the surface handle to a reference to the backing `Surface`.
    ///
    /// # Unsafety
    /// This function is unsafe, because it creates an unbound `Surface`
    /// which may live forever..
    /// But no surface lives forever and might be disconnected at any time.
    pub(crate) unsafe fn upgrade(&self) -> UpgradeHandleResult<Surface> {
        self.handle.upgrade()
            .ok_or(UpgradeHandleErr::AlreadyDropped)
            // NOTE
            // We drop the Rc here because having two would allow a dangling
            // pointer to exist!
            .and_then(|check| {
                if check.load(Ordering::Acquire) {
                    return Err(UpgradeHandleErr::AlreadyBorrowed)
                }
                check.store(true, Ordering::Release);
                Ok(Surface::from_handle(self))
            })
    }

    /// Run a function on the referenced Surface, if it still exists
    ///
    /// Returns the result of the function, if successful
    ///
    /// # Safety
    /// By enforcing a rather harsh limit on the lifetime of the surface
    /// to a short lived scope of an anonymous function,
    /// this function ensures the Surface does not live longer
    /// than it exists.
    ///
    /// # Panics
    /// This function will panic if multiple mutable borrows are detected.
    /// This will happen if you call `upgrade` directly within this callback,
    /// or if you run this function within the another run to the same `Surface`.
    ///
    /// So don't nest `run` calls and everything will be ok :).
    pub fn run<F, R>(&mut self, runner: F) -> UpgradeHandleResult<R>
        where F: FnOnce(&mut Surface) -> R
    {
        let mut surface = unsafe { self.upgrade()? };
        let res = panic::catch_unwind(panic::AssertUnwindSafe(|| runner(&mut surface)));
        self.handle.upgrade().map(|check| {
                                      // Sanity check that it hasn't been tampered with.
                                      if !check.load(Ordering::Acquire) {
                                          wlr_log!(L_ERROR,
                                                   "After running surface callback, mutable lock \
                                                    was false for: {:?}",
                                                   surface);
                                          panic!("Lock in incorrect state!");
                                      }
                                      check.store(false, Ordering::Release);
                                  });
        match res {
            Ok(res) => Ok(res),
            Err(err) => panic::resume_unwind(err)
        }
    }
}

impl Drop for Surface {
    fn drop(&mut self) {
        match self.liveliness {
            None => return,
            Some(ref liveliness) => {
                if Rc::strong_count(liveliness) != 1 {
                    return
                }
                wlr_log!(L_DEBUG, "Dropped surface {:p}", self.surface);
                let weak_count = Rc::weak_count(liveliness);
                if weak_count > 0 {
                    wlr_log!(L_DEBUG,
                             "Still {} weak pointers to Surface {:p}",
                             weak_count,
                             self.surface);
                }
            }
        }
        unsafe {
            let _ = Box::from_raw((*self.surface).data as *mut InternalSurfaceState);
            let manager =
                Rc::into_raw(self.subsurfaces_manager.clone()) as *mut Box<SubsurfaceManager>;
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*(*manager).subsurface_created_listener()).link as *mut _ as _);
            for _ in &mut (*manager).subsurfaces() {
                ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                              wl_list_remove,
                              &mut (*(*manager).subsurface_destroyed_listener()).link as *mut _
                              as _);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io::Cursor;
use byteorder::{BigEndian, ReadBytesExt};

pub enum PseudoPort {
    PhysicalPort(u16),
    InPort,
    Table,
    Normal,
    Flood,
    AllPorts,
    Controller(u64),
    Local
}

pub enum Action {
    Output(PseudoPort),
}

#[repr(u8)]
#[derive(Copy, Clone)]
pub enum MsgCode {
    Hello,
    Error,
    EchoReq,
    EchoResp,
    Vendor,
    FeaturesReq,
    FeaturesResp,
    GetConfigReq,
    GetConfigResp,
    SetConfig,
    PacketIn,
    FlowRemoved,
    PortStatus,
    PacketOut,
    FlowMod,
    PortMod,
    StatsReq,
    StatsResp,
    BarrierReq,
    BarrierResp,
    QueueGetConfigReq,
    QueueGetConfigResp,
}

pub struct Capabilities {
    pub flow_stats: bool,
    pub table_stats: bool,
    pub port_stats: bool,
    pub group_stats: bool,
    pub ip_reasm: bool,
    pub queue_stats: bool,
    pub port_blocked: bool,
}

pub struct SwitchFeatures {
    pub datapath_id: u64,
    pub num_buffers: u32,
    pub num_tables: u8,
    pub aux_id: u8,
    pub supported_capabilities: Capabilities,
}

impl SwitchFeatures {
    pub fn parse(buf: &[u8]) -> SwitchFeatures {
        let mut bytes = Cursor::new(buf.to_vec());
        SwitchFeatures {
            datapath_id: bytes.read_u64::<BigEndian>().unwrap(),
            num_buffers: bytes.read_u32::<BigEndian>().unwrap(),
            num_tables: bytes.read_u8().unwrap(),
            aux_id: bytes.read_u8().unwrap(),
            supported_capabilities: Capabilities {
                flow_stats: bytes.read_u8().unwrap() != 0,
                table_stats: bytes.read_u8().unwrap() != 0,
                port_stats: bytes.read_u8().unwrap() != 0,
                group_stats: bytes.read_u8().unwrap() != 0,
                ip_reasm: bytes.read_u8().unwrap() != 0,
                queue_stats: bytes.read_u8().unwrap() != 0,
                port_blocked: bytes.read_u8().unwrap() != 0,
            }
        }
    }
}

pub enum FlowModCmd {
    AddFlow,
    ModFlow,
    ModStrictFlow,
    DeleteFlow,
    DeleteStrictFlow
}

pub struct FlowMod {
    pub command: FlowModCmd,
    pub pattern: u8,
    pub priority: u16,
    pub actions: Vec<Action>,
    pub cookie: i64,
    pub out_port: Option<PseudoPort>
}

pub mod message {
    use super::*;
    use ofp_header::OfpHeader;

    pub enum Message {
        Hello,
        FeaturesReq,
        FeaturesReply(SwitchFeatures),
        FlowMod(FlowMod)
    }

    impl Message {
        fn msg_code_of_message(msg: &Message) -> MsgCode {
            match *msg {
                Message::Hello => MsgCode::Hello,
                Message::FeaturesReq => MsgCode::FeaturesReq,
                Message::FeaturesReply(_) => MsgCode::FeaturesResp,
                Message::FlowMod(_) => MsgCode::FlowMod
                // _ => MsgCode::Hello
            }
        }

        fn size_of(msg: &Message) -> usize {
            match *msg {
                Message::Hello => OfpHeader::size(),
                Message::FeaturesReq => OfpHeader::size(),
                _ => 0,
            }
        }

        fn header_of(xid: u32, msg: &Message) -> OfpHeader {
            let sizeof_buf = Self::size_of(&msg);
            OfpHeader::new(0x01,
                           Self::msg_code_of_message(msg) as u8,
                           sizeof_buf as u16,
                           xid)
        }

        pub fn marshal(xid: u32, msg: Message) -> Vec<u8> {
            let hdr = Self::header_of(xid, &msg);
            let mut bytes = vec![];
            OfpHeader::marshal(&mut bytes, hdr);
            bytes
        }

        pub fn parse(header: &OfpHeader, buf: &[u8]) -> (u32, Message) {
            let typ = header.type_code();
            let msg = match typ {
                MsgCode::Hello => {
                    println!("Hello!");
                    Message::Hello
                }
                MsgCode::FeaturesResp => {
                    println!("FeaturesResp");
                    Message::FeaturesReply(SwitchFeatures::parse(buf))
                }
                t => {
                    println!("{}", t as u8);
                    Message::Hello
                }
            };
            (header.xid(), msg)
        }
    }

    pub fn add_flow(prio: u16, pattern: u8, actions: Vec<Action>) -> FlowMod {
        FlowMod {
            command: FlowModCmd::AddFlow,
            pattern: pattern,
            priority: prio,
            actions: actions,
            cookie: 0,
            out_port: None
        }
    }
}
<commit_msg>Continue implementing parse/marshal for various Ofp msg codes<commit_after>use std::io::Cursor;
use std::mem::{size_of, transmute};

use byteorder::{BigEndian, ReadBytesExt};

fn test_bit(bit: u64, x: u64) -> bool {
    (x >> bit) & 1 == 1
}

pub struct Pattern {}

struct OfpMatch {
    wildcards: u32,
    in_port: u16,
    dl_src: [u8; 6],
    dl_dst: [u8; 6],
    dl_vlan: u16,
    dl_vlan_pcp: u8,
    pad1: u8,
    dl_type: u16,
    nw_tos: u8,
    nw_proto: u8,
    pad2: u16,
    nw_src: u32,
    nw_dst: u32,
    tp_src: u16,
    tp_dst: u16,
}

#[derive(Copy, Clone)]
pub enum PseudoPort {
    PhysicalPort(u16),
    InPort,
    Table,
    Normal,
    Flood,
    AllPorts,
    Controller(u64),
    Local
}

#[derive(Copy, Clone)]
pub enum Action {
    Output(PseudoPort),
}

struct OfpActionHeader {
    typ: u16,
    len: u16
}

struct OfpActionOutput {
    port: u16,
    max_len: u16
}

impl Action {
    fn size_of(a: &Action) -> usize {
        let h = size_of::<OfpActionHeader>();
        let body = match *a {
            Action::Output(_) => size_of::<OfpActionOutput>()
        };
        h + body
    }

    pub fn size_of_sequence(actions: Vec<Action>) -> usize {
        actions.iter().fold(0, |acc, x| Action::size_of(x) + acc)
    }
}

pub enum Timeout {
    Permanent,
    ExpiresAfter(u16)
}

#[repr(u8)]
#[derive(Copy, Clone)]
pub enum MsgCode {
    Hello,
    Error,
    EchoReq,
    EchoResp,
    Vendor,
    FeaturesReq,
    FeaturesResp,
    GetConfigReq,
    GetConfigResp,
    SetConfig,
    PacketIn,
    FlowRemoved,
    PortStatus,
    PacketOut,
    FlowMod,
    PortMod,
    StatsReq,
    StatsResp,
    BarrierReq,
    BarrierResp,
    QueueGetConfigReq,
    QueueGetConfigResp,
}

pub struct Capabilities {
    pub flow_stats: bool,
    pub table_stats: bool,
    pub port_stats: bool,
    pub group_stats: bool,
    pub ip_reasm: bool,
    pub queue_stats: bool,
    pub port_blocked: bool,
}

pub struct SwitchFeatures {
    pub datapath_id: u64,
    pub num_buffers: u32,
    pub num_tables: u8,
    pub aux_id: u8,
    pub supported_capabilities: Capabilities,
}

impl SwitchFeatures {
    pub fn parse(buf: &[u8]) -> SwitchFeatures {
        let mut bytes = Cursor::new(buf.to_vec());
        SwitchFeatures {
            datapath_id: bytes.read_u64::<BigEndian>().unwrap(),
            num_buffers: bytes.read_u32::<BigEndian>().unwrap(),
            num_tables: bytes.read_u8().unwrap(),
            aux_id: bytes.read_u8().unwrap(),
            supported_capabilities: Capabilities {
                flow_stats: bytes.read_u8().unwrap() != 0,
                table_stats: bytes.read_u8().unwrap() != 0,
                port_stats: bytes.read_u8().unwrap() != 0,
                group_stats: bytes.read_u8().unwrap() != 0,
                ip_reasm: bytes.read_u8().unwrap() != 0,
                queue_stats: bytes.read_u8().unwrap() != 0,
                port_blocked: bytes.read_u8().unwrap() != 0,
            }
        }
    }
}

pub enum FlowModCmd {
    AddFlow,
    ModFlow,
    ModStrictFlow,
    DeleteFlow,
    DeleteStrictFlow
}

pub struct FlowMod {
    pub command: FlowModCmd,
    pub pattern: u8,
    pub priority: u16,
    pub actions: Vec<Action>,
    pub cookie: i64,
    pub idle_timeout: Timeout,
    pub hard_timeout: Timeout,
    pub notify_when_removed: bool,
    pub apply_to_packet: Option<u32>,
    pub out_port: Option<PseudoPort>,
    pub check_overlap: bool
}

struct OfpFlowMod {
    cookie: u64,
    command: u16,
    idle_timeout: u16,
    hard_timeout: u16,
    priority: u16,
    buffer_id: u32,
    out_port: u16,
    flags: u16
}

impl FlowMod {
    pub fn size_of(msg: &FlowMod) -> usize {
        size_of::<OfpMatch>() + size_of::<OfpFlowMod>() + Action::size_of_sequence(msg.actions.clone())
    }

    pub fn marshal(msg: FlowMod, bytes: &mut Vec<u8>) {

    }
}

#[repr(u8)]
pub enum StpState {
    Listen,
    Learn,
    Forward,
    Block
}

pub struct PortState {
    pub down: bool,
    pub stp_state: StpState
}

pub struct PortFeatures {
    pub f_10MBHD: bool,
    pub f_10MBFD: bool,
    pub f_100MBHD: bool,
    pub f_100MBFD: bool,
    pub f_1GBHD: bool,
    pub f_1GBFD: bool,
    pub f_10GBFD: bool,
    pub copper: bool,
    pub fiber: bool,
    pub autoneg: bool,
    pub pause: bool,
    pub pause_asym: bool
}

impl PortFeatures {
    fn of_int(d: u32) -> PortFeatures {
        PortFeatures {
            f_10MBHD: test_bit(0, d as u64),
            f_10MBFD: test_bit(1, d as u64),
            f_100MBHD: test_bit(2, d as u64),
            f_100MBFD: test_bit(3, d as u64),
            f_1GBHD: test_bit(4, d as u64),
            f_1GBFD: test_bit(5, d as u64),
            f_10GBFD: test_bit(6, d as u64),
            copper: test_bit(7, d as u64),
            fiber: test_bit(8, d as u64),
            autoneg: test_bit(9, d as u64),
            pause: test_bit(10, d as u64),
            pause_asym: test_bit(11, d as u64),
        }
    }
}

pub struct PortConfig {
    pub down: bool,
    pub no_stp: bool,
    pub no_recv: bool,
    pub no_recv_stp: bool,
    pub no_flood: bool,
    pub no_fwd: bool,
    pub no_packet_in: bool
}

pub struct PortDesc {
    pub port_no: u16,
    pub hw_addr: i64,
    pub name: String,
    pub config: PortConfig,
    pub state: PortState,
    pub curr: PortFeatures,
    pub advertised: PortFeatures,
    pub supported: PortFeatures,
    pub peer: PortFeatures,
}

struct OfpPhyPort {
    port_no: u16,
    hw_addr: [u8; 6],
    name: [u8; 16],
    config: u32,
    state: u32,
    curr: u32,
    advertised: u32,
    supported: u32,
    peer: u32
}

#[repr(u8)]
pub enum PortReason {
    PortAdd,
    PortDelete,
    PortModify
}

pub struct PortStatus {
    pub reason: PortReason,
    pub desc: PortDesc
}

struct OfpPortStatus {
    reason: u8,
    pad: [u8; 7]
}

impl PortStatus {
    pub fn size_of() -> usize {
        size_of::<PortReason>() + size_of::<OfpPhyPort>()
    }

    pub fn parse(buf: &[u8]) -> PortStatus {
        let mut bytes = Cursor::new(buf.to_vec());
        PortStatus {
            reason: {
                let reason = unsafe { transmute(bytes.read_u8().unwrap()) };
                // read through padding
                for _ in 0..7 { let _ = bytes.read_u8(); }
                reason
            },
            desc: PortDesc {
                port_no: bytes.read_u16::<BigEndian>().unwrap(),
                hw_addr: {
                    let mut arr: [u8; 8] = [0;8];
                    for i in 0..6 {
                        arr[i] = bytes.read_u8().unwrap();
                    }
                    unsafe { transmute(arr) }
                },
                name: {
                    let mut arr: [u8; 16] = [0; 16];
                    for i in 0..16 {
                        arr[i] = bytes.read_u8().unwrap();
                    }
                    String::from_utf8(arr.to_vec()).unwrap()
                },
                config: {
                    let d = bytes.read_u8().unwrap();
                    PortConfig {
                        down: test_bit(0, d as u64),
                        no_stp: test_bit(1, d as u64),
                        no_recv: test_bit(2, d as u64),
                        no_recv_stp: test_bit(3, d as u64),
                        no_flood: test_bit(4, d as u64),
                        no_fwd: test_bit(5, d as u64),
                        no_packet_in: test_bit(6, d as u64)
                    }
                },
                state: {
                    let d = bytes.read_u32::<BigEndian>().unwrap();
                    PortState {
                        down: test_bit(0, d as u64),
                        stp_state: {
                            let mask: u32 = 3 << 8;
                            let d_masked = d & mask;
                            if d_masked == (StpState::Listen as u32) << 8 { StpState::Listen }
                            else if d_masked == (StpState::Learn as u32) << 8 { StpState::Learn }
                            else if d_masked == (StpState::Forward as u32) << 8 { StpState::Forward }
                            else if d_masked == (StpState::Block as u32) << 8 { StpState::Block }
                            else { panic!("Unexpected ofp_port_state for STP: {}", d_masked) }
                        }
                    }
                },
                curr: PortFeatures::of_int(bytes.read_u32::<BigEndian>().unwrap()),
                advertised: PortFeatures::of_int(bytes.read_u32::<BigEndian>().unwrap()),
                supported: PortFeatures::of_int(bytes.read_u32::<BigEndian>().unwrap()),
                peer: PortFeatures::of_int(bytes.read_u32::<BigEndian>().unwrap()),
            }
        }
    }

    pub fn marshal(sts: PortStatus, bytes: &mut Vec<u8>) {

    }
}

pub mod message {
    use super::*;
    use ofp_header::OfpHeader;

    pub enum Message {
        Hello,
        FeaturesReq,
        FeaturesReply(SwitchFeatures),
        FlowMod(FlowMod),
        PortStatus(PortStatus)
    }

    impl Message {
        fn msg_code_of_message(msg: &Message) -> MsgCode {
            match *msg {
                Message::Hello => MsgCode::Hello,
                Message::FeaturesReq => MsgCode::FeaturesReq,
                Message::FeaturesReply(_) => MsgCode::FeaturesResp,
                Message::FlowMod(_) => MsgCode::FlowMod,
                Message::PortStatus(_) => MsgCode::PortStatus
                // _ => MsgCode::Hello
            }
        }

        fn size_of(msg: &Message) -> usize {
            match *msg {
                Message::Hello => OfpHeader::size(),
                Message::FeaturesReq => OfpHeader::size(),
                Message::FlowMod(ref flow_mod) => OfpHeader::size() + FlowMod::size_of(flow_mod),
                Message::PortStatus(_) => OfpHeader::size() + PortStatus::size_of(),
                _ => 0,
            }
        }

        fn header_of(xid: u32, msg: &Message) -> OfpHeader {
            let sizeof_buf = Self::size_of(&msg);
            OfpHeader::new(0x01,
                           Self::msg_code_of_message(msg) as u8,
                           sizeof_buf as u16,
                           xid)
        }

        fn marshal_body(msg: Message, bytes: &mut Vec<u8>) {
            match msg {
                Message::Hello => (),
                Message::FeaturesReq => (),
                Message::FlowMod(flow_mod) => FlowMod::marshal(flow_mod, bytes),
                Message::PortStatus(sts) => PortStatus::marshal(sts, bytes),
                _ => ()
            }
        }

        pub fn marshal(xid: u32, msg: Message) -> Vec<u8> {
            let hdr = Self::header_of(xid, &msg);
            let mut bytes = vec![];
            OfpHeader::marshal(&mut bytes, hdr);
            Message::marshal_body(msg, &mut bytes);
            bytes
        }

        pub fn parse(header: &OfpHeader, buf: &[u8]) -> (u32, Message) {
            let typ = header.type_code();
            let msg = match typ {
                MsgCode::Hello => {
                    println!("Hello!");
                    Message::Hello
                }
                MsgCode::FeaturesResp => {
                    println!("FeaturesResp");
                    Message::FeaturesReply(SwitchFeatures::parse(buf))
                }
                MsgCode::PortStatus => {
                    println!("PortStatus");
                    Message::PortStatus(PortStatus::parse(buf))
                }
                t => {
                    println!("{}", t as u8);
                    Message::Hello
                }
            };
            (header.xid(), msg)
        }
    }

    pub fn add_flow(prio: u16, pattern: u8, actions: Vec<Action>) -> FlowMod {
        FlowMod {
            command: FlowModCmd::AddFlow,
            pattern: pattern,
            priority: prio,
            actions: actions,
            cookie: 0,
            idle_timeout: Timeout::Permanent,
            hard_timeout: Timeout::Permanent,
            notify_when_removed: false,
            out_port: None,
            apply_to_packet: None,
            check_overlap: false
        }
    }
}
<|endoftext|>


<commit_before>extern crate image;
extern crate time;

use std::iter;
use std::path::Path;
use std::thread;

use vector::*;
use objects::*;
mod lighting;

pub type Image = image::RgbImage;

pub fn write_image(image: Image, filename: &str) {
    let _ = image.save(&Path::new(filename));
}

pub fn raytrace(scene: &Scene, width: u32, height: u32, h_fov: f64) {
    let start_time = time::precise_time_ns();
    let f_width = width as f64;
    let f_height = height as f64;
    let v_fov = h_fov * (f_height / f_width);

    let vw_per_pixel = 2.0 * (h_fov / 2.0).tan() / f_width;
    let vh_per_pixel = 2.0 * (v_fov / 2.0).tan() / f_height;

    let norm_up = scene.camera.up.normalized();
    let norm_right = scene.camera.direction.cross(scene.camera.up).normalized();

    let tracer = move |row_start, num_rows, scene: Scene| {
        move || {
            let coords = (0..width).flat_map(|y| {
                iter::repeat(y).zip(row_start..(row_start + num_rows))
            });
            let trace_coord = |coord| {
                let (x, y) = coord;
                let mut rays = 0;
                let cast_ray = |dx: f64, dy: f64, rays: &mut u64| {
                    *rays += 1;
                    let fi = (x as f64) + dx;
                    let fj = (y as f64) + dy;

                    let u_rel = vw_per_pixel * (fi - (f_width / 2.0));
                    let v_rel = vh_per_pixel * (fj - (f_height / 2.0));

                    let pixel_loc = scene.camera.position + scene.camera.direction +
                        (norm_right * u_rel) + (norm_up * v_rel);

                    let ray = Ray {
                        origin: scene.camera.position,
                        direction: pixel_loc - scene.camera.position
                    };

                    let (color, new_rays) = lighting::get_color(&scene, &ray, 3);
                    *rays += new_rays;
                    color
                };

                let c1 = cast_ray(0.25, 0.25, &mut rays);
                let c2 = cast_ray(0.75, 0.25, &mut rays);
                let c3 = cast_ray(0.50, 0.50, &mut rays);
                let c4 = cast_ray(0.75, 0.75, &mut rays);
                let c5 = cast_ray(0.25, 0.75, &mut rays);

                (coord, rays, (c1 + c2 + c3 + c4 + c5) / 5.0)
            };

            let mut result = Vec::with_capacity((num_rows * width) as usize);
            let mut rays = 0;
            for (coord, new_rays, color) in coords.map(trace_coord) {
                rays += new_rays;
                result.push((coord, color))
            }

            (rays, result)
        }
    };

    // TODO: split based on core count
    let split = height;
    let handle1 = thread::spawn(tracer(0, split, (*scene).clone()));
    let handle2 = thread::spawn(tracer(split, height - split, (*scene).clone()));

    let mut image = image::RgbImage::new(width, height);
    let mut rays = 0;
    let (new_rays, pixels): (u64, Vec<((u32, u32), Color)>) = handle1.join().unwrap();

    // TODO: direct copying into image. Also see Image.sub_image
    for ((x, y), pixel) in pixels {
        image.put_pixel(x as u32, y as u32, pixel.to_rgb());
    }
    rays += new_rays;

    let (new_rays, pixels): (u64, Vec<((u32, u32), Color)>) = handle2.join().unwrap();

    for ((x, y), pixel) in pixels {
        image.put_pixel(x as u32, y as u32, pixel.to_rgb());
    }
    rays += new_rays;

    write_image(image, "test.png");

    let elapsed_time = ((time::precise_time_ns() - start_time) as f64) /
        1000000.0;
    let rays_per_s = 1000.0 * (rays as f64) / elapsed_time;
    println!("Traced {} rays in {} ms ({} rays per second).",
             rays, elapsed_time, rays_per_s);
}
<commit_msg>Fix typo destroying our performance<commit_after>extern crate image;
extern crate time;

use std::iter;
use std::path::Path;
use std::thread;

use vector::*;
use objects::*;
mod lighting;

pub type Image = image::RgbImage;

pub fn write_image(image: Image, filename: &str) {
    let _ = image.save(&Path::new(filename));
}

pub fn raytrace(scene: &Scene, width: u32, height: u32, h_fov: f64) {
    let start_time = time::precise_time_ns();
    let f_width = width as f64;
    let f_height = height as f64;
    let v_fov = h_fov * (f_height / f_width);

    let vw_per_pixel = 2.0 * (h_fov / 2.0).tan() / f_width;
    let vh_per_pixel = 2.0 * (v_fov / 2.0).tan() / f_height;

    let norm_up = scene.camera.up.normalized();
    let norm_right = scene.camera.direction.cross(scene.camera.up).normalized();

    let tracer = move |row_start, num_rows, scene: Scene| {
        move || {
            let coords = (0..width).flat_map(|y| {
                iter::repeat(y).zip(row_start..(row_start + num_rows))
            });
            let trace_coord = |coord| {
                let (x, y) = coord;
                let mut rays = 0;
                let cast_ray = |dx: f64, dy: f64, rays: &mut u64| {
                    *rays += 1;
                    let fi = (x as f64) + dx;
                    let fj = (y as f64) + dy;

                    let u_rel = vw_per_pixel * (fi - (f_width / 2.0));
                    let v_rel = vh_per_pixel * (fj - (f_height / 2.0));

                    let pixel_loc = scene.camera.position + scene.camera.direction +
                        (norm_right * u_rel) + (norm_up * v_rel);

                    let ray = Ray {
                        origin: scene.camera.position,
                        direction: pixel_loc - scene.camera.position
                    };

                    let (color, new_rays) = lighting::get_color(&scene, &ray, 3);
                    *rays += new_rays;
                    color
                };

                let c1 = cast_ray(0.25, 0.25, &mut rays);
                let c2 = cast_ray(0.75, 0.25, &mut rays);
                let c3 = cast_ray(0.50, 0.50, &mut rays);
                let c4 = cast_ray(0.75, 0.75, &mut rays);
                let c5 = cast_ray(0.25, 0.75, &mut rays);

                (coord, rays, (c1 + c2 + c3 + c4 + c5) / 5.0)
            };

            let mut result = Vec::with_capacity((num_rows * width) as usize);
            let mut rays = 0;
            for (coord, new_rays, color) in coords.map(trace_coord) {
                rays += new_rays;
                result.push((coord, color))
            }

            (rays, result)
        }
    };

    // TODO: split based on core count
    let split = height / 2;
    let handle1 = thread::spawn(tracer(0, split, (*scene).clone()));
    let handle2 = thread::spawn(tracer(split, height - split, (*scene).clone()));

    let mut image = image::RgbImage::new(width, height);
    let mut rays = 0;
    let (new_rays, pixels): (u64, Vec<((u32, u32), Color)>) = handle1.join().unwrap();

    // TODO: direct copying into image. Also see Image.sub_image
    for ((x, y), pixel) in pixels {
        image.put_pixel(x as u32, y as u32, pixel.to_rgb());
    }
    rays += new_rays;

    let (new_rays, pixels): (u64, Vec<((u32, u32), Color)>) = handle2.join().unwrap();

    for ((x, y), pixel) in pixels {
        image.put_pixel(x as u32, y as u32, pixel.to_rgb());
    }
    rays += new_rays;

    write_image(image, "test.png");

    let elapsed_time = ((time::precise_time_ns() - start_time) as f64) /
        1000000.0;
    let rays_per_s = 1000.0 * (rays as f64) / elapsed_time;
    println!("Traced {} rays in {} ms ({} rays per second).",
             rays, elapsed_time, rays_per_s);
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Batches are structures containing all the data required for the draw call,
//! except for the target frame. Here we define the `Batch` trait as well as
//! `RefBatch` and `OwnedBatch` implementations.

use device::ProgramHandle;
use device::shade::ProgramInfo;
use mesh;
use mesh::ToSlice;
use shade::{ParameterError, ShaderParam};
use state::DrawState;

/// An error with a defined Mesh.
#[deriving(Clone, Show)]
pub enum MeshError {
    /// A required attribute was missing.
    ErrorAttributeMissing(String),
    /// An attribute's type from the vertex format differed from the type used in the shader.
    ErrorAttributeType,
    /// Internal error due to mesh link limitations
    ErrorMeshLink(mesh::LinkError),
}

/// An error occurring at batch creation
#[deriving(Clone, Show)]
pub enum BatchError {
    /// Error connecting mesh attributes
    ErrorMesh(MeshError),
    /// Error connecting shader parameters
    ErrorParameters(ParameterError),
}

/// Match mesh attributes against shader inputs, produce a mesh link.
/// Exposed to public to allow external `Batch` implementations to use it.
pub fn link_mesh(mesh: &mesh::Mesh, pinfo: &ProgramInfo) -> Result<mesh::Link, MeshError> {
    let mut indices = Vec::new();
    for sat in pinfo.attributes.iter() {
        match mesh.attributes.iter().enumerate()
                  .find(|&(_, a)| a.name.as_slice() == sat.name.as_slice()) {
            Some((attrib_id, vat)) => match vat.format.elem_type.is_compatible(sat.base_type) {
                Ok(_) => indices.push(attrib_id),
                Err(_) => return Err(ErrorAttributeType),
            },
            None => return Err(ErrorAttributeMissing(sat.name.clone())),
        }
    }
    mesh::Link::from_iter(indices.move_iter())
        .map_err(|e| ErrorMeshLink(e))
}

/// Abstract batch trait
pub trait Batch {
    /// Obtain information about the mesh, program, and state
    fn get_data(&self) -> (&mesh::Mesh, &mesh::Link, &mesh::Slice, &ProgramHandle, &DrawState);
    /// Fill shader parameter values
    fn fill_params(&self, ::shade::ParamValues);
}

/// Owned batch - self-contained, but has heap-allocated data
pub struct OwnedBatch<L, T> {
    mesh: mesh::Mesh,
    mesh_link: mesh::Link,
    /// Mesh slice
    pub slice: mesh::Slice,
    program: ProgramHandle,
    param: T,
    param_link: L,
    /// Draw state
    pub state: DrawState,
}

impl<L, T: ShaderParam<L>> OwnedBatch<L, T> {
    /// Create a new owned batch
    pub fn new(mesh: mesh::Mesh, program: ProgramHandle, param: T)
           -> Result<OwnedBatch<L, T>, BatchError> {
        let slice = mesh.to_slice(::device::TriangleList);
        let mesh_link = match link_mesh(&mesh, program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(ErrorMesh(e)),
        };
        let param_link = match ShaderParam::create_link(None::<T>, program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(ErrorParameters(e)),
        };
        Ok(OwnedBatch {
            mesh: mesh,
            mesh_link: mesh_link,
            slice: slice,
            program: program,
            param: param,
            param_link: param_link,
            state: DrawState::new(),
        })
    }
}

impl<'a, L, T: ShaderParam<L>> Batch for &'a OwnedBatch<L, T> {
    fn get_data(&self) -> (&mesh::Mesh, &mesh::Link, &mesh::Slice, &ProgramHandle, &DrawState) {
        (&self.mesh, &self.mesh_link, &self.slice, &self.program, &self.state)
    }

    fn fill_params(&self, values: ::shade::ParamValues) {
        self.param.fill_params(&self.param_link, values);
    }
}

type Index = u16;

//#[deriving(PartialEq, Eq, PartialOrd, Ord, Show)]
struct Id<T>(Index);

impl<T> Id<T> {
    fn unwrap(&self) -> Index {
        let Id(i) = *self;
        i
    }
}

impl<T> PartialEq for Id<T> {
    fn eq(&self, other: &Id<T>) -> bool {
        self.unwrap() == other.unwrap()
    }
}

impl<T> Eq for Id<T> {}

impl<T> PartialOrd for Id<T> {
    fn partial_cmp(&self, other: &Id<T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<T> Ord for Id<T> {
    fn cmp(&self, other: &Id<T>) -> Ordering {
        self.unwrap().cmp(&other.unwrap())
    }
}

struct Array<T> {
    data: Vec<T>,
    //generation: u16,
}

impl<T> Array<T> {
    fn new() -> Array<T> {
        Array {
            data: Vec::new(),
            //generation: 0,
        }
    }

    fn get(&self, id: Id<T>) -> &T {
        let Id(i) = id;
        &self.data[i as uint]
    }
}

impl<T: Clone + PartialEq> Array<T> {
    fn find_or_insert(&mut self, value: &T) -> Id<T> {
        let i = self.data.iter().position(|v| v == value).unwrap_or_else(|| {
            let i = self.data.len();
            self.data.push(value.clone());
            i
        });
        Id(i as Index)
    }
}

/// Ref batch - copyable and smaller, but depends on the `Context`.
/// It has references to the resources (mesh, program, state), that are held
/// by the context that created the batch, so these have to be used together.
pub struct RefBatch<L, T> {
    mesh_id: Id<mesh::Mesh>,
    mesh_link: mesh::Link,
    /// Mesh slice
    pub slice: mesh::Slice,
    program_id: Id<ProgramHandle>,
    param_link: L,
    state_id: Id<DrawState>,
}

impl<L, T> PartialEq for RefBatch<L, T> {
    fn eq(&self, other: &RefBatch<L, T>) -> bool {
        self.program_id == other.program_id &&
        self.state_id == other.state_id &&
        self.mesh_id == other.mesh_id
    }
}

impl<L, T> Eq for RefBatch<L, T> {}

impl<L, T> PartialOrd for RefBatch<L, T> {
    fn partial_cmp(&self, other: &RefBatch<L, T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<L, T> Ord for RefBatch<L, T> {
    fn cmp(&self, other: &RefBatch<L, T>) -> Ordering {
        (self.program_id, self.state_id, self.mesh_id).cmp(
        &(other.program_id, other.state_id, other.mesh_id))
    }
}

/// Factory of ref batches, required to always be used with them.
pub struct Context {
    meshes: Array<mesh::Mesh>,
    programs: Array<ProgramHandle>,
    states: Array<DrawState>,
}

impl Context {
    /// Create a new empty `Context`
    pub fn new() -> Context {
        Context {
            meshes: Array::new(),
            programs: Array::new(),
            states: Array::new(),
        }
    }
}

impl Context {
    /// Produce a new ref batch
    pub fn batch<L, T: ShaderParam<L>>(&mut self, mesh: &mesh::Mesh,
                slice: mesh::Slice, program: &ProgramHandle, state: &DrawState)
                -> Result<RefBatch<L, T>, BatchError> {
        let mesh_link = match link_mesh(mesh, program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(ErrorMesh(e)),
        };
        let link = match ShaderParam::create_link(None::<T>, program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(ErrorParameters(e))
        };
        Ok(RefBatch {
            mesh_id: self.meshes.find_or_insert(mesh),
            mesh_link: mesh_link,
            slice: slice,
            program_id: self.programs.find_or_insert(program),
            param_link: link,
            state_id: self.states.find_or_insert(state),
        })
    }
}

impl<'a, L, T: ShaderParam<L>> Batch for (&'a RefBatch<L, T>, &'a T, &'a Context) {
    fn get_data(&self) -> (&mesh::Mesh, &mesh::Link, &mesh::Slice, &ProgramHandle, &DrawState) {
        let (b, _, ctx) = *self;
        (ctx.meshes.get(b.mesh_id),
        &b.mesh_link,
        &b.slice,
        ctx.programs.get(b.program_id),
        ctx.states.get(b.state_id))
    }

    fn fill_params(&self, values: ::shade::ParamValues) {
        let (b, data, _) = *self;
        data.fill_params(&b.param_link, values);
    }
}
<commit_msg>Make OwnerBatch::param public<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Batches are structures containing all the data required for the draw call,
//! except for the target frame. Here we define the `Batch` trait as well as
//! `RefBatch` and `OwnedBatch` implementations.

use device::ProgramHandle;
use device::shade::ProgramInfo;
use mesh;
use mesh::ToSlice;
use shade::{ParameterError, ShaderParam};
use state::DrawState;

/// An error with a defined Mesh.
#[deriving(Clone, Show)]
pub enum MeshError {
    /// A required attribute was missing.
    ErrorAttributeMissing(String),
    /// An attribute's type from the vertex format differed from the type used in the shader.
    ErrorAttributeType,
    /// Internal error due to mesh link limitations
    ErrorMeshLink(mesh::LinkError),
}

/// An error occurring at batch creation
#[deriving(Clone, Show)]
pub enum BatchError {
    /// Error connecting mesh attributes
    ErrorMesh(MeshError),
    /// Error connecting shader parameters
    ErrorParameters(ParameterError),
}

/// Match mesh attributes against shader inputs, produce a mesh link.
/// Exposed to public to allow external `Batch` implementations to use it.
pub fn link_mesh(mesh: &mesh::Mesh, pinfo: &ProgramInfo) -> Result<mesh::Link, MeshError> {
    let mut indices = Vec::new();
    for sat in pinfo.attributes.iter() {
        match mesh.attributes.iter().enumerate()
                  .find(|&(_, a)| a.name.as_slice() == sat.name.as_slice()) {
            Some((attrib_id, vat)) => match vat.format.elem_type.is_compatible(sat.base_type) {
                Ok(_) => indices.push(attrib_id),
                Err(_) => return Err(ErrorAttributeType),
            },
            None => return Err(ErrorAttributeMissing(sat.name.clone())),
        }
    }
    mesh::Link::from_iter(indices.move_iter())
        .map_err(|e| ErrorMeshLink(e))
}

/// Abstract batch trait
pub trait Batch {
    /// Obtain information about the mesh, program, and state
    fn get_data(&self) -> (&mesh::Mesh, &mesh::Link, &mesh::Slice, &ProgramHandle, &DrawState);
    /// Fill shader parameter values
    fn fill_params(&self, ::shade::ParamValues);
}

/// Owned batch - self-contained, but has heap-allocated data
pub struct OwnedBatch<L, T> {
    mesh: mesh::Mesh,
    mesh_link: mesh::Link,
    /// Mesh slice
    pub slice: mesh::Slice,
    /// Parameter data.
    pub param: T,
    program: ProgramHandle,
    param_link: L,
    /// Draw state
    pub state: DrawState,
}

impl<L, T: ShaderParam<L>> OwnedBatch<L, T> {
    /// Create a new owned batch
    pub fn new(mesh: mesh::Mesh, program: ProgramHandle, param: T)
           -> Result<OwnedBatch<L, T>, BatchError> {
        let slice = mesh.to_slice(::device::TriangleList);
        let mesh_link = match link_mesh(&mesh, program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(ErrorMesh(e)),
        };
        let param_link = match ShaderParam::create_link(None::<T>, program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(ErrorParameters(e)),
        };
        Ok(OwnedBatch {
            mesh: mesh,
            mesh_link: mesh_link,
            slice: slice,
            program: program,
            param: param,
            param_link: param_link,
            state: DrawState::new(),
        })
    }
}

impl<'a, L, T: ShaderParam<L>> Batch for &'a OwnedBatch<L, T> {
    fn get_data(&self) -> (&mesh::Mesh, &mesh::Link, &mesh::Slice, &ProgramHandle, &DrawState) {
        (&self.mesh, &self.mesh_link, &self.slice, &self.program, &self.state)
    }

    fn fill_params(&self, values: ::shade::ParamValues) {
        self.param.fill_params(&self.param_link, values);
    }
}

type Index = u16;

//#[deriving(PartialEq, Eq, PartialOrd, Ord, Show)]
struct Id<T>(Index);

impl<T> Id<T> {
    fn unwrap(&self) -> Index {
        let Id(i) = *self;
        i
    }
}

impl<T> PartialEq for Id<T> {
    fn eq(&self, other: &Id<T>) -> bool {
        self.unwrap() == other.unwrap()
    }
}

impl<T> Eq for Id<T> {}

impl<T> PartialOrd for Id<T> {
    fn partial_cmp(&self, other: &Id<T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<T> Ord for Id<T> {
    fn cmp(&self, other: &Id<T>) -> Ordering {
        self.unwrap().cmp(&other.unwrap())
    }
}

struct Array<T> {
    data: Vec<T>,
    //generation: u16,
}

impl<T> Array<T> {
    fn new() -> Array<T> {
        Array {
            data: Vec::new(),
            //generation: 0,
        }
    }

    fn get(&self, id: Id<T>) -> &T {
        let Id(i) = id;
        &self.data[i as uint]
    }
}

impl<T: Clone + PartialEq> Array<T> {
    fn find_or_insert(&mut self, value: &T) -> Id<T> {
        let i = self.data.iter().position(|v| v == value).unwrap_or_else(|| {
            let i = self.data.len();
            self.data.push(value.clone());
            i
        });
        Id(i as Index)
    }
}

/// Ref batch - copyable and smaller, but depends on the `Context`.
/// It has references to the resources (mesh, program, state), that are held
/// by the context that created the batch, so these have to be used together.
pub struct RefBatch<L, T> {
    mesh_id: Id<mesh::Mesh>,
    mesh_link: mesh::Link,
    /// Mesh slice
    pub slice: mesh::Slice,
    program_id: Id<ProgramHandle>,
    param_link: L,
    state_id: Id<DrawState>,
}

impl<L, T> PartialEq for RefBatch<L, T> {
    fn eq(&self, other: &RefBatch<L, T>) -> bool {
        self.program_id == other.program_id &&
        self.state_id == other.state_id &&
        self.mesh_id == other.mesh_id
    }
}

impl<L, T> Eq for RefBatch<L, T> {}

impl<L, T> PartialOrd for RefBatch<L, T> {
    fn partial_cmp(&self, other: &RefBatch<L, T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<L, T> Ord for RefBatch<L, T> {
    fn cmp(&self, other: &RefBatch<L, T>) -> Ordering {
        (self.program_id, self.state_id, self.mesh_id).cmp(
        &(other.program_id, other.state_id, other.mesh_id))
    }
}

/// Factory of ref batches, required to always be used with them.
pub struct Context {
    meshes: Array<mesh::Mesh>,
    programs: Array<ProgramHandle>,
    states: Array<DrawState>,
}

impl Context {
    /// Create a new empty `Context`
    pub fn new() -> Context {
        Context {
            meshes: Array::new(),
            programs: Array::new(),
            states: Array::new(),
        }
    }
}

impl Context {
    /// Produce a new ref batch
    pub fn batch<L, T: ShaderParam<L>>(&mut self, mesh: &mesh::Mesh,
                slice: mesh::Slice, program: &ProgramHandle, state: &DrawState)
                -> Result<RefBatch<L, T>, BatchError> {
        let mesh_link = match link_mesh(mesh, program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(ErrorMesh(e)),
        };
        let link = match ShaderParam::create_link(None::<T>, program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(ErrorParameters(e))
        };
        Ok(RefBatch {
            mesh_id: self.meshes.find_or_insert(mesh),
            mesh_link: mesh_link,
            slice: slice,
            program_id: self.programs.find_or_insert(program),
            param_link: link,
            state_id: self.states.find_or_insert(state),
        })
    }
}

impl<'a, L, T: ShaderParam<L>> Batch for (&'a RefBatch<L, T>, &'a T, &'a Context) {
    fn get_data(&self) -> (&mesh::Mesh, &mesh::Link, &mesh::Slice, &ProgramHandle, &DrawState) {
        let (b, _, ctx) = *self;
        (ctx.meshes.get(b.mesh_id),
        &b.mesh_link,
        &b.slice,
        ctx.programs.get(b.program_id),
        ctx.states.get(b.state_id))
    }

    fn fill_params(&self, values: ::shade::ParamValues) {
        let (b, data, _) = *self;
        data.fill_params(&b.param_link, values);
    }
}
<|endoftext|>