<commit_before>use std::ptr::null;
use libc::{c_char, c_int, c_double};
use std::ffi::CString;
use std::cell::RefCell;
use utils::_string;
use vector::{ogr, geom};
use GdalError;

pub struct Geometry {
    c_geometry_ref: RefCell<Option<*const ()>>,
    owned: bool,
}

impl Geometry {
    pub unsafe fn lazy_feature_geometry() -> Geometry {
        // Geometry objects created with this method map to a Feature's
        // geometry whose memory is managed by the GDAL feature.
        // This object has a tricky lifecycle:
        //
        // * Initially it's created with a null c_geometry
        // * The first time `Feature::geometry` is called, it gets
        //   c_geometry from GDAL and calls `set_c_geometry` with it.
        // * When the Feature is destroyed, this object is also destroyed,
        //   which is good, because that's when c_geometry (which is managed
        //   by the GDAL feature) becomes invalid. Because `self.owned` is
        //   `true`, we don't call `OGR_G_DestroyGeometry`.
        return Geometry{c_geometry_ref: RefCell::new(None), owned: false};
    }

    pub fn has_gdal_ptr(&self) -> bool {
        return self.c_geometry_ref.borrow().is_some();
    }

    pub unsafe fn set_c_geometry(&self, c_geometry: *const ()) {
        assert!(! self.has_gdal_ptr());
        assert_eq!(self.owned, false);
        *(self.c_geometry_ref.borrow_mut()) = Some(c_geometry);
    }

    pub fn empty(wkb_type: c_int) -> Geometry {
        let c_geom = unsafe { ogr::OGR_G_CreateGeometry(wkb_type) };
        assert!(c_geom != null());
        return Geometry{c_geometry_ref: RefCell::new(Some(c_geom)), owned: true};
    }

    pub fn from_wkt(wkt: &str) -> Geometry {
        let c_wkt = CString::new(wkt.as_bytes()).unwrap();
        let mut c_wkt_ptr: *const c_char = c_wkt.as_ptr();
        let mut c_geom: *const () = null();
        let rv = unsafe { ogr::OGR_G_CreateFromWkt(&mut c_wkt_ptr, null(), &mut c_geom) };
        assert_eq!(rv, ogr::OGRERR_NONE);
        return Geometry{c_geometry_ref: RefCell::new(Some(c_geom)), owned: true};
    }

    pub fn bbox(w: f64, s: f64, e: f64, n: f64) -> Geometry {
        Geometry::from_wkt(&format!(
            "POLYGON (({} {}, {} {}, {} {}, {} {}, {} {}))",
            w, n,
            e, n,
            e, s,
            w, s,
            w, n,
        ))
    }

    pub fn json(&self) -> String {
        let c_json = unsafe { ogr::OGR_G_ExportToJson(self.c_geometry()) };
        let rv = _string(c_json);
        unsafe { ogr::VSIFree(c_json as *mut ()) };
        return rv;
    }

    pub fn wkt(&self) -> String {
        let mut c_wkt: *const c_char = null();
        let _err = unsafe { ogr::OGR_G_ExportToWkt(self.c_geometry(), &mut c_wkt) };
        assert_eq!(_err, ogr::OGRERR_NONE);
        let wkt = _string(c_wkt);
        unsafe { ogr::OGRFree(c_wkt as *mut ()) };
        return wkt;
    }

    pub unsafe fn c_geometry(&self) -> *const () {
        return self.c_geometry_ref.borrow().unwrap();
    }

    pub fn set_point_2d(&mut self, i: i32, p: (f64, f64)) {
        let (x, y) = p;
        unsafe { ogr::OGR_G_SetPoint_2D(
            self.c_geometry(),
            i as c_int,
            x as c_double,
            y as c_double,
        ) };
    }

    pub fn get_point(&self, i: i32) -> (f64, f64, f64) {
        let mut x: c_double = 0.;
        let mut y: c_double = 0.;
        let mut z: c_double = 0.;
        unsafe { ogr::OGR_G_GetPoint(self.c_geometry(), i, &mut x, &mut y, &mut z) };
        return (x as f64, y as f64, z as f64);
    }

    pub fn to_geom(&self) -> Result<geom::Geom, GdalError> {
        let geometry_type = unsafe { ogr::OGR_G_GetGeometryType(self.c_geometry()) };
        match geometry_type {
            1 => {
                let (x, y, _) = self.get_point(0);
                Ok(geom::Geom::Point(geom::Point{x: x, y: y}))
            },
            _ => Err(GdalError{desc: "Unknown geometry type"})
        }
    }
}

impl Drop for Geometry {
    fn drop(&mut self) {
        if self.owned {
            let c_geometry = self.c_geometry_ref.borrow();
            unsafe { ogr::OGR_G_DestroyGeometry(c_geometry.unwrap() as *mut ()) };
        }
    }
}

pub trait ToGdal {
    fn to_gdal(&self) -> Geometry;
}

impl ToGdal for geom::Point {
    fn to_gdal(&self) -> Geometry {
        let mut geom = Geometry::empty(ogr::WKB_POINT);
        geom.set_point_2d(0, (self.x, self.y));
        return geom;
    }
}

#[cfg(test)]
mod tests {
    use vector::{Geometry, ToGdal};
    use vector::geom::{Geom, Point};

    #[test]
    fn test_ogr_to_point() {
        let g = Geometry::from_wkt("POINT (10 20)");
        assert_eq!(g.to_geom(), Ok(Geom::Point(Point{x: 10., y: 20.})));
    }

    #[test]
    fn test_point_to_ogr() {
        let g = Point{x: 10., y: 20.}.to_gdal();
        assert_eq!(g.wkt(), "POINT (10 20)");
    }
}
<commit_msg>helper to create Geometry object<commit_after>use std::ptr::null;
use libc::{c_char, c_int, c_double};
use std::ffi::CString;
use std::cell::RefCell;
use utils::_string;
use vector::{ogr, geom};
use GdalError;

pub struct Geometry {
    c_geometry_ref: RefCell<Option<*const ()>>,
    owned: bool,
}

impl Geometry {
    pub unsafe fn lazy_feature_geometry() -> Geometry {
        // Geometry objects created with this method map to a Feature's
        // geometry whose memory is managed by the GDAL feature.
        // This object has a tricky lifecycle:
        //
        // * Initially it's created with a null c_geometry
        // * The first time `Feature::geometry` is called, it gets
        //   c_geometry from GDAL and calls `set_c_geometry` with it.
        // * When the Feature is destroyed, this object is also destroyed,
        //   which is good, because that's when c_geometry (which is managed
        //   by the GDAL feature) becomes invalid. Because `self.owned` is
        //   `true`, we don't call `OGR_G_DestroyGeometry`.
        return Geometry{c_geometry_ref: RefCell::new(None), owned: false};
    }

    pub fn has_gdal_ptr(&self) -> bool {
        return self.c_geometry_ref.borrow().is_some();
    }

    pub unsafe fn set_c_geometry(&self, c_geometry: *const ()) {
        assert!(! self.has_gdal_ptr());
        assert_eq!(self.owned, false);
        *(self.c_geometry_ref.borrow_mut()) = Some(c_geometry);
    }

    unsafe fn with_c_geometry(c_geom: *const()) -> Geometry {
        return Geometry{
            c_geometry_ref: RefCell::new(Some(c_geom)),
            owned: true,
        };
    }

    pub fn empty(wkb_type: c_int) -> Geometry {
        let c_geom = unsafe { ogr::OGR_G_CreateGeometry(wkb_type) };
        assert!(c_geom != null());
        return unsafe { Geometry::with_c_geometry(c_geom) };
    }

    pub fn from_wkt(wkt: &str) -> Geometry {
        let c_wkt = CString::new(wkt.as_bytes()).unwrap();
        let mut c_wkt_ptr: *const c_char = c_wkt.as_ptr();
        let mut c_geom: *const () = null();
        let rv = unsafe { ogr::OGR_G_CreateFromWkt(&mut c_wkt_ptr, null(), &mut c_geom) };
        assert_eq!(rv, ogr::OGRERR_NONE);
        return unsafe { Geometry::with_c_geometry(c_geom) };
    }

    pub fn bbox(w: f64, s: f64, e: f64, n: f64) -> Geometry {
        Geometry::from_wkt(&format!(
            "POLYGON (({} {}, {} {}, {} {}, {} {}, {} {}))",
            w, n,
            e, n,
            e, s,
            w, s,
            w, n,
        ))
    }

    pub fn json(&self) -> String {
        let c_json = unsafe { ogr::OGR_G_ExportToJson(self.c_geometry()) };
        let rv = _string(c_json);
        unsafe { ogr::VSIFree(c_json as *mut ()) };
        return rv;
    }

    pub fn wkt(&self) -> String {
        let mut c_wkt: *const c_char = null();
        let _err = unsafe { ogr::OGR_G_ExportToWkt(self.c_geometry(), &mut c_wkt) };
        assert_eq!(_err, ogr::OGRERR_NONE);
        let wkt = _string(c_wkt);
        unsafe { ogr::OGRFree(c_wkt as *mut ()) };
        return wkt;
    }

    pub unsafe fn c_geometry(&self) -> *const () {
        return self.c_geometry_ref.borrow().unwrap();
    }

    pub fn set_point_2d(&mut self, i: i32, p: (f64, f64)) {
        let (x, y) = p;
        unsafe { ogr::OGR_G_SetPoint_2D(
            self.c_geometry(),
            i as c_int,
            x as c_double,
            y as c_double,
        ) };
    }

    pub fn get_point(&self, i: i32) -> (f64, f64, f64) {
        let mut x: c_double = 0.;
        let mut y: c_double = 0.;
        let mut z: c_double = 0.;
        unsafe { ogr::OGR_G_GetPoint(self.c_geometry(), i, &mut x, &mut y, &mut z) };
        return (x as f64, y as f64, z as f64);
    }

    pub fn to_geom(&self) -> Result<geom::Geom, GdalError> {
        let geometry_type = unsafe { ogr::OGR_G_GetGeometryType(self.c_geometry()) };
        match geometry_type {
            1 => {
                let (x, y, _) = self.get_point(0);
                Ok(geom::Geom::Point(geom::Point{x: x, y: y}))
            },
            _ => Err(GdalError{desc: "Unknown geometry type"})
        }
    }
}

impl Drop for Geometry {
    fn drop(&mut self) {
        if self.owned {
            let c_geometry = self.c_geometry_ref.borrow();
            unsafe { ogr::OGR_G_DestroyGeometry(c_geometry.unwrap() as *mut ()) };
        }
    }
}

pub trait ToGdal {
    fn to_gdal(&self) -> Geometry;
}

impl ToGdal for geom::Point {
    fn to_gdal(&self) -> Geometry {
        let mut geom = Geometry::empty(ogr::WKB_POINT);
        geom.set_point_2d(0, (self.x, self.y));
        return geom;
    }
}

#[cfg(test)]
mod tests {
    use vector::{Geometry, ToGdal};
    use vector::geom::{Geom, Point};

    #[test]
    fn test_ogr_to_point() {
        let g = Geometry::from_wkt("POINT (10 20)");
        assert_eq!(g.to_geom(), Ok(Geom::Point(Point{x: 10., y: 20.})));
    }

    #[test]
    fn test_point_to_ogr() {
        let g = Point{x: 10., y: 20.}.to_gdal();
        assert_eq!(g.wkt(), "POINT (10 20)");
    }
}
<|endoftext|>


<commit_before>use std::intrinsics::TypeId;
use std::cell::RefCell;
use std::rc::{Rc, Weak};
use std::fmt::{Formatter, Show, Result};
use std::collections::hashmap::HashMap;
use std::any::{Any, AnyRefExt, AnyMutRefExt};
use std::mem;
use uuid::Uuid;

/// Toplevel container of the entity component system.
pub struct World<T> {
    data: Rc<RefCell<WorldData<T>>>,
}

impl<T: System> World<T> {
    /// Create a world coupled with an application specific system object.
    pub fn new(master_system: T) -> World<T> {
        let ret = World {
            data: Rc::new(RefCell::new(WorldData::new(master_system))),
        };
        ret.data.borrow_mut().master_system.register(&ret);
        ret
    }

    /// Wrap an EntityId struct into an entity handle that has a backreference
    /// to the world object.
    fn wrap(&self, id: EntityId) -> Entity<T> {
        Entity {
            world: self.data.downgrade(),
            id: id
        }
    }

    /// Create a new entity bound to this world.
    pub fn new_entity(&mut self) -> Entity<T> {
        let id = EntityId {
            idx: self.data.borrow_mut().get_idx(),
            uuid: Uuid::new_v4(),
        };
        self.data.borrow_mut().register_new_entity(id);
        let ret = self.wrap(id);
        self.data.borrow_mut().master_system.added(&ret);
        ret
    }

    pub fn system<'a>(&'a self) -> &'a T {
        unsafe { mem::transmute(&self.data.borrow().master_system) }
    }

    pub fn system_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe { mem::transmute(&self.data.borrow_mut().master_system) }
    }

    pub fn find_entity(&self, uuid: &Uuid) -> Option<Entity<T>> {
        match self.data.borrow().uuids.find(uuid) {
            Some(idx) => Some(self.wrap(EntityId { uuid: *uuid, idx: *idx })),
            None => None
        }
    }
}

/// Callback interface for application data connected to the component system
/// world.
pub trait System {
    /// Callback for initially attaching the system to a world.
    fn register(&mut self, world: &World<Self>);
    /// Callback for adding a new entity to world.
    fn added(&mut self, e: &Entity<Self>);
    /// Callback for a component being added or removed in an entity. Note that
    /// this is not called when the data of an existing component is written
    /// to, only if the component is replaced or removed.
    fn changed<C>(&mut self, e: &Entity<Self>, component: Option<&C>);
    /// Callback for an entity being deleted.
    fn deleted(&mut self, e: &Entity<Self>);
}

#[deriving(Clone)]
pub struct Entity<T> {
    world: Weak<RefCell<WorldData<T>>>,
    id: EntityId,
}

impl<T> Show for Entity<T> {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}", self.id)
    }
}

impl<T: System> Entity<T> {
    /// Add or reset a component in the entity. Causes a "changed" call to the
    /// world system.
    pub fn set_component<C: 'static+Clone>(&mut self, comp: C) {
        self.world.upgrade().unwrap().borrow_mut().deref_mut()
            .set_component(self, Some(comp));
    }

    /// Remove a component from the entity. Causes a "changed" call to the
    /// world system.
    pub fn remove_component<C: 'static+Clone>(&mut self) {
        let comp : Option<C> = None;
        self.world.upgrade().unwrap().borrow_mut().deref_mut()
            .set_component(self, comp);
    }

    /// Delete the entity from the world. Causes a "deleted" call to the world
    /// system.
    pub fn delete(&mut self) {
        self.world.upgrade().unwrap().borrow_mut().deref_mut()
            .delete_entity(self);
    }

    /// Query whether the entity has a type of component.
    pub fn has<'a, C: 'static>(&self) -> bool {
        self.world.upgrade().unwrap().borrow()
            .comp_ref::<'a, C>(self.id).is_some()
    }

    /// Get an access proxy to the entity's component if the entity has that
    /// component.
    pub fn into<C: 'static>(&self) -> Option<CompProxyMut<T, C>> {
        if self.has::<C>() {
            Some(CompProxyMut {
                world: self.world.clone(),
                id: self.id
            })
        } else {
            None
        }
    }

    /// Return unique identifier for this entity.
    pub fn uuid(&self) -> Uuid {
        self.id.uuid
    }

    /// Return a handle to the world.
    pub fn world(&self) -> World<T> {
        World { data: self.world.upgrade().unwrap() }
    }
}

/// Access proxy to entity components. The implementation RefCell (mutable)
/// borrow internally, so using this carelessly may lead to runtime borrow
/// errors. You should generally keep access to the concrete entity data short
/// in scope and low in the call stack to prevent unexpected borrow failures.
pub struct CompProxyMut<T, C> {
    world: Weak<RefCell<WorldData<T>>>,
    id: EntityId,
}

impl<T: System, C: 'static> Deref<C> for CompProxyMut<T, C> {
    fn deref<'a>(&'a self) -> &'a C {
        self.world.upgrade().unwrap().borrow()
            .comp_ref::<'a, C>(self.id).unwrap()
    }
}

impl<T: System, C: 'static> DerefMut<C> for CompProxyMut<T, C> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut C {
        self.world.upgrade().unwrap().borrow_mut()
            .comp_ref_mut::<'a, C>(self.id).unwrap()
    }
}

#[deriving(PartialEq, Clone, Show)]
struct EntityId {
    uuid: Uuid,
    idx: uint,
}

struct WorldData<T> {
    // XXX: This is much less efficient than it could be. A serious
    // implementation would use unboxed vecs for the components and would
    // provide lookup methods faster than a HashMap find to access the
    // components
    components: HashMap<TypeId, Vec<Option<Box<Any>>>>,

    next_idx: uint,
    reusable_idxs: Vec<uint>,
    uuids: HashMap<Uuid, uint>,

    master_system: T,
}

impl<T: System> WorldData<T> {
    fn new(master_system: T) -> WorldData<T> {
        WorldData {
            components: HashMap::new(),
            next_idx: 0,
            reusable_idxs: vec!(),
            uuids: HashMap::new(),
            master_system: master_system,
        }
    }

    fn register_new_entity(&mut self, id: EntityId) {
        assert!(!self.uuids.contains_key(&id.uuid),
            "New entity clobbering existing one");
        self.uuids.insert(id.uuid, id.idx);
    }

    fn delete_entity(&mut self, e: &Entity<T>) {
        self.check_entity(e.id);
        self.uuids.remove(&e.id.uuid);

        for (_, c) in self.components.mut_iter() {
            if c.len() > e.id.idx {
                c.as_mut_slice()[e.id.idx] = None;
            }
        }

        self.reusable_idxs.push(e.id.idx);

        self.master_system.deleted(e);
    }

    /// Return the next unused reusable entity id.
    fn get_idx(&mut self) -> uint {
        match self.reusable_idxs.pop() {
            None => {
                let ret = self.next_idx;
                self.next_idx += 1;
                ret
            }
            Some(idx) => idx
        }
    }

    fn check_entity(&self, id: EntityId) {
        assert!(self.uuids.contains_key(&id.uuid), "Unknown entity UUID");
        assert!(*self.uuids.find(&id.uuid).unwrap() == id.idx, "Entity UUID mismatch");
    }

    fn set_component<C: 'static+Clone>(&mut self, e: &Entity<T>, comp: Option<C>) {
        self.check_entity(e.id);
        let type_id = TypeId::of::<C>();
        // We haven't seen this kind of component yet.
        if !self.components.contains_key(&type_id) {
            self.components.insert(type_id, vec!());
        }

        let bin = self.components.find_mut(&type_id).unwrap();

        // XXX: grow_set didn't work.
        while bin.len() <= e.id.idx { bin.push(None); }
        bin.as_mut_slice()[e.id.idx] = match comp {
            None => None,
            Some(c) => Some(box c as Box<Any>),
        };

        match bin.as_mut_slice()[e.id.idx] {
            None => self.master_system.changed::<C>(e, None),
            Some(ref c) => self.master_system.changed(e, Some(&c)),
        };
    }

    fn comp_ref<'a, C: 'static>(
        &self, id: EntityId) -> Option<&'a C> {
        self.check_entity(id);
        let type_id = TypeId::of::<C>();
        match self.components.find(&type_id) {
            None => { None }
            Some(bin) => {
                if id.idx < bin.len() {
                    match bin.get(id.idx) {
                        &Some(ref c) => { unsafe { Some(mem::transmute(c.as_ref::<C>().unwrap())) } }
                        &None => None
                    }
                } else {
                    None
                }
            }
        }
    }

    fn comp_ref_mut<'a, C: 'static>(
        &mut self, id: EntityId) -> Option<&'a mut C> {
        self.check_entity(id);
        let type_id = TypeId::of::<C>();
        match self.components.find_mut(&type_id) {
            None => { None }
            Some(bin) => {
                if id.idx < bin.len() {
                    match bin.get_mut(id.idx) {
                        &Some(ref mut c) => {
                            unsafe { Some(mem::transmute(c.as_mut::<C>().unwrap())) }
                        }
                        &None => None
                    }
                } else {
                    None
                }
            }
        }
    }
}

<commit_msg>Cloneability in ECS<commit_after>use std::intrinsics::TypeId;
use std::cell::RefCell;
use std::rc::{Rc, Weak};
use std::fmt::{Formatter, Show, Result};
use std::collections::hashmap::HashMap;
use std::any::{Any, AnyRefExt, AnyMutRefExt};
use std::mem;
use uuid::Uuid;

/// Toplevel container of the entity component system.
pub struct World<T> {
    data: Rc<RefCell<WorldData<T>>>,
}

impl<T> Clone for World<T> {
    fn clone(&self) -> World<T> {
        World { data: self.data.clone() }
    }
}

impl<T: System> World<T> {
    /// Create a world coupled with an application specific system object.
    pub fn new(master_system: T) -> World<T> {
        let ret = World {
            data: Rc::new(RefCell::new(WorldData::new(master_system))),
        };
        ret.data.borrow_mut().master_system.register(&ret);
        ret
    }

    /// Wrap an EntityId struct into an entity handle that has a backreference
    /// to the world object.
    fn wrap(&self, id: EntityId) -> Entity<T> {
        Entity {
            world: self.data.downgrade(),
            id: id
        }
    }

    /// Create a new entity bound to this world.
    pub fn new_entity(&mut self) -> Entity<T> {
        let id = EntityId {
            idx: self.data.borrow_mut().get_idx(),
            uuid: Uuid::new_v4(),
        };
        self.data.borrow_mut().register_new_entity(id);
        let ret = self.wrap(id);
        self.data.borrow_mut().master_system.added(&ret);
        ret
    }

    pub fn system<'a>(&'a self) -> &'a T {
        unsafe { mem::transmute(&self.data.borrow().master_system) }
    }

    pub fn system_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe { mem::transmute(&self.data.borrow_mut().master_system) }
    }

    pub fn find_entity(&self, uuid: &Uuid) -> Option<Entity<T>> {
        match self.data.borrow().uuids.find(uuid) {
            Some(idx) => Some(self.wrap(EntityId { uuid: *uuid, idx: *idx })),
            None => None
        }
    }
}

/// Callback interface for application data connected to the component system
/// world.
pub trait System {
    /// Callback for initially attaching the system to a world.
    fn register(&mut self, world: &World<Self>);
    /// Callback for adding a new entity to world.
    fn added(&mut self, e: &Entity<Self>);
    /// Callback for a component being added or removed in an entity. Note that
    /// this is not called when the data of an existing component is written
    /// to, only if the component is replaced or removed.
    fn changed<C>(&mut self, e: &Entity<Self>, component: Option<&C>);
    /// Callback for an entity being deleted.
    fn deleted(&mut self, e: &Entity<Self>);
}

#[deriving(Clone)]
pub struct Entity<T> {
    world: Weak<RefCell<WorldData<T>>>,
    id: EntityId,
}

impl<T> Show for Entity<T> {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}", self.id)
    }
}

impl<T: System> Entity<T> {
    /// Add or reset a component in the entity. Causes a "changed" call to the
    /// world system.
    pub fn set_component<C: 'static+Clone>(&mut self, comp: C) {
        self.world.upgrade().unwrap().borrow_mut().deref_mut()
            .set_component(self, Some(comp));
    }

    /// Remove a component from the entity. Causes a "changed" call to the
    /// world system.
    pub fn remove_component<C: 'static+Clone>(&mut self) {
        let comp : Option<C> = None;
        self.world.upgrade().unwrap().borrow_mut().deref_mut()
            .set_component(self, comp);
    }

    /// Delete the entity from the world. Causes a "deleted" call to the world
    /// system.
    pub fn delete(&mut self) {
        self.world.upgrade().unwrap().borrow_mut().deref_mut()
            .delete_entity(self);
    }

    /// Query whether the entity has a type of component.
    pub fn has<'a, C: 'static>(&self) -> bool {
        self.world.upgrade().unwrap().borrow()
            .comp_ref::<'a, C>(self.id).is_some()
    }

    /// Get an access proxy to the entity's component if the entity has that
    /// component.
    pub fn into<C: 'static>(&self) -> Option<CompProxyMut<T, C>> {
        if self.has::<C>() {
            Some(CompProxyMut {
                world: self.world.clone(),
                id: self.id
            })
        } else {
            None
        }
    }

    /// Return unique identifier for this entity.
    pub fn uuid(&self) -> Uuid {
        self.id.uuid
    }

    /// Return a handle to the world.
    pub fn world(&self) -> World<T> {
        World { data: self.world.upgrade().unwrap() }
    }
}

/// Access proxy to entity components. The implementation RefCell (mutable)
/// borrow internally, so using this carelessly may lead to runtime borrow
/// errors. You should generally keep access to the concrete entity data short
/// in scope and low in the call stack to prevent unexpected borrow failures.
pub struct CompProxyMut<T, C> {
    world: Weak<RefCell<WorldData<T>>>,
    id: EntityId,
}

impl<T: System, C: 'static> Deref<C> for CompProxyMut<T, C> {
    fn deref<'a>(&'a self) -> &'a C {
        self.world.upgrade().unwrap().borrow()
            .comp_ref::<'a, C>(self.id).unwrap()
    }
}

impl<T: System, C: 'static> DerefMut<C> for CompProxyMut<T, C> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut C {
        self.world.upgrade().unwrap().borrow_mut()
            .comp_ref_mut::<'a, C>(self.id).unwrap()
    }
}

#[deriving(PartialEq, Clone, Show)]
struct EntityId {
    uuid: Uuid,
    idx: uint,
}

struct WorldData<T> {
    // XXX: This is much less efficient than it could be. A serious
    // implementation would use unboxed vecs for the components and would
    // provide lookup methods faster than a HashMap find to access the
    // components
    components: HashMap<TypeId, Vec<Option<Box<Any>>>>,

    next_idx: uint,
    reusable_idxs: Vec<uint>,
    uuids: HashMap<Uuid, uint>,

    master_system: T,
}

impl<T: System> WorldData<T> {
    fn new(master_system: T) -> WorldData<T> {
        WorldData {
            components: HashMap::new(),
            next_idx: 0,
            reusable_idxs: vec!(),
            uuids: HashMap::new(),
            master_system: master_system,
        }
    }

    fn register_new_entity(&mut self, id: EntityId) {
        assert!(!self.uuids.contains_key(&id.uuid),
            "New entity clobbering existing one");
        self.uuids.insert(id.uuid, id.idx);
    }

    fn delete_entity(&mut self, e: &Entity<T>) {
        self.check_entity(e.id);
        self.uuids.remove(&e.id.uuid);

        for (_, c) in self.components.mut_iter() {
            if c.len() > e.id.idx {
                c.as_mut_slice()[e.id.idx] = None;
            }
        }

        self.reusable_idxs.push(e.id.idx);

        self.master_system.deleted(e);
    }

    /// Return the next unused reusable entity id.
    fn get_idx(&mut self) -> uint {
        match self.reusable_idxs.pop() {
            None => {
                let ret = self.next_idx;
                self.next_idx += 1;
                ret
            }
            Some(idx) => idx
        }
    }

    fn check_entity(&self, id: EntityId) {
        assert!(self.uuids.contains_key(&id.uuid), "Unknown entity UUID");
        assert!(*self.uuids.find(&id.uuid).unwrap() == id.idx, "Entity UUID mismatch");
    }

    fn set_component<C: 'static+Clone>(&mut self, e: &Entity<T>, comp: Option<C>) {
        self.check_entity(e.id);
        let type_id = TypeId::of::<C>();
        // We haven't seen this kind of component yet.
        if !self.components.contains_key(&type_id) {
            self.components.insert(type_id, vec!());
        }

        let bin = self.components.find_mut(&type_id).unwrap();

        // XXX: grow_set didn't work.
        while bin.len() <= e.id.idx { bin.push(None); }
        bin.as_mut_slice()[e.id.idx] = match comp {
            None => None,
            Some(c) => Some(box c as Box<Any>),
        };

        match bin.as_mut_slice()[e.id.idx] {
            None => self.master_system.changed::<C>(e, None),
            Some(ref c) => self.master_system.changed(e, Some(&c)),
        };
    }

    fn comp_ref<'a, C: 'static>(
        &self, id: EntityId) -> Option<&'a C> {
        self.check_entity(id);
        let type_id = TypeId::of::<C>();
        match self.components.find(&type_id) {
            None => { None }
            Some(bin) => {
                if id.idx < bin.len() {
                    match bin.get(id.idx) {
                        &Some(ref c) => { unsafe { Some(mem::transmute(c.as_ref::<C>().unwrap())) } }
                        &None => None
                    }
                } else {
                    None
                }
            }
        }
    }

    fn comp_ref_mut<'a, C: 'static>(
        &mut self, id: EntityId) -> Option<&'a mut C> {
        self.check_entity(id);
        let type_id = TypeId::of::<C>();
        match self.components.find_mut(&type_id) {
            None => { None }
            Some(bin) => {
                if id.idx < bin.len() {
                    match bin.get_mut(id.idx) {
                        &Some(ref mut c) => {
                            unsafe { Some(mem::transmute(c.as_mut::<C>().unwrap())) }
                        }
                        &None => None
                    }
                } else {
                    None
                }
            }
        }
    }
}

<|endoftext|>


<commit_before>//! # ADC module
//!
//! This module provides access to the ADC of the stm32f0 board.
//! You can:
//!
//! * configure a PIN in Input
//! * read the analog value from the PIN
//!
//! ## Examples
//!
//! ```
//! extern crate stm32f0_hal;
//!
//! use stm32f0_hal::adc;
//!
// ! let p = adc::Input::setup(adc::Pin::P4);
// ! let b = p.read();
//! ```

use cortex_m;
use stm32f0x2::{GPIOC, RCC, ADC};

/// ADC Pin available on PORT C
pub enum Pin {
    P3,
    P4,
}

/// Input Mode Pin
pub struct Input {
    pin: Pin,
}
impl Input {
    /// Setup a PIN in Input Mode
    pub fn setup(pin: Pin) -> Input {
        setup_pin(&pin);
        Input { pin }
    }
    /// Read the analog value of a PIN
    pub fn read(&self) -> u16 {
        cortex_m::interrupt::free(|cs| {
            let adc = ADC.borrow(cs);

            // ADC Channel selection
            match self.pin {
                Pin::P3 => adc.chselr.write(|w| w.chsel13().set_bit()),
                Pin::P4 => adc.chselr.write(|w| w.chsel14().set_bit()),
            }

            // Active ADC and Start Conversion
            adc.cr.write(|w| w.aden().set_bit().adstart().set_bit());

            // Wait end of conversation
            while adc.isr.read().eoc().bit_is_clear() {}

            // Return result
            adc.dr.read().data().bits()
        })
    }
}

fn setup_pin(pin: &Pin) {
    cortex_m::interrupt::free(|cs| {
        let rcc = RCC.borrow(cs);
        let gpioc = GPIOC.borrow(cs);

        // Clock Activation PORTC
        rcc.ahbenr.modify(|_, w| w.iopaen().enabled());
        // Clock activation ADC
        rcc.apb2enr.modify(|_, w| w.adcen().enabled());

        // PA Analog Input Channel
        match *pin {
            Pin::P3 => gpioc.moder.modify(|_, w| w.moder3().analog()),
            Pin::P4 => gpioc.moder.modify(|_, w| w.moder4().analog()),
        }
    });
}
<commit_msg>Typo in comment.<commit_after>//! # ADC module
//!
//! This module provides access to the ADC of the stm32f0 board.
//! You can:
//!
//! * configure a PIN in Input
//! * read the analog value from the PIN
//!
//! ## Examples
//!
//! ```
//! extern crate stm32f0_hal;
//!
//! use stm32f0_hal::adc;
//!
//! let p = adc::Input::setup(adc::Pin::P4);
//! let b = p.read();
//! ```

use cortex_m;
use stm32f0x2::{GPIOC, RCC, ADC};

/// ADC Pin available on PORT C
pub enum Pin {
    P3,
    P4,
}

/// Input Mode Pin
pub struct Input {
    pin: Pin,
}
impl Input {
    /// Setup a PIN in Input Mode
    pub fn setup(pin: Pin) -> Input {
        setup_pin(&pin);
        Input { pin }
    }
    /// Read the analog value of a PIN
    pub fn read(&self) -> u16 {
        cortex_m::interrupt::free(|cs| {
            let adc = ADC.borrow(cs);

            // ADC Channel selection
            match self.pin {
                Pin::P3 => adc.chselr.write(|w| w.chsel13().set_bit()),
                Pin::P4 => adc.chselr.write(|w| w.chsel14().set_bit()),
            }

            // Active ADC and Start Conversion
            adc.cr.write(|w| w.aden().set_bit().adstart().set_bit());

            // Wait end of conversation
            while adc.isr.read().eoc().bit_is_clear() {}

            // Return result
            adc.dr.read().data().bits()
        })
    }
}

fn setup_pin(pin: &Pin) {
    cortex_m::interrupt::free(|cs| {
        let rcc = RCC.borrow(cs);
        let gpioc = GPIOC.borrow(cs);

        // Clock Activation PORTC
        rcc.ahbenr.modify(|_, w| w.iopaen().enabled());
        // Clock activation ADC
        rcc.apb2enr.modify(|_, w| w.adcen().enabled());

        // PA Analog Input Channel
        match *pin {
            Pin::P3 => gpioc.moder.modify(|_, w| w.moder3().analog()),
            Pin::P4 => gpioc.moder.modify(|_, w| w.moder4().analog()),
        }
    });
}
<|endoftext|>


<commit_before>use puyoai_core::decision::Decision;

pub struct FrameResponse {
    pub frame_id: i32,
    pub decision: Decision,
    pub message: String,
}
<commit_msg>Add FrameResponse::to_string<commit_after>use puyoai_core::decision::Decision;

pub struct FrameResponse {
    pub frame_id: i32,
    pub decision: Decision,
    pub message: String,
}

fn escape_message(s: &str) -> String {
    let mut result = String::new();
    for c in s.chars() {
        if c == ' ' {
            result.push('_');
        } else if c == '\n' {
            result.push(',');
        } else {
            result.push(c);
        }
    }

    result
}

impl FrameResponse {
    pub fn to_string(&self) -> String {
        let mut result = String::new();

        result.push_str(&format!("ID={}", self.frame_id));
        if self.decision.valid() {
            result.push_str(&format!(" X={}", self.decision.axis_x()));
            result.push_str(&format!(" R={}", self.decision.rot()));
        }
        if !self.message.is_empty() {
            result.push_str(&format!(" MSG={}", escape_message(&self.message)))
        }

        result
    }
}

#[cfg(test)]
mod tests {
    use super::FrameResponse;
    use puyoai_core::decision::Decision;

    #[test]
    fn test_to_string() {
        let resp = FrameResponse {
            frame_id: 1,
            decision: Decision::new(3, 1),
            message: "test".to_string(),
        };

        assert_eq!(resp.to_string(), "ID=1 X=3 R=1 MSG=test");
    }
}
<|endoftext|>


<commit_before>/* 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 freetype::freetype::FTErrorMethods;
use freetype::freetype::FT_Add_Default_Modules;
use freetype::freetype::FT_Done_Library;
use freetype::freetype::FT_Library;
use freetype::freetype::FT_Memory;
use freetype::freetype::FT_New_Library;
use freetype::freetype::struct_FT_MemoryRec_;

use std::ptr;
use std::rc::Rc;
use std::rt::heap;
use util::mem::{HeapSizeOf, heap_size_of};

use libc::{c_void, c_long};

// We pass a |User| struct -- via an opaque |void*| -- to FreeType each time a new instance is
// created. FreeType passes it back to the ft_alloc/ft_realloc/ft_free callbacks. We use it to
// record the memory usage of each FreeType instance.
struct User {
    size: usize,
}

// FreeType doesn't require any particular alignment for allocations.
const FT_ALIGNMENT: usize = 0;

extern fn ft_alloc(mem: FT_Memory, req_size: c_long) -> *mut c_void {
    unsafe {
        let ptr = heap::allocate(req_size as usize, FT_ALIGNMENT) as *mut c_void;
        let actual_size = heap_size_of(ptr);

        let user = (*mem).user as *mut User;
        (*user).size += actual_size;

        ptr
    }
}

extern fn ft_free(mem: FT_Memory, ptr: *mut c_void) {
    unsafe {
        let actual_size = heap_size_of(ptr);

        let user = (*mem).user as *mut User;
        (*user).size -= actual_size;

        heap::deallocate(ptr as *mut u8, actual_size, FT_ALIGNMENT);
    }
}

extern fn ft_realloc(mem: FT_Memory, _cur_size: c_long, new_req_size: c_long,
                     old_ptr: *mut c_void) -> *mut c_void {
    unsafe {
        let old_actual_size = heap_size_of(old_ptr);
        let new_ptr = heap::reallocate(old_ptr as *mut u8, old_actual_size,
                                       new_req_size as usize, FT_ALIGNMENT) as *mut c_void;
        let new_actual_size = heap_size_of(new_ptr);

        let user = (*mem).user as *mut User;
        (*user).size += new_actual_size - old_actual_size;

        new_ptr
    }
}

// A |*mut User| field in a struct triggers a "use of `#[derive]` with a raw pointer" warning from
// rustc. But using a typedef avoids this, so...
pub type UserPtr = *mut User;

// WARNING: We need to be careful how we use this struct. See the comment about Rc<> in
// FontContextHandle.
#[derive(Clone)]
pub struct FreeTypeLibraryHandle {
    pub ctx: FT_Library,
    mem: FT_Memory,
    user: UserPtr,
}

impl Drop for FreeTypeLibraryHandle {
    fn drop(&mut self) {
        assert!(!self.ctx.is_null());
        unsafe {
            FT_Done_Library(self.ctx);
            Box::from_raw(self.mem);
            Box::from_raw(self.user);
        }
    }
}

impl HeapSizeOf for FreeTypeLibraryHandle {
    fn heap_size_of_children(&self) -> usize {
        let ft_size = unsafe { (*self.user).size };
        ft_size +
            heap_size_of(self.ctx as *const c_void) +
            heap_size_of(self.mem as *const c_void) +
            heap_size_of(self.user as *const c_void)
    }
}

#[derive(Clone, HeapSizeOf)]
pub struct FontContextHandle {
    // WARNING: FreeTypeLibraryHandle contains raw pointers, is clonable, and also implements
    // `Drop`. This field needs to be Rc<> to make sure that the `drop` function is only called
    // once, otherwise we'll get crashes. Yuk.
    pub ctx: Rc<FreeTypeLibraryHandle>,
}

impl FontContextHandle {
    pub fn new() -> FontContextHandle {
        let user = Box::into_raw(box User {
            size: 0,
        });
        let mem = Box::into_raw(box struct_FT_MemoryRec_ {
            user: user as *mut c_void,
            alloc: ft_alloc,
            free: ft_free,
            realloc: ft_realloc,
        });
        unsafe {
            let mut ctx: FT_Library = ptr::null_mut();

            let result = FT_New_Library(mem, &mut ctx);
            if !result.succeeded() { panic!("Unable to initialize FreeType library"); }

            FT_Add_Default_Modules(ctx);

            FontContextHandle {
                ctx: Rc::new(FreeTypeLibraryHandle { ctx: ctx, mem: mem, user: user }),
            }
        }
    }
}
<commit_msg>Avoid undefined behaviour by allocating with align 1.<commit_after>/* 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 freetype::freetype::FTErrorMethods;
use freetype::freetype::FT_Add_Default_Modules;
use freetype::freetype::FT_Done_Library;
use freetype::freetype::FT_Library;
use freetype::freetype::FT_Memory;
use freetype::freetype::FT_New_Library;
use freetype::freetype::struct_FT_MemoryRec_;

use std::ptr;
use std::rc::Rc;
use std::rt::heap;
use util::mem::{HeapSizeOf, heap_size_of};

use libc::{c_void, c_long};

// We pass a |User| struct -- via an opaque |void*| -- to FreeType each time a new instance is
// created. FreeType passes it back to the ft_alloc/ft_realloc/ft_free callbacks. We use it to
// record the memory usage of each FreeType instance.
struct User {
    size: usize,
}

// FreeType doesn't require any particular alignment for allocations.
const FT_ALIGNMENT: usize = 1;

extern fn ft_alloc(mem: FT_Memory, req_size: c_long) -> *mut c_void {
    unsafe {
        let ptr = heap::allocate(req_size as usize, FT_ALIGNMENT) as *mut c_void;
        let actual_size = heap_size_of(ptr);

        let user = (*mem).user as *mut User;
        (*user).size += actual_size;

        ptr
    }
}

extern fn ft_free(mem: FT_Memory, ptr: *mut c_void) {
    unsafe {
        let actual_size = heap_size_of(ptr);

        let user = (*mem).user as *mut User;
        (*user).size -= actual_size;

        heap::deallocate(ptr as *mut u8, actual_size, FT_ALIGNMENT);
    }
}

extern fn ft_realloc(mem: FT_Memory, _cur_size: c_long, new_req_size: c_long,
                     old_ptr: *mut c_void) -> *mut c_void {
    unsafe {
        let old_actual_size = heap_size_of(old_ptr);
        let new_ptr = heap::reallocate(old_ptr as *mut u8, old_actual_size,
                                       new_req_size as usize, FT_ALIGNMENT) as *mut c_void;
        let new_actual_size = heap_size_of(new_ptr);

        let user = (*mem).user as *mut User;
        (*user).size += new_actual_size - old_actual_size;

        new_ptr
    }
}

// A |*mut User| field in a struct triggers a "use of `#[derive]` with a raw pointer" warning from
// rustc. But using a typedef avoids this, so...
pub type UserPtr = *mut User;

// WARNING: We need to be careful how we use this struct. See the comment about Rc<> in
// FontContextHandle.
#[derive(Clone)]
pub struct FreeTypeLibraryHandle {
    pub ctx: FT_Library,
    mem: FT_Memory,
    user: UserPtr,
}

impl Drop for FreeTypeLibraryHandle {
    fn drop(&mut self) {
        assert!(!self.ctx.is_null());
        unsafe {
            FT_Done_Library(self.ctx);
            Box::from_raw(self.mem);
            Box::from_raw(self.user);
        }
    }
}

impl HeapSizeOf for FreeTypeLibraryHandle {
    fn heap_size_of_children(&self) -> usize {
        let ft_size = unsafe { (*self.user).size };
        ft_size +
            heap_size_of(self.ctx as *const c_void) +
            heap_size_of(self.mem as *const c_void) +
            heap_size_of(self.user as *const c_void)
    }
}

#[derive(Clone, HeapSizeOf)]
pub struct FontContextHandle {
    // WARNING: FreeTypeLibraryHandle contains raw pointers, is clonable, and also implements
    // `Drop`. This field needs to be Rc<> to make sure that the `drop` function is only called
    // once, otherwise we'll get crashes. Yuk.
    pub ctx: Rc<FreeTypeLibraryHandle>,
}

impl FontContextHandle {
    pub fn new() -> FontContextHandle {
        let user = Box::into_raw(box User {
            size: 0,
        });
        let mem = Box::into_raw(box struct_FT_MemoryRec_ {
            user: user as *mut c_void,
            alloc: ft_alloc,
            free: ft_free,
            realloc: ft_realloc,
        });
        unsafe {
            let mut ctx: FT_Library = ptr::null_mut();

            let result = FT_New_Library(mem, &mut ctx);
            if !result.succeeded() { panic!("Unable to initialize FreeType library"); }

            FT_Add_Default_Modules(ctx);

            FontContextHandle {
                ctx: Rc::new(FreeTypeLibraryHandle { ctx: ctx, mem: mem, user: user }),
            }
        }
    }
}
<|endoftext|>


<commit_before>use ritual::config::Config;
use ritual::cpp_checker::{PreliminaryTest, Snippet};
use ritual::cpp_data::{CppItem, CppPath};
use ritual::cpp_ffi_data::CppFfiFunctionKind;
use ritual::cpp_type::CppType;
use ritual::rust_info::{NameType, RustPathScope};
use ritual::rust_type::RustPath;
use ritual_common::errors::{bail, Result};

/// QtCore specific configuration.
pub fn core_config(config: &mut Config) -> Result<()> {
    let crate_name = config.crate_properties().name().to_string();
    let namespace = CppPath::from_good_str("Qt");
    config.set_rust_path_scope_hook(move |path| {
        if path == &namespace {
            return Ok(Some(RustPathScope {
                path: RustPath::from_good_str(&crate_name),
                prefix: None,
            }));
        }
        Ok(None)
    });

    config.set_cpp_parser_path_hook(|path| {
        let string = path.to_templateless_string();
        let blocked = &[
            // Qt internals, not intended for direct use
            "QtPrivate",
            "QAlgorithmsPrivate",
            "QtMetaTypePrivate",
            "QInternal",
            "qFlagLocation",
            "QArrayData",
            "QTypedArrayData",
            "QStaticByteArrayData",
            "QListData",
            "QObjectData",
            "QObjectUserData",
            "QObject::registerUserData",
            "QMapNodeBase",
            "QMapNode",
            "QMapDataBase",
            "QMapData",
            "QHashData",
            "QHashDummyValue",
            "QHashNode",
            "QContiguousCacheData",
            "QContiguousCacheTypedData",
            "QLinkedListData",
            "QLinkedListNode",
            "QThreadStorageData",
            "QVariant::Private",
            "QVariant::PrivateShared",
            "QByteArrayDataPtr",
            "QStringDataPtr",
            "QArrayDataPointer",
            "QArrayDataPointerRef",
            "QMetaTypeId",
            "QMetaTypeId2",
            "QVariantComparisonHelper",
            "QtStringBuilder",
            "QStringBuilder",
            "QStringBuilderCommon",
            "QStringBuilderBase",
            "QConcatenable",
            "QVariant::Handler",
            "QForeachContainer",
            "QPersistentModelIndex::internalId",
            "QPersistentModelIndex::internalPointer",
            "qMapLessThanKey",
            "qt_hash",
            "qt_qFindChild_helper",
            "qt_qFindChildren_helper",
            "qt_sharedpointer_cast_check",
            "qThreadStorage_deleteData",
            "qbswap_helper",
            // deprecated
            "qGreater",
            "qLess",
            "QString::Null",
            // undocumented, does nothing
            "qt_noop",
            "QNoDebug",
            // undocumented, unknown purpose
            "qTerminate",
            "qt_error_string",
            "QFutureInterfaceBase",
            "QFutureInterfaceBase",
            "Qt::Initialization",
            "QAbstractConcatenable",
            "QTextCodec::ConverterState",
            "QJsonValuePtr",
            "QJsonValueRefPtr",
            "QTypeInfo",
            "QTypeInfoQuery",
            "QTypeInfoMerger",
            "QtGlobalStatic",
            "_GUID",
            // for Q_ASSERT, Q_ASSERT_X macros, no need to access this from Rust
            "qt_assert",
            "qt_assert_x",
            // for Q_CHECK_PTR macro, no need to access this from Rust
            "qt_check_pointer",
            "q_check_ptr",
            // atomic operations, useless in Rust
            "QGenericAtomicOps",
            "QAtomicTraits",
            "QAtomicOps",
            "QBasicAtomicInteger",
            "QBasicAtomicPointer",
            "qAtomicAssign",
            "qAtomicDetach",
            "QAtomicAdditiveType",
            "QAtomicInt",
            "QAtomicPointer",
            "QAtomicInteger",
            // BE/LE integers, useless in Rust
            "QSpecialInteger",
            "QBigEndianStorageType",
            "QLittleEndianStorageType",
            // works on overloading, can't be useful in Rust
            "Qt::qt_getEnumName",
            // reimplemented in Rust
            "QFlag",
            "QIncompatibleFlag",
            // not useful in Rust
            "QtSharedPointer",
            "QSharedPointer",
            "QWeakPointer",
            "QEnableSharedFromThis",
            "QScopedArrayPointer",
            // throws exception, so useless here
            "qBadAlloc",
            // requires user class templates, so useless here
            "QSharedDataPointer",
            "QExplicitlySharedDataPointer",
            "QSharedData",
            "QScopeGuard",
            "QScopedValueRollback",
            "QScopedPointer",
            "QScopedPointerObjectDeleteLater",
            "QScopedPointerPodDeleter",
            "QScopedPointerDeleter",
            "QScopedPointerArrayDeleter",
            "QGenericArgument",
            "QGenericReturnArgument",
            "QNonConstOverload",
            "QConstOverload",
            // global functions that redirects to member functions
            "swap",
            // is not cross-platform and is deprecated anyway
            "QProcess::pid",
        ];
        if blocked.contains(&string.as_str()) {
            return Ok(false);
        }

        Ok(true)
    });
    // TODO: replace QVariant::Type with QMetaType::Type?

    let connect_path = CppPath::from_good_str("QObject::connect");
    let qmetamethod_ref_type =
        CppType::new_reference(true, CppType::Class(CppPath::from_good_str("QMetaMethod")));
    config.set_rust_path_hook(move |_path, name_type, data| {
        if let NameType::ApiFunction(function) = name_type {
            if let CppFfiFunctionKind::Function { cpp_function, .. } = &function.kind {
                if cpp_function.path == connect_path && cpp_function.arguments.len() >= 3 {
                    if !cpp_function.is_static_member() {
                        bail!("non-static QObject::connect is blacklisted");
                    }
                    let arg = &cpp_function.arguments[1].argument_type;
                    if arg == &qmetamethod_ref_type {
                        return Ok(Some(RustPath::from_good_str(&format!(
                            "{}::QObject::connect_by_meta_methods",
                            data.current_database.crate_name()
                        ))));
                    }
                }
            }
        }
        Ok(None)
    });

    config.set_ffi_generator_hook(|item| {
        if let CppItem::Function(function) = &item.item {
            if let Ok(class_type) = function.class_type() {
                let class_text = class_type.to_templateless_string();
                if class_text == "QFlags" {
                    return Ok(false);
                }
            }
            if function.is_operator() {
                if let CppType::Class(path) = &function.return_type {
                    if path.to_templateless_string() == "QFlags" {
                        return Ok(false);
                    }
                }
            }
        }
        Ok(true)
    });

    let tests = if config.crate_properties().name().starts_with("moqt") {
        vec![PreliminaryTest::new(
            "moqt_abs",
            true,
            Snippet::new_in_main("ritual_assert(moqt_abs(-2) == 2);", false),
        )]
    } else {
        let code1 = format!(
            "ritual_assert(QLibraryInfo::version().toString() == \"{}\");",
            config.cpp_lib_version().unwrap()
        );
        let test1 = PreliminaryTest::new("qt_version_fn", true, Snippet::new_in_main(code1, false));

        let code2 = format!(
            "ritual_assert(strcmp(QT_VERSION_STR, \"{}\") == 0);",
            config.cpp_lib_version().unwrap()
        );
        let test2 = PreliminaryTest::new(
            "qt_version_define",
            true,
            Snippet::new_in_main(code2, false),
        );
        let code3 = "
            class Class1 : public QObject {
            Q_OBJECT
            public:
                Class1() {
                    emit signal1();
                }
            signals:
                void signal1();
            };

            void x() {
                Class1 c;
            }
        ";
        let test3 =
            PreliminaryTest::new("class_with_signal", true, Snippet::new_global(code3, true));

        vec![test1, test2, test3]
    };
    config.add_cpp_checker_tests(tests);
    Ok(())
}
<commit_msg>blacklist qt_getEnumMetaObject<commit_after>use ritual::config::Config;
use ritual::cpp_checker::{PreliminaryTest, Snippet};
use ritual::cpp_data::{CppItem, CppPath};
use ritual::cpp_ffi_data::CppFfiFunctionKind;
use ritual::cpp_type::CppType;
use ritual::rust_info::{NameType, RustPathScope};
use ritual::rust_type::RustPath;
use ritual_common::errors::{bail, Result};

/// QtCore specific configuration.
pub fn core_config(config: &mut Config) -> Result<()> {
    let crate_name = config.crate_properties().name().to_string();
    let namespace = CppPath::from_good_str("Qt");
    config.set_rust_path_scope_hook(move |path| {
        if path == &namespace {
            return Ok(Some(RustPathScope {
                path: RustPath::from_good_str(&crate_name),
                prefix: None,
            }));
        }
        Ok(None)
    });

    config.set_cpp_parser_path_hook(|path| {
        let string = path.to_templateless_string();
        let blocked = &[
            // Qt internals, not intended for direct use
            "QtPrivate",
            "QAlgorithmsPrivate",
            "QtMetaTypePrivate",
            "QInternal",
            "qFlagLocation",
            "QArrayData",
            "QTypedArrayData",
            "QStaticByteArrayData",
            "QListData",
            "QObjectData",
            "QObjectUserData",
            "QObject::registerUserData",
            "QMapNodeBase",
            "QMapNode",
            "QMapDataBase",
            "QMapData",
            "QHashData",
            "QHashDummyValue",
            "QHashNode",
            "QContiguousCacheData",
            "QContiguousCacheTypedData",
            "QLinkedListData",
            "QLinkedListNode",
            "QThreadStorageData",
            "QVariant::Private",
            "QVariant::PrivateShared",
            "QByteArrayDataPtr",
            "QStringDataPtr",
            "QArrayDataPointer",
            "QArrayDataPointerRef",
            "QMetaTypeId",
            "QMetaTypeId2",
            "QVariantComparisonHelper",
            "QtStringBuilder",
            "QStringBuilder",
            "QStringBuilderCommon",
            "QStringBuilderBase",
            "QConcatenable",
            "QVariant::Handler",
            "QForeachContainer",
            "QPersistentModelIndex::internalId",
            "QPersistentModelIndex::internalPointer",
            "qMapLessThanKey",
            "qt_hash",
            "qt_qFindChild_helper",
            "qt_qFindChildren_helper",
            "qt_sharedpointer_cast_check",
            "qThreadStorage_deleteData",
            "qbswap_helper",
            // deprecated
            "qGreater",
            "qLess",
            "QString::Null",
            // undocumented, does nothing
            "qt_noop",
            "QNoDebug",
            // undocumented, unknown purpose
            "qTerminate",
            "qt_error_string",
            "QFutureInterfaceBase",
            "QFutureInterfaceBase",
            "Qt::Initialization",
            "QAbstractConcatenable",
            "QTextCodec::ConverterState",
            "QJsonValuePtr",
            "QJsonValueRefPtr",
            "QTypeInfo",
            "QTypeInfoQuery",
            "QTypeInfoMerger",
            "QtGlobalStatic",
            "_GUID",
            // for Q_ASSERT, Q_ASSERT_X macros, no need to access this from Rust
            "qt_assert",
            "qt_assert_x",
            // for Q_CHECK_PTR macro, no need to access this from Rust
            "qt_check_pointer",
            "q_check_ptr",
            // atomic operations, useless in Rust
            "QGenericAtomicOps",
            "QAtomicTraits",
            "QAtomicOps",
            "QBasicAtomicInteger",
            "QBasicAtomicPointer",
            "qAtomicAssign",
            "qAtomicDetach",
            "QAtomicAdditiveType",
            "QAtomicInt",
            "QAtomicPointer",
            "QAtomicInteger",
            // BE/LE integers, useless in Rust
            "QSpecialInteger",
            "QBigEndianStorageType",
            "QLittleEndianStorageType",
            // works on overloading, can't be useful in Rust
            "Qt::qt_getEnumName",
            "Qt::qt_getEnumMetaObject",
            // reimplemented in Rust
            "QFlag",
            "QIncompatibleFlag",
            // not useful in Rust
            "QtSharedPointer",
            "QSharedPointer",
            "QWeakPointer",
            "QEnableSharedFromThis",
            "QScopedArrayPointer",
            // throws exception, so useless here
            "qBadAlloc",
            // requires user class templates, so useless here
            "QSharedDataPointer",
            "QExplicitlySharedDataPointer",
            "QSharedData",
            "QScopeGuard",
            "QScopedValueRollback",
            "QScopedPointer",
            "QScopedPointerObjectDeleteLater",
            "QScopedPointerPodDeleter",
            "QScopedPointerDeleter",
            "QScopedPointerArrayDeleter",
            "QGenericArgument",
            "QGenericReturnArgument",
            "QNonConstOverload",
            "QConstOverload",
            // global functions that redirects to member functions
            "swap",
            // is not cross-platform and is deprecated anyway
            "QProcess::pid",
        ];
        if blocked.contains(&string.as_str()) {
            return Ok(false);
        }

        Ok(true)
    });
    // TODO: replace QVariant::Type with QMetaType::Type?

    let connect_path = CppPath::from_good_str("QObject::connect");
    let qmetamethod_ref_type =
        CppType::new_reference(true, CppType::Class(CppPath::from_good_str("QMetaMethod")));
    config.set_rust_path_hook(move |_path, name_type, data| {
        if let NameType::ApiFunction(function) = name_type {
            if let CppFfiFunctionKind::Function { cpp_function, .. } = &function.kind {
                if cpp_function.path == connect_path && cpp_function.arguments.len() >= 3 {
                    if !cpp_function.is_static_member() {
                        bail!("non-static QObject::connect is blacklisted");
                    }
                    let arg = &cpp_function.arguments[1].argument_type;
                    if arg == &qmetamethod_ref_type {
                        return Ok(Some(RustPath::from_good_str(&format!(
                            "{}::QObject::connect_by_meta_methods",
                            data.current_database.crate_name()
                        ))));
                    }
                }
            }
        }
        Ok(None)
    });

    config.set_ffi_generator_hook(|item| {
        if let CppItem::Function(function) = &item.item {
            if let Ok(class_type) = function.class_type() {
                let class_text = class_type.to_templateless_string();
                if class_text == "QFlags" {
                    return Ok(false);
                }
            }
            if function.is_operator() {
                if let CppType::Class(path) = &function.return_type {
                    if path.to_templateless_string() == "QFlags" {
                        return Ok(false);
                    }
                }
            }
        }
        Ok(true)
    });

    let tests = if config.crate_properties().name().starts_with("moqt") {
        vec![PreliminaryTest::new(
            "moqt_abs",
            true,
            Snippet::new_in_main("ritual_assert(moqt_abs(-2) == 2);", false),
        )]
    } else {
        let code1 = format!(
            "ritual_assert(QLibraryInfo::version().toString() == \"{}\");",
            config.cpp_lib_version().unwrap()
        );
        let test1 = PreliminaryTest::new("qt_version_fn", true, Snippet::new_in_main(code1, false));

        let code2 = format!(
            "ritual_assert(strcmp(QT_VERSION_STR, \"{}\") == 0);",
            config.cpp_lib_version().unwrap()
        );
        let test2 = PreliminaryTest::new(
            "qt_version_define",
            true,
            Snippet::new_in_main(code2, false),
        );
        let code3 = "
            class Class1 : public QObject {
            Q_OBJECT
            public:
                Class1() {
                    emit signal1();
                }
            signals:
                void signal1();
            };

            void x() {
                Class1 c;
            }
        ";
        let test3 =
            PreliminaryTest::new("class_with_signal", true, Snippet::new_global(code3, true));

        vec![test1, test2, test3]
    };
    config.add_cpp_checker_tests(tests);
    Ok(())
}
<|endoftext|>


<commit_before>#[cfg(feature = "smoltcp")]
pub mod uhyve;

use crossbeam_channel::{Receiver, Sender};
use std::arch::x86_64::_rdtsc;
use std::collections::BTreeMap;
use std::str::FromStr;
use std::sync::atomic::{AtomicU16, Ordering};
use std::sync::Mutex;
use std::u16;

use smoltcp::phy::Device;
use smoltcp::socket::{SocketHandle, SocketSet, TcpSocket, TcpSocketBuffer, TcpState};
use smoltcp::time::Instant;
use smoltcp::wire::IpAddress;

use net::uhyve::UhyveNet;

lazy_static! {
	static ref NIC: Mutex<Option<NetworkInterface<UhyveNet>>> =
		Mutex::new(NetworkInterface::<UhyveNet>::new());
}

extern "Rust" {
	fn uhyve_netwakeup();
	fn uhyve_netwait(millis: Option<u64>);
}

extern "C" {
	fn sys_yield();
	fn sys_spawn(
		id: *mut Tid,
		func: extern "C" fn(usize),
		arg: usize,
		prio: u8,
		selector: isize,
	) -> i32;
}

pub type Handle = SocketHandle;
pub type Tid = u32;

static LOCAL_ENDPOINT: AtomicU16 = AtomicU16::new(0);

#[derive(Debug, PartialEq, Eq)]
pub enum WriteFailed {
	CanSendFailed,
	InternalError,
}

#[derive(Debug, PartialEq, Eq)]
pub enum ReadFailed {
	CanRecvFailed,
	InternalError,
}

#[derive(Debug, PartialEq, Eq)]
pub enum WaitFor {
	Establish,
	Read,
	Write,
	Close,
}

#[derive(Debug, PartialEq, Eq)]
pub enum WaitForResult {
	Ok,
	Failed,
}

pub struct NetworkInterface<T: for<'a> Device<'a>> {
	pub iface: smoltcp::iface::EthernetInterface<'static, 'static, 'static, T>,
	pub sockets: SocketSet<'static, 'static, 'static>,
	pub channels: BTreeMap<Handle, (WaitFor, Sender<WaitForResult>, bool)>,
	pub timestamp: Instant,
}

impl<T> NetworkInterface<T>
where
	T: for<'a> Device<'a>,
{
	pub fn poll(&mut self) -> Option<u64> {
		self.iface
			.poll(&mut self.sockets, self.timestamp)
			.map(|_| {
				trace!("receive message {}", self.counter);
				self.counter += 1;
			})
			.unwrap_or_else(|e| debug!("Poll: {:?}", e));

		// check if we have to inform a thread, which waits for input
		for (handle, (wait, tx, complete)) in self.channels.iter_mut() {
			let socket = self.sockets.get::<TcpSocket>(*handle);

			if !*complete {
				match wait {
					// a thread is trying to establish a connection
					WaitFor::Establish => match socket.state() {
						TcpState::Established => {
							if tx.try_send(WaitForResult::Ok).is_ok() {
								*complete = true;
							}
						}
						TcpState::FinWait1
						| TcpState::FinWait2
						| TcpState::Closing
						| TcpState::TimeWait
						| TcpState::LastAck
						| TcpState::Closed => {
							if tx.try_send(WaitForResult::Failed).is_ok() {
								*complete = true;
							}
						}
						_ => {}
					},
					// a thread wants to read data
					WaitFor::Read => {
						if socket.can_recv() {
							if tx.try_send(WaitForResult::Ok).is_ok() {
								*complete = true;
							}
						} else if !socket.may_recv() {
							if tx.try_send(WaitForResult::Failed).is_ok() {
								*complete = true;
							}
						}
					}
					// a thread wants to write data
					WaitFor::Write => {
						if socket.can_send() {
							if tx.try_send(WaitForResult::Ok).is_ok() {
								*complete = true;
							}
						}
					}
					// a thread is waiting for acknowledge
					WaitFor::Close => match socket.state() {
						TcpState::Closed | TcpState::TimeWait => {
							if tx.try_send(WaitForResult::Ok).is_ok() {
								*complete = true;
							}
						}
						_ => {}
					},
				}
			}
		}

		self.iface
			.poll_delay(&self.sockets, self.timestamp)
			.map(|s| if s.millis() == 0 { 1 } else { s.millis() })
	}

	pub fn connect(&mut self, ip: &[u8], port: u16) -> Result<Handle, ()> {
		let tcp_rx_buffer = TcpSocketBuffer::new(vec![0; 65535]);
		let tcp_tx_buffer = TcpSocketBuffer::new(vec![0; 65535]);
		let tcp_socket = TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer);
		let tcp_handle = self.sockets.add(tcp_socket);
		let address =
			IpAddress::from_str(std::str::from_utf8(ip).map_err(|_| ())?).map_err(|_| ())?;

		// request a connection
		let mut socket = self.sockets.get::<TcpSocket>(tcp_handle);
		socket
			.connect(
				(address, port),
				LOCAL_ENDPOINT.fetch_add(1, Ordering::SeqCst),
			)
			.map_err(|_| ())?;

		Ok(tcp_handle)
	}

	pub fn close(&mut self, handle: Handle) -> Result<(), ()> {
		let mut socket = self.sockets.get::<TcpSocket>(handle);
		socket.close();

		Ok(())
	}

	pub fn read(&mut self, handle: Handle, buffer: &mut [u8]) -> Result<usize, ReadFailed> {
		let mut socket = self.sockets.get::<TcpSocket>(handle);
		if socket.can_recv() {
			let len = socket
				.recv_slice(buffer)
				.map_err(|_| ReadFailed::InternalError)?;
			trace!(
				"receive {} bytes, {}",
				len,
				std::str::from_utf8(&buffer).unwrap().to_owned()
			);
			Ok(len)
		} else {
			Err(ReadFailed::CanRecvFailed)
		}
	}

	pub fn write(&mut self, handle: Handle, buffer: &[u8]) -> Result<usize, WriteFailed> {
		let mut socket = self.sockets.get::<TcpSocket>(handle);
		if !socket.may_recv() {
			return Ok(0);
		} else if socket.can_send() {
			socket
				.send_slice(buffer)
				.map_err(|_| WriteFailed::InternalError)?;
			trace!(
				"sending {} bytes, {}",
				buffer.len(),
				std::str::from_utf8(&buffer).unwrap().to_owned()
			);
		} else {
			return Err(WriteFailed::CanSendFailed);
		}

		trace!("send {}", std::str::from_utf8(&buffer).unwrap().to_owned());

		Ok(buffer.len())
	}
}

#[no_mangle]
extern "C" fn uhyve_thread(_: usize) {
	loop {
		let delay = NIC.lock().unwrap().as_mut().unwrap().poll();

		unsafe {
			uhyve_netwait(delay);
		}
	}
}

pub fn network_init() -> Result<(), ()> {
	if !uhyve::is_network_available() {
		return Err(());
	}

	// initialize variable, which contains the next local endpoint
	let start_endpoint = ((unsafe { _rdtsc() as u64 }) % (u16::MAX as u64)) as u16;
	LOCAL_ENDPOINT.store(start_endpoint, Ordering::SeqCst);

	// create thread, which manages the network stack
	// use a higher priority to reduce the network latency
	let mut tid: Tid = 0;
	let ret = unsafe { sys_spawn(&mut tid, uhyve_thread, 0, 3, 0) };
	if ret >= 0 {
		info!("Spawn network thread with id {}", tid);
	}

	Ok(())
}

#[no_mangle]
pub fn sys_tcp_stream_connect(ip: &[u8], port: u16, timeout: Option<u64>) -> Result<Handle, ()> {
	let (tx, rx): (Sender<WaitForResult>, Receiver<WaitForResult>) = crossbeam_channel::bounded(1);
	let limit = match timeout {
		Some(t) => t,
		_ => 5000,
	};
	let handle = {
		let mut guard = NIC.lock().map_err(|_| ())?;
		let nic = guard.as_mut().ok_or(())?;
		let handle = nic.connect(ip, port)?;
		nic.channels
			.insert(handle, (WaitFor::Establish, tx.clone(), false));

		handle
	};

	unsafe {
		uhyve_netwakeup();
	}

	let result = rx
		.recv_timeout(std::time::Duration::from_millis(limit))
		.map_err(|_| ())?;
	match result {
		WaitForResult::Ok => Ok(handle),
		_ => Err(()),
	}
}

fn tcp_stream_try_read(
	handle: Handle,
	buffer: &mut [u8],
	tx: Sender<WaitForResult>,
) -> Result<usize, ReadFailed> {
	let mut guard = NIC.lock().map_err(|_| ReadFailed::InternalError)?;
	let nic = guard.as_mut().ok_or(ReadFailed::InternalError)?;

	nic.read(handle, buffer).map_err(|err| {
		match err {
			ReadFailed::CanRecvFailed => {
				*nic.channels
					.get_mut(&handle)
					.expect("Unable to find handle") = (WaitFor::Read, tx, false);
			}
			_ => {}
		}

		err
	})
}

#[no_mangle]
pub fn sys_tcp_stream_read(handle: Handle, buffer: &mut [u8]) -> Result<usize, ()> {
	let (tx, rx): (Sender<WaitForResult>, Receiver<WaitForResult>) = crossbeam_channel::bounded(1);

	loop {
		let result = tcp_stream_try_read(handle, buffer, tx.clone());

		unsafe {
			uhyve_netwakeup();
			// switch to IP thread
			sys_yield();
		}

		match result {
			Ok(len) => {
				return Ok(len);
			}
			Err(err) => {
				match err {
					ReadFailed::CanRecvFailed => {
						// wait for tx buffers and try the send operation
						if rx.recv().map_err(|_| ())? != WaitForResult::Ok {
							return Ok(0);
						}
					}
					_ => {
						return Err(());
					}
				}
			}
		}
	}
}

fn tcp_stream_try_write(
	handle: Handle,
	buffer: &[u8],
	tx: Sender<WaitForResult>,
) -> Result<usize, WriteFailed> {
	let mut guard = NIC.lock().map_err(|_| WriteFailed::InternalError)?;
	let nic = guard.as_mut().ok_or(WriteFailed::InternalError)?;

	nic.write(handle, buffer).map_err(|err| {
		match err {
			WriteFailed::CanSendFailed => {
				*nic.channels
					.get_mut(&handle)
					.expect("Unable to find handle") = (WaitFor::Write, tx, false);
			}
			_ => {}
		}

		err
	})
}

#[no_mangle]
pub fn sys_tcp_stream_write(handle: Handle, buffer: &[u8]) -> Result<usize, ()> {
	let (tx, rx): (Sender<WaitForResult>, Receiver<WaitForResult>) = crossbeam_channel::bounded(1);

	loop {
		let result = tcp_stream_try_write(handle, buffer, tx.clone());

		unsafe {
			uhyve_netwakeup();
			// switch to IP thread
			sys_yield();
		}

		match result {
			Ok(len) => {
				return Ok(len);
			}
			Err(err) => {
				match err {
					WriteFailed::CanSendFailed => {
						// wait for tx buffers and try the send operation
						if rx.recv().map_err(|_| ())? != WaitForResult::Ok {
							return Err(());
						}
					}
					_ => {
						return Err(());
					}
				}
			}
		}
	}
}

#[no_mangle]
pub fn sys_tcp_stream_close(handle: Handle) -> Result<(), ()> {
	let (tx, rx): (Sender<WaitForResult>, Receiver<WaitForResult>) = crossbeam_channel::bounded(1);
	{
		// close connection
		let mut guard = NIC.lock().map_err(|_| ())?;
		let nic = guard.as_mut().ok_or(())?;
		nic.close(handle)?;
		*nic.channels
			.get_mut(&handle)
			.expect("Unable to find handle") = (WaitFor::Close, tx.clone(), false);
	}

	unsafe {
		uhyve_netwakeup();
		// switch to IP thread
		sys_yield();
	}

	rx.recv().map_err(|_| ())?;

	Ok(())
}

#[no_mangle]
pub fn sys_tcp_stream_shutdown(handle: Handle, how: i32) -> Result<(), ()> {
	match how {
		0 /* Read */ => {
			debug!("Shutdown::Read is not implemented");
			Ok(())
		},
		1 /* Write */ => {
			sys_tcp_stream_close(handle)
		},
		2 /* Both */ => {
			sys_tcp_stream_close(handle)
		},
		_ => {
			panic!("Invalid shutdown argument {}", how);
		},
	}
}

#[no_mangle]
pub fn sys_tcp_stream_set_read_timeout(_handle: Handle, _timeout: Option<u64>) -> Result<(), ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_get_read_timeout(_handle: Handle) -> Result<Option<u64>, ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_set_write_timeout(_handle: Handle, _timeout: Option<u64>) -> Result<(), ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_get_write_timeout(_handle: Handle) -> Result<Option<u64>, ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_duplicate(_handle: Handle) -> Result<Handle, ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_peek(_handle: Handle, _buf: &mut [u8]) -> Result<usize, ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_set_nonblocking(_handle: Handle, _mode: bool) -> Result<(), ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_set_tll(_handle: Handle, _ttl: u32) -> Result<(), ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_get_tll(_handle: Handle) -> Result<u32, ()> {
	Err(())
}
<commit_msg>reduce the context switches between IP and the sender threads<commit_after>#[cfg(feature = "smoltcp")]
pub mod uhyve;

use crossbeam_channel::{Receiver, Sender};
use std::arch::x86_64::_rdtsc;
use std::collections::BTreeMap;
use std::str::FromStr;
use std::sync::atomic::{AtomicU16, Ordering};
use std::sync::Mutex;
use std::u16;

use smoltcp::phy::Device;
use smoltcp::socket::{SocketHandle, SocketSet, TcpSocket, TcpSocketBuffer, TcpState};
use smoltcp::time::Instant;
use smoltcp::wire::IpAddress;

use net::uhyve::UhyveNet;

lazy_static! {
	static ref NIC: Mutex<Option<NetworkInterface<UhyveNet>>> =
		Mutex::new(NetworkInterface::<UhyveNet>::new());
}

extern "Rust" {
	fn uhyve_netwakeup();
	fn uhyve_netwait(millis: Option<u64>);
}

extern "C" {
	fn sys_yield();
	fn sys_spawn(
		id: *mut Tid,
		func: extern "C" fn(usize),
		arg: usize,
		prio: u8,
		selector: isize,
	) -> i32;
}

pub type Handle = SocketHandle;
pub type Tid = u32;

static LOCAL_ENDPOINT: AtomicU16 = AtomicU16::new(0);

#[derive(Debug, PartialEq, Eq)]
pub enum WriteFailed {
	CanSendFailed,
	InternalError,
}

#[derive(Debug, PartialEq, Eq)]
pub enum ReadFailed {
	CanRecvFailed,
	InternalError,
}

#[derive(Debug, PartialEq, Eq)]
pub enum WaitFor {
	Establish,
	Read,
	Write,
	Close,
}

#[derive(Debug, PartialEq, Eq)]
pub enum WaitForResult {
	Ok,
	Failed,
}

pub struct NetworkInterface<T: for<'a> Device<'a>> {
	pub iface: smoltcp::iface::EthernetInterface<'static, 'static, 'static, T>,
	pub sockets: SocketSet<'static, 'static, 'static>,
	pub channels: BTreeMap<Handle, (WaitFor, Sender<WaitForResult>, bool)>,
	pub timestamp: Instant,
}

impl<T> NetworkInterface<T>
where
	T: for<'a> Device<'a>,
{
	pub fn poll(&mut self) -> Option<u64> {
		self.iface
			.poll(&mut self.sockets, self.timestamp)
			.map(|_| {
				trace!("receive message {}", self.counter);
				self.counter += 1;
			})
			.unwrap_or_else(|e| debug!("Poll: {:?}", e));

		// check if we have to inform a thread, which waits for input
		for (handle, (wait, tx, complete)) in self.channels.iter_mut() {
			let socket = self.sockets.get::<TcpSocket>(*handle);

			if !*complete {
				match wait {
					// a thread is trying to establish a connection
					WaitFor::Establish => match socket.state() {
						TcpState::Established => {
							if tx.try_send(WaitForResult::Ok).is_ok() {
								*complete = true;
							}
						}
						TcpState::FinWait1
						| TcpState::FinWait2
						| TcpState::Closing
						| TcpState::TimeWait
						| TcpState::LastAck
						| TcpState::Closed => {
							if tx.try_send(WaitForResult::Failed).is_ok() {
								*complete = true;
							}
						}
						_ => {}
					},
					// a thread wants to read data
					WaitFor::Read => {
						if socket.can_recv() {
							if tx.try_send(WaitForResult::Ok).is_ok() {
								*complete = true;
							}
						} else if !socket.may_recv() {
							if tx.try_send(WaitForResult::Failed).is_ok() {
								*complete = true;
							}
						}
					}
					// a thread wants to write data
					WaitFor::Write => {
						if socket.can_send() {
							if tx.try_send(WaitForResult::Ok).is_ok() {
								*complete = true;
							}
						}
					}
					// a thread is waiting for acknowledge
					WaitFor::Close => match socket.state() {
						TcpState::Closed | TcpState::TimeWait => {
							if tx.try_send(WaitForResult::Ok).is_ok() {
								*complete = true;
							}
						}
						_ => {}
					},
				}
			}
		}

		self.iface
			.poll_delay(&self.sockets, self.timestamp)
			.map(|s| if s.millis() == 0 { 1 } else { s.millis() })
	}

	pub fn connect(&mut self, ip: &[u8], port: u16) -> Result<Handle, ()> {
		let tcp_rx_buffer = TcpSocketBuffer::new(vec![0; 65535]);
		let tcp_tx_buffer = TcpSocketBuffer::new(vec![0; 65535]);
		let tcp_socket = TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer);
		let tcp_handle = self.sockets.add(tcp_socket);
		let address =
			IpAddress::from_str(std::str::from_utf8(ip).map_err(|_| ())?).map_err(|_| ())?;

		// request a connection
		let mut socket = self.sockets.get::<TcpSocket>(tcp_handle);
		socket
			.connect(
				(address, port),
				LOCAL_ENDPOINT.fetch_add(1, Ordering::SeqCst),
			)
			.map_err(|_| ())?;

		Ok(tcp_handle)
	}

	pub fn close(&mut self, handle: Handle) -> Result<(), ()> {
		let mut socket = self.sockets.get::<TcpSocket>(handle);
		socket.close();

		Ok(())
	}

	pub fn read(&mut self, handle: Handle, buffer: &mut [u8]) -> Result<usize, ReadFailed> {
		let mut socket = self.sockets.get::<TcpSocket>(handle);
		if socket.can_recv() {
			let len = socket
				.recv_slice(buffer)
				.map_err(|_| ReadFailed::InternalError)?;

			Ok(len)
		} else {
			Err(ReadFailed::CanRecvFailed)
		}
	}

	pub fn write(&mut self, handle: Handle, buffer: &[u8]) -> Result<usize, WriteFailed> {
		let mut socket = self.sockets.get::<TcpSocket>(handle);
		if !socket.may_recv() {
			return Ok(0);
		} else if !socket.can_send() {
			return Err(WriteFailed::CanSendFailed);
		}

		socket
			.send_slice(buffer)
			.map_err(|_| WriteFailed::InternalError)?;

		Ok(buffer.len())
	}
}

#[no_mangle]
extern "C" fn uhyve_thread(_: usize) {
	loop {
		let delay = NIC.lock().unwrap().as_mut().unwrap().poll();

		unsafe {
			uhyve_netwait(delay);
		}
	}
}

pub fn network_init() -> Result<(), ()> {
	if !uhyve::is_network_available() {
		return Err(());
	}

	// initialize variable, which contains the next local endpoint
	let start_endpoint = ((unsafe { _rdtsc() as u64 }) % (u16::MAX as u64)) as u16;
	LOCAL_ENDPOINT.store(start_endpoint, Ordering::SeqCst);

	// create thread, which manages the network stack
	// use a higher priority to reduce the network latency
	let mut tid: Tid = 0;
	let ret = unsafe { sys_spawn(&mut tid, uhyve_thread, 0, 3, 0) };
	if ret >= 0 {
		info!("Spawn network thread with id {}", tid);
	}

	Ok(())
}

#[no_mangle]
pub fn sys_tcp_stream_connect(ip: &[u8], port: u16, timeout: Option<u64>) -> Result<Handle, ()> {
	let (tx, rx): (Sender<WaitForResult>, Receiver<WaitForResult>) = crossbeam_channel::bounded(1);
	let limit = match timeout {
		Some(t) => t,
		_ => 5000,
	};
	let handle = {
		let mut guard = NIC.lock().map_err(|_| ())?;
		let nic = guard.as_mut().ok_or(())?;
		let handle = nic.connect(ip, port)?;
		nic.channels
			.insert(handle, (WaitFor::Establish, tx.clone(), false));

		handle
	};

	unsafe {
		uhyve_netwakeup();
	}

	let result = rx
		.recv_timeout(std::time::Duration::from_millis(limit))
		.map_err(|_| ())?;
	match result {
		WaitForResult::Ok => Ok(handle),
		_ => Err(()),
	}
}

fn tcp_stream_try_read(
	handle: Handle,
	buffer: &mut [u8],
	tx: Sender<WaitForResult>,
) -> Result<usize, ReadFailed> {
	let mut guard = NIC.lock().map_err(|_| ReadFailed::InternalError)?;
	let nic = guard.as_mut().ok_or(ReadFailed::InternalError)?;

	nic.read(handle, buffer).map_err(|err| {
		match err {
			ReadFailed::CanRecvFailed => {
				*nic.channels
					.get_mut(&handle)
					.expect("Unable to find handle") = (WaitFor::Read, tx, false);
			}
			_ => {}
		}

		err
	})
}

#[no_mangle]
pub fn sys_tcp_stream_read(handle: Handle, buffer: &mut [u8]) -> Result<usize, ()> {
	let (tx, rx): (Sender<WaitForResult>, Receiver<WaitForResult>) = crossbeam_channel::bounded(1);

	loop {
		let result = tcp_stream_try_read(handle, buffer, tx.clone());

		unsafe {
			uhyve_netwakeup();
			// switch to IP thread
			sys_yield();
		}

		match result {
			Ok(len) => {
				return Ok(len);
			}
			Err(err) => {
				match err {
					ReadFailed::CanRecvFailed => {
						// wait for tx buffers and try the send operation
						if rx.recv().map_err(|_| ())? != WaitForResult::Ok {
							return Ok(0);
						}
					}
					_ => {
						return Err(());
					}
				}
			}
		}
	}
}

fn tcp_stream_try_write(
	handle: Handle,
	buffer: &[u8],
	tx: Sender<WaitForResult>,
) -> Result<usize, WriteFailed> {
	let mut guard = NIC.lock().map_err(|_| WriteFailed::InternalError)?;
	let nic = guard.as_mut().ok_or(WriteFailed::InternalError)?;

	let len = nic.write(handle, buffer).map_err(|err| {
		match err {
			WriteFailed::CanSendFailed => {
				*nic.channels
					.get_mut(&handle)
					.expect("Unable to find handle") = (WaitFor::Write, tx, false);
			}
			_ => {}
		}

		err
	})?;

	// transfer packet to nic
	while let Some(delay) = nic.poll() {
		if delay > 0 {
			break;
		}
	}

	Ok(len)
}

#[no_mangle]
pub fn sys_tcp_stream_write(handle: Handle, buffer: &[u8]) -> Result<usize, ()> {
	let (tx, rx): (Sender<WaitForResult>, Receiver<WaitForResult>) = crossbeam_channel::bounded(1);

	loop {
		let result = tcp_stream_try_write(handle, buffer, tx.clone());

		match result {
			Ok(len) => {
				return Ok(len);
			}
			Err(err) => {
				match err {
					WriteFailed::CanSendFailed => {
						// wait for tx buffers and try the send operation
						if rx.recv().map_err(|_| ())? != WaitForResult::Ok {
							return Err(());
						}
					}
					_ => {
						return Err(());
					}
				}
			}
		}
	}
}

#[no_mangle]
pub fn sys_tcp_stream_close(handle: Handle) -> Result<(), ()> {
	let (tx, rx): (Sender<WaitForResult>, Receiver<WaitForResult>) = crossbeam_channel::bounded(1);
	{
		// close connection
		let mut guard = NIC.lock().map_err(|_| ())?;
		let nic = guard.as_mut().ok_or(())?;
		nic.close(handle)?;
		*nic.channels
			.get_mut(&handle)
			.expect("Unable to find handle") = (WaitFor::Close, tx.clone(), false);

		// transfer request to nic
		while let Some(delay) = nic.poll() {
			if delay > 0 {
				break;
			}
		}
	}

	rx.recv().map_err(|_| ())?;

	Ok(())
}

#[no_mangle]
pub fn sys_tcp_stream_shutdown(handle: Handle, how: i32) -> Result<(), ()> {
	match how {
		0 /* Read */ => {
			debug!("Shutdown::Read is not implemented");
			Ok(())
		},
		1 /* Write */ => {
			sys_tcp_stream_close(handle)
		},
		2 /* Both */ => {
			sys_tcp_stream_close(handle)
		},
		_ => {
			panic!("Invalid shutdown argument {}", how);
		},
	}
}

#[no_mangle]
pub fn sys_tcp_stream_set_read_timeout(_handle: Handle, _timeout: Option<u64>) -> Result<(), ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_get_read_timeout(_handle: Handle) -> Result<Option<u64>, ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_set_write_timeout(_handle: Handle, _timeout: Option<u64>) -> Result<(), ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_get_write_timeout(_handle: Handle) -> Result<Option<u64>, ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_duplicate(_handle: Handle) -> Result<Handle, ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_peek(_handle: Handle, _buf: &mut [u8]) -> Result<usize, ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_set_nonblocking(_handle: Handle, _mode: bool) -> Result<(), ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_set_tll(_handle: Handle, _ttl: u32) -> Result<(), ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_get_tll(_handle: Handle) -> Result<u32, ()> {
	Err(())
}
<|endoftext|>


<commit_before>//! Allow access to the various flavours of sass contexts:
//! https://github.com/sass/libsass/wiki/API-Sass-Context

use std::ffi;
use std::sync::{Arc, RwLock};

use sass_sys;
use bindings::util;
use bindings::ptr::Unique;
use options::{OutputStyle, Options};
use bindings::SassOptions;

pub struct SassContext {
    // Need Unique to send between threads, libsass is thread safe
    pub raw: Unique<sass_sys::Sass_Context>,
    pub options: Arc<RwLock<SassOptions>>
}

pub struct SassFileContext {
    // Need Unique to send between threads, libsass is thread safe
    context: Unique<sass_sys::Sass_File_Context>,
    pub sass_context: SassContext
}

pub struct SassDataContext {
    // Need Unique to send between threads, libsass is thread safe
    context: Unique<sass_sys::Sass_Data_Context>,
    pub sass_context: SassContext
}

pub enum Context {
    File(SassFileContext),
    Data(SassDataContext),
}

impl Context {
    fn make_sass_context(c_sass_context: *mut sass_sys::Sass_Context) -> SassContext {;
        let options = unsafe { sass_sys::sass_context_get_options(c_sass_context) };
        let sass_options = Arc::new(RwLock::new(SassOptions {
            raw: unsafe { Unique::new(options) }
        }));

        SassContext {
            raw: unsafe { Unique::new(c_sass_context) },
            options: sass_options
        }
    }

    pub fn new_data(data: &str) -> Context {
        let c_str = ffi::CString::new(data).unwrap();
        let data_context = unsafe { sass_sys::sass_make_data_context(c_str.into_raw()) };
        let data_sass_context = unsafe { sass_sys::sass_data_context_get_context(data_context) };
        let sass_context = Context::make_sass_context(data_sass_context);

        Context::Data(SassDataContext {
            context: unsafe { Unique::new(data_context) },
            sass_context,
        })
    }

    pub fn new_file(path: &str) -> Context {
        let c_str = ffi::CString::new(path).unwrap();
        let file_context = unsafe { sass_sys::sass_make_file_context(c_str.as_ptr()) };
        let file_sass_context = unsafe { sass_sys::sass_file_context_get_context(file_context) };
        let sass_context = Context::make_sass_context(file_sass_context);

        Context::File(SassFileContext {
            context: unsafe { Unique::new(file_context) },
            sass_context,
        })
    }

    pub fn set_options(&mut self, options: Options) {
        let mut sass_options = match *self {
            Context::File(ref mut s) => {
                (*s.sass_context.options).write().unwrap()
            },
            Context::Data(ref mut s) => {
                (*s.sass_context.options).write().unwrap()
            },
        };
        sass_options.set_output_style(options.output_style);
        sass_options.set_precision(options.precision);
        if options.indented_syntax {
            sass_options.set_is_indented_syntax();
        }
        if !options.include_paths.is_empty() {
            sass_options.set_include_path(options.include_paths);
        }
    }

    pub fn compile(&mut self) -> Result<String, String> {
        let ctx_out = match *self {
            Context::File(ref mut s) => unsafe {
                sass_sys::sass_compile_file_context(s.context.get_mut());
                s.sass_context.raw.get_mut()
            },
            Context::Data(ref mut s) => unsafe {
                sass_sys::sass_compile_data_context(s.context.get_mut());
                s.sass_context.raw.get_mut()
            },
        };

        let error_status = unsafe { sass_sys::sass_context_get_error_status(ctx_out) };
        let error_message = unsafe { sass_sys::sass_context_get_error_message(ctx_out) };
        let output_string = unsafe { sass_sys::sass_context_get_output_string(ctx_out) };

        if error_status != 0 {
            if !error_message.is_null() {
                Result::Err(util::to_string(error_message))
            } else {
                Result::Err("An error occurred; no error message available.".to_string())
            }
        } else {
            Result::Ok(util::to_string(output_string))
        }
    }

    pub fn set_output_style(&mut self, output_style: OutputStyle) {
        match *self {
            Context::File(ref mut s) => {
                let mut options = (*s.sass_context.options).write().unwrap();
                options.set_output_style(output_style);
            },
            Context::Data(ref mut s) => {
                let mut options = (*s.sass_context.options).write().unwrap();
                options.set_output_style(output_style);
            },
        };
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        match *self {
            Context::File(ref mut s) => unsafe {
                sass_sys::sass_delete_file_context(s.context.get_mut())
            },
            Context::Data(ref mut s) => unsafe {
                sass_sys::sass_delete_data_context(s.context.get_mut())
            },
        };
    }
}
<commit_msg>use strdup because sass_make_data_context frees its input<commit_after>//! Allow access to the various flavours of sass contexts:
//! https://github.com/sass/libsass/wiki/API-Sass-Context

use std::ffi;
use std::sync::{Arc, RwLock};
use libc::strdup;

use sass_sys;
use bindings::util;
use bindings::ptr::Unique;
use options::{OutputStyle, Options};
use bindings::SassOptions;

pub struct SassContext {
    // Need Unique to send between threads, libsass is thread safe
    pub raw: Unique<sass_sys::Sass_Context>,
    pub options: Arc<RwLock<SassOptions>>
}

pub struct SassFileContext {
    // Need Unique to send between threads, libsass is thread safe
    context: Unique<sass_sys::Sass_File_Context>,
    pub sass_context: SassContext
}

pub struct SassDataContext {
    // Need Unique to send between threads, libsass is thread safe
    context: Unique<sass_sys::Sass_Data_Context>,
    pub sass_context: SassContext
}

pub enum Context {
    File(SassFileContext),
    Data(SassDataContext),
}

impl Context {
    fn make_sass_context(c_sass_context: *mut sass_sys::Sass_Context) -> SassContext {;
        let options = unsafe { sass_sys::sass_context_get_options(c_sass_context) };
        let sass_options = Arc::new(RwLock::new(SassOptions {
            raw: unsafe { Unique::new(options) }
        }));

        SassContext {
            raw: unsafe { Unique::new(c_sass_context) },
            options: sass_options
        }
    }

    pub fn new_data(data: &str) -> Context {
        let c_str = ffi::CString::new(data).unwrap();
        let data_context = unsafe { sass_sys::sass_make_data_context(strdup(c_str.as_ptr())) };
        let data_sass_context = unsafe { sass_sys::sass_data_context_get_context(data_context) };
        let sass_context = Context::make_sass_context(data_sass_context);

        Context::Data(SassDataContext {
            context: unsafe { Unique::new(data_context) },
            sass_context,
        })
    }

    pub fn new_file(path: &str) -> Context {
        let c_str = ffi::CString::new(path).unwrap();
        let file_context = unsafe { sass_sys::sass_make_file_context(c_str.as_ptr()) };
        let file_sass_context = unsafe { sass_sys::sass_file_context_get_context(file_context) };
        let sass_context = Context::make_sass_context(file_sass_context);

        Context::File(SassFileContext {
            context: unsafe { Unique::new(file_context) },
            sass_context,
        })
    }

    pub fn set_options(&mut self, options: Options) {
        let mut sass_options = match *self {
            Context::File(ref mut s) => {
                (*s.sass_context.options).write().unwrap()
            },
            Context::Data(ref mut s) => {
                (*s.sass_context.options).write().unwrap()
            },
        };
        sass_options.set_output_style(options.output_style);
        sass_options.set_precision(options.precision);
        if options.indented_syntax {
            sass_options.set_is_indented_syntax();
        }
        if !options.include_paths.is_empty() {
            sass_options.set_include_path(options.include_paths);
        }
    }

    pub fn compile(&mut self) -> Result<String, String> {
        let ctx_out = match *self {
            Context::File(ref mut s) => unsafe {
                sass_sys::sass_compile_file_context(s.context.get_mut());
                s.sass_context.raw.get_mut()
            },
            Context::Data(ref mut s) => unsafe {
                sass_sys::sass_compile_data_context(s.context.get_mut());
                s.sass_context.raw.get_mut()
            },
        };

        let error_status = unsafe { sass_sys::sass_context_get_error_status(ctx_out) };
        let error_message = unsafe { sass_sys::sass_context_get_error_message(ctx_out) };
        let output_string = unsafe { sass_sys::sass_context_get_output_string(ctx_out) };

        if error_status != 0 {
            if !error_message.is_null() {
                Result::Err(util::to_string(error_message))
            } else {
                Result::Err("An error occurred; no error message available.".to_string())
            }
        } else {
            Result::Ok(util::to_string(output_string))
        }
    }

    pub fn set_output_style(&mut self, output_style: OutputStyle) {
        match *self {
            Context::File(ref mut s) => {
                let mut options = (*s.sass_context.options).write().unwrap();
                options.set_output_style(output_style);
            },
            Context::Data(ref mut s) => {
                let mut options = (*s.sass_context.options).write().unwrap();
                options.set_output_style(output_style);
            },
        };
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        match *self {
            Context::File(ref mut s) => unsafe {
                sass_sys::sass_delete_file_context(s.context.get_mut())
            },
            Context::Data(ref mut s) => unsafe {
                sass_sys::sass_delete_data_context(s.context.get_mut())
            },
        };
    }
}
<|endoftext|>