<commit_before>/// The Toml Read extensions

#[cfg(feature = "typed")]
use std::fmt::Debug;

#[cfg(feature = "typed")]
use serde::{Deserialize, Serialize};
use toml::Value;

use crate::error::{Error, Result};
use crate::tokenizer::tokenize_with_seperator;

pub trait TomlValueReadExt<'doc> {
    /// Extension function for reading a value from the current toml::Value document
    /// using a custom seperator
    fn read_with_seperator(&'doc self, query: &str, sep: char) -> Result<Option<&'doc Value>>;

    /// Extension function for reading a value from the current toml::Value document mutably
    /// using a custom seperator
    fn read_mut_with_seperator(
        &'doc mut self,
        query: &str,
        sep: char,
    ) -> Result<Option<&'doc mut Value>>;

    /// Extension function for reading a value from the current toml::Value document
    fn read(&'doc self, query: &str) -> Result<Option<&'doc Value>> {
        self.read_with_seperator(query, '.')
    }

    /// Extension function for reading a value from the current toml::Value document mutably
    fn read_mut(&'doc mut self, query: &str) -> Result<Option<&'doc mut Value>> {
        self.read_mut_with_seperator(query, '.')
    }

    #[cfg(feature = "typed")]
    fn read_deserialized<'de, D: Deserialize<'de>>(&'doc self, query: &str) -> Result<Option<D>> {
        let raw = self.read(query)?;

        match raw {
            Some(value) => {
                let deserialized = value.clone().try_into().map_err(Error::TomlDeserialize)?;
                Ok(Some(deserialized))
            }
            None => Ok(None),
        }
    }

    #[cfg(feature = "typed")]
    fn read_partial<'a, P: Partial<'a>>(&'doc self) -> Result<Option<P::Output>> {
        self.read_deserialized::<P::Output>(P::LOCATION)
    }
}

/// Describes a _part_ of a document
#[cfg(feature = "typed")]
pub trait Partial<'a> {
    // The location ("section") of the header where to find the struct
    const LOCATION: &'static str;

    // The type which represents the data
    type Output: Serialize + Deserialize<'a> + Debug;
}

impl<'doc> TomlValueReadExt<'doc> for Value {
    fn read_with_seperator(&'doc self, query: &str, sep: char) -> Result<Option<&'doc Value>> {
        use crate::resolver::non_mut_resolver::resolve;

        tokenize_with_seperator(query, sep).and_then(move |tokens| resolve(self, &tokens, false))
    }

    fn read_mut_with_seperator(
        &'doc mut self,
        query: &str,
        sep: char,
    ) -> Result<Option<&'doc mut Value>> {
        use crate::resolver::mut_resolver::resolve;

        tokenize_with_seperator(query, sep).and_then(move |tokens| resolve(self, &tokens, false))
    }
}

pub trait TomlValueReadTypeExt<'doc>: TomlValueReadExt<'doc> {
    fn read_string(&'doc self, query: &str) -> Result<Option<String>>;
    fn read_int(&'doc self, query: &str) -> Result<Option<i64>>;
    fn read_float(&'doc self, query: &str) -> Result<Option<f64>>;
    fn read_bool(&'doc self, query: &str) -> Result<Option<bool>>;
}

macro_rules! make_type_getter {
    ($fnname:ident, $rettype:ty, $typename:expr, $matcher:pat => $implementation:expr) => {
        fn $fnname(&'doc self, query: &str) -> Result<Option<$rettype>> {
            self.read_with_seperator(query, '.').and_then(|o| match o {
                $matcher => Ok(Some($implementation)),
                Some(o)  => Err(Error::TypeError($typename, crate::util::name_of_val(&o)).into()),
                None     => Ok(None),
            })
        }
    };
}

impl<'doc, T> TomlValueReadTypeExt<'doc> for T
where
    T: TomlValueReadExt<'doc>,
{
    make_type_getter!(read_string, String, "String", Some(&Value::String(ref obj)) => obj.clone());
    make_type_getter!(read_int, i64, "Integer", Some(&Value::Integer(obj)) => obj);
    make_type_getter!(read_float, f64, "Float", Some(&Value::Float(obj)) => obj);
    make_type_getter!(read_bool, bool, "Boolean", Some(&Value::Boolean(obj)) => obj);
}

#[cfg(test)]
mod test {
    use super::*;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_read_empty() {
        let toml: Value = toml_from_str("").unwrap();

        let val = toml.read_with_seperator(&String::from("a"), '.');

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        "#,
        )
        .unwrap();

        let val = toml.read_with_seperator(&String::from("table"), '.');

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Table(_)));
        match val {
            Value::Table(ref t) => assert!(t.is_empty()),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_read_table_value() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        a = 1
        "#,
        )
        .unwrap();

        let val = toml.read_with_seperator(&String::from("table.a"), '.');

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Integer(1)));
    }

    #[test]
    fn test_read_empty_table_value() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        "#,
        )
        .unwrap();

        let val = toml.read_with_seperator(&String::from("table.a"), '.');
        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table_index() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        "#,
        )
        .unwrap();

        let val = toml.read_with_seperator(&String::from("table.[0]"), '.');
        assert!(val.is_err());
        let err = val.unwrap_err();

        assert!(is_match!(err, Error::NoIndexInTable(_)));
    }

    ///
    ///
    /// Querying without specifying the seperator
    ///
    ///

    #[test]
    fn test_read_empty_without_seperator() {
        let toml: Value = toml_from_str("").unwrap();

        let val = toml.read(&String::from("a"));
        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table_without_seperator() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        "#,
        )
        .unwrap();

        let val = toml.read(&String::from("table"));

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Table(_)));
        match val {
            Value::Table(ref t) => assert!(t.is_empty()),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_read_table_value_without_seperator() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        a = 1
        "#,
        )
        .unwrap();

        let val = toml.read(&String::from("table.a"));

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Integer(1)));
    }

    #[test]
    fn test_read_empty_table_value_without_seperator() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        "#,
        )
        .unwrap();

        let val = toml.read(&String::from("table.a"));
        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table_index_without_seperator() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        "#,
        )
        .unwrap();

        let val = toml.read(&String::from("table.[0]"));
        assert!(val.is_err());
        let err = val.unwrap_err();

        assert!(is_match!(err, Error::NoIndexInTable(_)));
    }
}

#[cfg(test)]
mod high_level_fn_test {
    use super::*;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_read_table_value() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        a = 1
        "#,
        )
        .unwrap();

        let val = toml.read_int("table.a").unwrap();

        assert_eq!(val.unwrap(), 1);
    }

    #[cfg(feature = "typed")]
    #[test]
    fn test_name() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        a = 1
        "#,
        )
        .unwrap();

        let val: u32 = toml.read_deserialized("table.a").unwrap().unwrap();

        assert_eq!(val, 1);
    }

    #[cfg(feature = "typed")]
    #[test]
    fn test_deser() {
        use crate::insert::TomlValueInsertExt;
        use crate::read::TomlValueReadExt;
        use toml::map::Map;

        #[derive(Serialize, Deserialize, Debug)]
        struct Test {
            a: u64,
            s: String,
        }

        let mut toml = Value::Table(Map::new());
        let test = Test {
            a: 15,
            s: String::from("Helloworld"),
        };

        assert!(toml
            .insert_serialized("table.value", test)
            .unwrap()
            .is_none());
        let _: Test = toml.read_deserialized("table.value").unwrap().unwrap();

        assert!(true);
    }
}

#[cfg(all(test, feature = "typed"))]
mod partial_tests {
    use super::*;

    use toml::map::Map;
    use toml::Value;

    #[derive(Debug, Deserialize, Serialize)]
    struct TestObj {
        pub value: String,
    }

    impl<'a> Partial<'a> for TestObj {
        const LOCATION: &'static str = "foo";
        type Output = Self;
    }

    #[test]
    fn test_compiles() {
        let tbl = {
            let mut tbl = Map::new();
            tbl.insert(String::from("foo"), {
                let mut tbl = Map::new();
                tbl.insert(String::from("value"), Value::String(String::from("foobar")));
                Value::Table(tbl)
            });
            Value::Table(tbl)
        };

        let obj: TestObj = tbl.read_partial::<TestObj>().unwrap().unwrap();
        assert_eq!(obj.value, "foobar");
    }
}
<commit_msg>Fix: Remove statement that will be optimized out by the compiler<commit_after>/// The Toml Read extensions

#[cfg(feature = "typed")]
use std::fmt::Debug;

#[cfg(feature = "typed")]
use serde::{Deserialize, Serialize};
use toml::Value;

use crate::error::{Error, Result};
use crate::tokenizer::tokenize_with_seperator;

pub trait TomlValueReadExt<'doc> {
    /// Extension function for reading a value from the current toml::Value document
    /// using a custom seperator
    fn read_with_seperator(&'doc self, query: &str, sep: char) -> Result<Option<&'doc Value>>;

    /// Extension function for reading a value from the current toml::Value document mutably
    /// using a custom seperator
    fn read_mut_with_seperator(
        &'doc mut self,
        query: &str,
        sep: char,
    ) -> Result<Option<&'doc mut Value>>;

    /// Extension function for reading a value from the current toml::Value document
    fn read(&'doc self, query: &str) -> Result<Option<&'doc Value>> {
        self.read_with_seperator(query, '.')
    }

    /// Extension function for reading a value from the current toml::Value document mutably
    fn read_mut(&'doc mut self, query: &str) -> Result<Option<&'doc mut Value>> {
        self.read_mut_with_seperator(query, '.')
    }

    #[cfg(feature = "typed")]
    fn read_deserialized<'de, D: Deserialize<'de>>(&'doc self, query: &str) -> Result<Option<D>> {
        let raw = self.read(query)?;

        match raw {
            Some(value) => {
                let deserialized = value.clone().try_into().map_err(Error::TomlDeserialize)?;
                Ok(Some(deserialized))
            }
            None => Ok(None),
        }
    }

    #[cfg(feature = "typed")]
    fn read_partial<'a, P: Partial<'a>>(&'doc self) -> Result<Option<P::Output>> {
        self.read_deserialized::<P::Output>(P::LOCATION)
    }
}

/// Describes a _part_ of a document
#[cfg(feature = "typed")]
pub trait Partial<'a> {
    // The location ("section") of the header where to find the struct
    const LOCATION: &'static str;

    // The type which represents the data
    type Output: Serialize + Deserialize<'a> + Debug;
}

impl<'doc> TomlValueReadExt<'doc> for Value {
    fn read_with_seperator(&'doc self, query: &str, sep: char) -> Result<Option<&'doc Value>> {
        use crate::resolver::non_mut_resolver::resolve;

        tokenize_with_seperator(query, sep).and_then(move |tokens| resolve(self, &tokens, false))
    }

    fn read_mut_with_seperator(
        &'doc mut self,
        query: &str,
        sep: char,
    ) -> Result<Option<&'doc mut Value>> {
        use crate::resolver::mut_resolver::resolve;

        tokenize_with_seperator(query, sep).and_then(move |tokens| resolve(self, &tokens, false))
    }
}

pub trait TomlValueReadTypeExt<'doc>: TomlValueReadExt<'doc> {
    fn read_string(&'doc self, query: &str) -> Result<Option<String>>;
    fn read_int(&'doc self, query: &str) -> Result<Option<i64>>;
    fn read_float(&'doc self, query: &str) -> Result<Option<f64>>;
    fn read_bool(&'doc self, query: &str) -> Result<Option<bool>>;
}

macro_rules! make_type_getter {
    ($fnname:ident, $rettype:ty, $typename:expr, $matcher:pat => $implementation:expr) => {
        fn $fnname(&'doc self, query: &str) -> Result<Option<$rettype>> {
            self.read_with_seperator(query, '.').and_then(|o| match o {
                $matcher => Ok(Some($implementation)),
                Some(o)  => Err(Error::TypeError($typename, crate::util::name_of_val(&o)).into()),
                None     => Ok(None),
            })
        }
    };
}

impl<'doc, T> TomlValueReadTypeExt<'doc> for T
where
    T: TomlValueReadExt<'doc>,
{
    make_type_getter!(read_string, String, "String", Some(&Value::String(ref obj)) => obj.clone());
    make_type_getter!(read_int, i64, "Integer", Some(&Value::Integer(obj)) => obj);
    make_type_getter!(read_float, f64, "Float", Some(&Value::Float(obj)) => obj);
    make_type_getter!(read_bool, bool, "Boolean", Some(&Value::Boolean(obj)) => obj);
}

#[cfg(test)]
mod test {
    use super::*;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_read_empty() {
        let toml: Value = toml_from_str("").unwrap();

        let val = toml.read_with_seperator(&String::from("a"), '.');

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        "#,
        )
        .unwrap();

        let val = toml.read_with_seperator(&String::from("table"), '.');

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Table(_)));
        match val {
            Value::Table(ref t) => assert!(t.is_empty()),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_read_table_value() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        a = 1
        "#,
        )
        .unwrap();

        let val = toml.read_with_seperator(&String::from("table.a"), '.');

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Integer(1)));
    }

    #[test]
    fn test_read_empty_table_value() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        "#,
        )
        .unwrap();

        let val = toml.read_with_seperator(&String::from("table.a"), '.');
        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table_index() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        "#,
        )
        .unwrap();

        let val = toml.read_with_seperator(&String::from("table.[0]"), '.');
        assert!(val.is_err());
        let err = val.unwrap_err();

        assert!(is_match!(err, Error::NoIndexInTable(_)));
    }

    ///
    ///
    /// Querying without specifying the seperator
    ///
    ///

    #[test]
    fn test_read_empty_without_seperator() {
        let toml: Value = toml_from_str("").unwrap();

        let val = toml.read(&String::from("a"));
        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table_without_seperator() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        "#,
        )
        .unwrap();

        let val = toml.read(&String::from("table"));

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Table(_)));
        match val {
            Value::Table(ref t) => assert!(t.is_empty()),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_read_table_value_without_seperator() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        a = 1
        "#,
        )
        .unwrap();

        let val = toml.read(&String::from("table.a"));

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Integer(1)));
    }

    #[test]
    fn test_read_empty_table_value_without_seperator() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        "#,
        )
        .unwrap();

        let val = toml.read(&String::from("table.a"));
        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table_index_without_seperator() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        "#,
        )
        .unwrap();

        let val = toml.read(&String::from("table.[0]"));
        assert!(val.is_err());
        let err = val.unwrap_err();

        assert!(is_match!(err, Error::NoIndexInTable(_)));
    }
}

#[cfg(test)]
mod high_level_fn_test {
    use super::*;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_read_table_value() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        a = 1
        "#,
        )
        .unwrap();

        let val = toml.read_int("table.a").unwrap();

        assert_eq!(val.unwrap(), 1);
    }

    #[cfg(feature = "typed")]
    #[test]
    fn test_name() {
        let toml: Value = toml_from_str(
            r#"
        [table]
        a = 1
        "#,
        )
        .unwrap();

        let val: u32 = toml.read_deserialized("table.a").unwrap().unwrap();

        assert_eq!(val, 1);
    }

    #[cfg(feature = "typed")]
    #[test]
    fn test_deser() {
        use crate::insert::TomlValueInsertExt;
        use crate::read::TomlValueReadExt;
        use toml::map::Map;

        #[derive(Serialize, Deserialize, Debug)]
        struct Test {
            a: u64,
            s: String,
        }

        let mut toml = Value::Table(Map::new());
        let test = Test {
            a: 15,
            s: String::from("Helloworld"),
        };

        assert!(toml
            .insert_serialized("table.value", test)
            .unwrap()
            .is_none());
        let _: Test = toml.read_deserialized("table.value").unwrap().unwrap();
    }
}

#[cfg(all(test, feature = "typed"))]
mod partial_tests {
    use super::*;

    use toml::map::Map;
    use toml::Value;

    #[derive(Debug, Deserialize, Serialize)]
    struct TestObj {
        pub value: String,
    }

    impl<'a> Partial<'a> for TestObj {
        const LOCATION: &'static str = "foo";
        type Output = Self;
    }

    #[test]
    fn test_compiles() {
        let tbl = {
            let mut tbl = Map::new();
            tbl.insert(String::from("foo"), {
                let mut tbl = Map::new();
                tbl.insert(String::from("value"), Value::String(String::from("foobar")));
                Value::Table(tbl)
            });
            Value::Table(tbl)
        };

        let obj: TestObj = tbl.read_partial::<TestObj>().unwrap().unwrap();
        assert_eq!(obj.value, "foobar");
    }
}
<|endoftext|>


<commit_before>use std::cast;
use std::libc::c_int;
use std::ptr;
use std::vec;

#[deriving(Eq)]
pub struct Point{
    x: i32,
    y: i32
}

#[deriving(Eq)]
pub struct Rect {
    x: i32,
    y: i32,
    w: i32,
    h: i32
}

pub mod ll {

    use std::libc::{c_int};
    use rect::Rect;
    use rect::Point;

    pub type SDL_Rect = Rect;
    pub type SDL_Point = Point;
    pub type SDL_bool = c_int;

    externfn!(fn SDL_HasIntersection(A: *SDL_Rect, B: *SDL_Rect) -> SDL_bool)
    externfn!(fn SDL_IntersectRect(A: *SDL_Rect, B: *SDL_Rect, result: *SDL_Rect) -> SDL_bool)
    externfn!(fn SDL_UnionRect(A: *SDL_Rect, B: *SDL_Rect, result: *SDL_Rect))
    externfn!(fn SDL_EnclosePoints(points: *SDL_Point, count: c_int, clip: *SDL_Rect, result: *SDL_Rect) -> SDL_bool)
    externfn!(fn SDL_IntersectRectAndLine(rect: *SDL_Rect, X1: *c_int, Y1: *c_int, X2: *c_int, Y2: *c_int) -> SDL_bool)
}

pub fn Point(x: i32, y: i32) -> Point {
    Point { x: x, y: y }
}

impl Point {
    pub fn new(x: i32, y: i32) -> Point {
        Point {
            x: x,
            y: y
        }
    }
}

pub fn Rect(x: i32, y: i32, w: i32, h: i32) -> Rect {
    Rect { x: x, y: y, w: w, h: h }
}

impl Rect {
    pub fn new(x: i32, y: i32, w: i32, h: i32) -> Rect {
        Rect {
            x: x,
            y: y,
            w: w,
            h: h
        }
    }

    pub fn enclose_points(points: &[Point], clip: Option<Rect>) -> Option<Rect> {
        let out: Rect = Rect::new(0, 0, 0, 0);

        let result = unsafe {
            ll::SDL_EnclosePoints(
                cast::transmute(vec::raw::to_ptr(points)),
                points.len() as c_int,
                match clip { Some(ref rect) => cast::transmute(rect), None => ptr::null() },
                &out
            ) == 0
        };

        if result {
            Some(out)
        } else {
            None
        }
    }

    pub fn empty(&self) -> bool {
        (self.w <= 0) || (self.h <= 0)
    }

    pub fn has_intersection(&self, other: &Rect) -> bool {
        unsafe {
            ll::SDL_HasIntersection(self, other) == 0
        }
    }

    pub fn intersection(&self, other: &Rect) -> Option<Rect> {
        let out: Rect = Rect::new(0, 0, 0, 0);

        let result = unsafe {
            ll::SDL_IntersectRect(self, other, &out) == 0
        };

        if result {
            Some(out)
        } else {
            None
        }
    }

    pub fn union(&self, other: &Rect) -> Rect {
        let out: Rect = Rect::new(0, 0, 0, 0);

        unsafe {
            ll::SDL_UnionRect(self, other, &out)
        };

        out
    }

    pub fn intersect_line(&self, start: &Point, end: &Point) -> Option<(Point, Point)> {
        let out_start: Point = *start.clone();
        let out_end: Point = *end.clone();

        let result = unsafe {
            ll::SDL_IntersectRectAndLine(self, &out_start.x, &out_start.y, &out_end.x, &out_end.y) == 0
        };

        if result {
            Some((out_start, out_end))
        } else {
            None
        }
    }
}
<commit_msg>Rects and Points can now be cloned<commit_after>use std::cast;
use std::libc::c_int;
use std::ptr;
use std::vec;

#[deriving(Eq)]
#[deriving(Clone)]
pub struct Point{
    x: i32,
    y: i32
}

#[deriving(Eq)]
#[deriving(Clone)]
pub struct Rect {
    x: i32,
    y: i32,
    w: i32,
    h: i32
}

pub mod ll {

    use std::libc::{c_int};
    use rect::Rect;
    use rect::Point;

    pub type SDL_Rect = Rect;
    pub type SDL_Point = Point;
    pub type SDL_bool = c_int;

    externfn!(fn SDL_HasIntersection(A: *SDL_Rect, B: *SDL_Rect) -> SDL_bool)
    externfn!(fn SDL_IntersectRect(A: *SDL_Rect, B: *SDL_Rect, result: *SDL_Rect) -> SDL_bool)
    externfn!(fn SDL_UnionRect(A: *SDL_Rect, B: *SDL_Rect, result: *SDL_Rect))
    externfn!(fn SDL_EnclosePoints(points: *SDL_Point, count: c_int, clip: *SDL_Rect, result: *SDL_Rect) -> SDL_bool)
    externfn!(fn SDL_IntersectRectAndLine(rect: *SDL_Rect, X1: *c_int, Y1: *c_int, X2: *c_int, Y2: *c_int) -> SDL_bool)
}

pub fn Point(x: i32, y: i32) -> Point {
    Point { x: x, y: y }
}

impl Point {
    pub fn new(x: i32, y: i32) -> Point {
        Point {
            x: x,
            y: y
        }
    }
}

pub fn Rect(x: i32, y: i32, w: i32, h: i32) -> Rect {
    Rect { x: x, y: y, w: w, h: h }
}

impl Rect {
    pub fn new(x: i32, y: i32, w: i32, h: i32) -> Rect {
        Rect {
            x: x,
            y: y,
            w: w,
            h: h
        }
    }

    pub fn enclose_points(points: &[Point], clip: Option<Rect>) -> Option<Rect> {
        let out: Rect = Rect::new(0, 0, 0, 0);

        let result = unsafe {
            ll::SDL_EnclosePoints(
                cast::transmute(vec::raw::to_ptr(points)),
                points.len() as c_int,
                match clip { Some(ref rect) => cast::transmute(rect), None => ptr::null() },
                &out
            ) == 0
        };

        if result {
            Some(out)
        } else {
            None
        }
    }

    pub fn empty(&self) -> bool {
        (self.w <= 0) || (self.h <= 0)
    }

    pub fn has_intersection(&self, other: &Rect) -> bool {
        unsafe {
            ll::SDL_HasIntersection(self, other) == 0
        }
    }

    pub fn intersection(&self, other: &Rect) -> Option<Rect> {
        let out: Rect = Rect::new(0, 0, 0, 0);

        let result = unsafe {
            ll::SDL_IntersectRect(self, other, &out) == 0
        };

        if result {
            Some(out)
        } else {
            None
        }
    }

    pub fn union(&self, other: &Rect) -> Rect {
        let out: Rect = Rect::new(0, 0, 0, 0);

        unsafe {
            ll::SDL_UnionRect(self, other, &out)
        };

        out
    }

    pub fn intersect_line(&self, start: &Point, end: &Point) -> Option<(Point, Point)> {
        let out_start: Point = start.clone();
        let out_end: Point = end.clone();

        let result = unsafe {
            ll::SDL_IntersectRectAndLine(self, &out_start.x, &out_start.y, &out_end.x, &out_end.y) == 0
        };

        if result {
            Some((out_start, out_end))
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>use std::error;
use std::fmt;
use std::io;
use std::mem;
use std::net::SocketAddr;
use std::result;
use std::time::Instant;

use kudu_pb::rpc_header;
use kudu_pb::rpc_header::{ErrorStatusPB_RpcErrorCodePB as RpcErrorCodePB};

use protobuf::{Message, ProtobufError};

mod backoff;
mod connection;
pub mod master;
mod messenger;
pub mod tablet_server;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RpcErrorCode {
    // Non-fatal RPC errors. Connection should be left open for future RPC calls.

    /// The application generated an error status. See the message field for
    /// more details.
    ApplicationError,
    /// The specified method was not valid.
    NoSuchMethod,
    /// The specified service was not valid.
    NoSuchService,
    /// The server is overloaded - the client should try again shortly.
    ServerTooBusy,
    /// The request parameter was not parseable, was missing required fields,
    /// or the server does not support the required feature flags.
    InvalidRequest,

    // Fatal errors indicate that the client should shut down the connection.

    FatalUnknown,
    /// The RPC server is already shutting down.
    FatalServerShuttingDown,
    /// Fields of RpcHeader are invalid.
    FatalInvalidRpcHeader,
    /// Could not deserialize RPC request.
    FatalDeserializingRequest,
    /// IPC Layer version mismatch.
    FatalVersionMismatch,
    /// Auth failed.
    FatalUnauthorized,
}

impl RpcErrorCode {
    pub fn is_fatal(&self) -> bool {
        match *self {
            RpcErrorCode::FatalUnknown |
            RpcErrorCode::FatalServerShuttingDown |
            RpcErrorCode::FatalInvalidRpcHeader |
            RpcErrorCode::FatalDeserializingRequest |
            RpcErrorCode::FatalVersionMismatch |
            RpcErrorCode::FatalUnauthorized => true,
            _ => false,
        }
    }
}

/// An internal error type returned by RPC operations.
#[derive(Debug)]
pub enum RpcError {
    /// An IO error.
    Io(io::Error),
    /// A Protobuf error.
    Pb(String),
    /// The RPC completed, but the server was not able to service the request.
    Rpc {
        code: RpcErrorCode,
        message: String,
        unsupported_feature_flags: Vec<u32>,
    },
    /// The `Connection` send queue is full.
    ConnectionQueueFull,
    /// The RPC timed out.
    TimedOut,
}

impl RpcError {
    pub fn is_fatal(&self) -> bool {
        match *self {
            RpcError::Io(..) => true,
            RpcError::Pb(..) => true,
            RpcError::Rpc { code, .. } => code.is_fatal(),
            RpcError::ConnectionQueueFull => false,
            RpcError::TimedOut => false,
        }
    }
    pub fn invalid_rpc_header(message: String) -> RpcError {
        RpcError::Rpc {
            code: RpcErrorCode::FatalInvalidRpcHeader,
            message: message,
            unsupported_feature_flags: Vec::new(),
        }
    }
}

impl Clone for RpcError {
    fn clone(&self) -> RpcError {
        match *self {
            RpcError::Io(ref e) => RpcError::Io(io::Error::new(e.kind(),
                                                               error::Error::description(e).clone())),
            RpcError::Pb(ref msg) => RpcError::Pb(msg.clone()),
            RpcError::Rpc { ref code, ref message, ref unsupported_feature_flags } => {
                RpcError::Rpc {
                    code: code.clone(),
                    message: message.clone(),
                    unsupported_feature_flags: unsupported_feature_flags.clone()
                }
            },
            RpcError::ConnectionQueueFull => RpcError::ConnectionQueueFull,
            RpcError::TimedOut => RpcError::TimedOut,
        }
    }
}

impl fmt::Display for RpcError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}

impl error::Error for RpcError {
    fn description(&self) -> &str {
        match *self {
            RpcError::Io(ref error) => error.description(),
            RpcError::Pb(ref msg) => msg,
            RpcError::Rpc { ref message, .. } => message,
            RpcError::ConnectionQueueFull => "connection queue full",
            RpcError::TimedOut => "RPC timed out",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            RpcError::Io(ref error) => error.cause(),
            _ => None,
        }
    }
}

impl From<rpc_header::ErrorStatusPB> for RpcError {
    fn from(mut error: rpc_header::ErrorStatusPB) -> RpcError {
        let code = match error.get_code() {
            RpcErrorCodePB::FATAL_UNKNOWN => RpcErrorCode::FatalUnknown,
            RpcErrorCodePB::ERROR_APPLICATION => RpcErrorCode::ApplicationError,
            RpcErrorCodePB::ERROR_NO_SUCH_METHOD => RpcErrorCode::NoSuchMethod,
            RpcErrorCodePB::ERROR_NO_SUCH_SERVICE => RpcErrorCode::NoSuchService,
            RpcErrorCodePB::ERROR_SERVER_TOO_BUSY => RpcErrorCode::ServerTooBusy,
            RpcErrorCodePB::ERROR_INVALID_REQUEST => RpcErrorCode::InvalidRequest,
            RpcErrorCodePB::FATAL_SERVER_SHUTTING_DOWN => RpcErrorCode::FatalServerShuttingDown,
            RpcErrorCodePB::FATAL_INVALID_RPC_HEADER => RpcErrorCode::FatalInvalidRpcHeader,
            RpcErrorCodePB::FATAL_DESERIALIZING_REQUEST => RpcErrorCode::FatalDeserializingRequest,
            RpcErrorCodePB::FATAL_VERSION_MISMATCH => RpcErrorCode::FatalVersionMismatch,
            RpcErrorCodePB::FATAL_UNAUTHORIZED => RpcErrorCode::FatalUnauthorized,
        };

        let message = mem::replace(error.mut_message(), String::new());
        let unsupported_feature_flags = mem::replace(error.mut_unsupported_feature_flags(), Vec::new());

        RpcError::Rpc {
            code: code,
            message: message,
            unsupported_feature_flags: unsupported_feature_flags,
        }
    }
}

impl From<io::Error> for RpcError {
    fn from(error: io::Error) -> RpcError {
        RpcError::Io(error)
    }
}

impl From<ProtobufError> for RpcError {
    fn from(error: ProtobufError) -> RpcError {
        match error {
            ProtobufError::IoError(error) => RpcError::Io(error),
            ProtobufError::WireError(msg) => RpcError::Pb(msg),
            ProtobufError::MessageNotInitialized { message } =>
                // This should never happen, all Protobuf messages are initialized internally.
                panic!("Protobuf message not initialized: {}", message),
        }
    }
}

pub type RpcResult = result::Result<(), RpcError>;

/// A callback that will be executed when the RPC is complete. If the RPC succeeds, the result will
/// be `Ok`, and the RPC will contain the response and sidecars. Othewise, the result will contain
/// the failure.
pub trait Callback: Send + 'static {
    fn callback(self: Box<Self>, result: RpcResult, rpc: Rpc);

}

impl<F> Callback for F where F: FnOnce(RpcResult, Rpc) + Send + 'static {
    fn callback(self: Box<F>, result: RpcResult, rpc: Rpc) {
        (*self)(result, rpc)
    }
}

pub struct Rpc {
    pub addr: SocketAddr,
    pub service_name: &'static str,
    pub method_name: &'static str,
    pub deadline: Instant,
    pub required_feature_flags: Vec<u32>,
    pub request: Box<Message>,
    pub response: Box<Message>,
    pub sidecars: Vec<Vec<u8>>,
    pub callback: Option<Box<Callback>>,
}

impl Rpc {
    fn complete(mut self) {
        if let Some(callback) = self.callback.take() {
            callback.callback(Ok(()), self)
        }
    }

    fn fail(mut self, error: RpcError) {
        if let Some(callback) = self.callback.take() {
            callback.callback(Err(error), self)
        }
    }
}

impl fmt::Debug for Rpc {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Rpc {{ service: {}, method: {}, deadline: {:?} }}",
               self.service_name, self.method_name, self.deadline)
    }
}

#[cfg(test)]
mod test {
    use std::time::{Duration, Instant};

    use mini_cluster::{MiniCluster, MiniClusterConfig};
    use rpc::messenger;
    use super::*;

    use env_logger;
    use kudu_pb;

    #[test]
    fn test_master_ping() {
        let _ = env_logger::init();
        let cluster = MiniCluster::new(MiniClusterConfig::default()
                                                         .num_tservers(0)
                                                         .log_rpc_negotiation_trace(true)
                                                         .log_rpc_trace(true));
        let messenger = messenger::Messenger::new().unwrap();
        let rpc = master::ping(cluster.master_addrs()[0],
                               Instant::now() + Duration::from_secs(5),
                               kudu_pb::master::PingRequestPB::new());

        let (result, _rpc) = messenger.send_sync(rpc);
        result.unwrap();
    }

    //#[test]
    //fn test_get_tablet_servers() {
        //let _ = env_logger::init();
        //let cluster = MiniCluster::new(MiniClusterConfig::default());
        //let messenger = messenger::Messenger::new().unwrap();
        //let master_addr = cluster.master_addrs()[0];
        //thread::sleep_ms(1000);
        //let future = messenger.send(master_addr,
                                    //"kudu.master.MasterService",
                                    //"ListTabletServers",
                                    //Duration::from_millis(100),
                                    //vec![],
                                    //Box::new(kudu_pb::master::ListTabletServersRequestPB::new()),
                                    //Box::new(kudu_pb::master::ListTabletServersResponsePB::new()));

        //let response = future.await().unwrap();
    //}

    //#[test]
    //fn test_rpc_timeout() {
        //let _ = env_logger::init();
        //let messenger = messenger::Messenger::new().unwrap();
        //let addr = SocketAddr::from_str("127.0.0.1:7051").unwrap();
        //let future = messenger.send(addr,
                                    //"kudu.master.MasterService",
                                    //"ListTabletServers",
                                    //Duration::from_millis(1000),
                                    //vec![],
                                    //Box::new(kudu_pb::master::ListTabletServersRequestPB::new()),
                                    //Box::new(kudu_pb::master::ListTabletServersResponsePB::new()));

        //assert!(future.await().is_err());
    //}
}
<commit_msg>clean up RPC tests<commit_after>use std::error;
use std::fmt;
use std::io;
use std::mem;
use std::net::SocketAddr;
use std::result;
use std::time::Instant;

use kudu_pb::rpc_header;
use kudu_pb::rpc_header::{ErrorStatusPB_RpcErrorCodePB as RpcErrorCodePB};

use protobuf::{Message, ProtobufError};

mod backoff;
mod connection;
pub mod master;
mod messenger;
pub mod tablet_server;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RpcErrorCode {
    // Non-fatal RPC errors. Connection should be left open for future RPC calls.

    /// The application generated an error status. See the message field for
    /// more details.
    ApplicationError,
    /// The specified method was not valid.
    NoSuchMethod,
    /// The specified service was not valid.
    NoSuchService,
    /// The server is overloaded - the client should try again shortly.
    ServerTooBusy,
    /// The request parameter was not parseable, was missing required fields,
    /// or the server does not support the required feature flags.
    InvalidRequest,

    // Fatal errors indicate that the client should shut down the connection.

    FatalUnknown,
    /// The RPC server is already shutting down.
    FatalServerShuttingDown,
    /// Fields of RpcHeader are invalid.
    FatalInvalidRpcHeader,
    /// Could not deserialize RPC request.
    FatalDeserializingRequest,
    /// IPC Layer version mismatch.
    FatalVersionMismatch,
    /// Auth failed.
    FatalUnauthorized,
}

impl RpcErrorCode {
    pub fn is_fatal(&self) -> bool {
        match *self {
            RpcErrorCode::FatalUnknown |
            RpcErrorCode::FatalServerShuttingDown |
            RpcErrorCode::FatalInvalidRpcHeader |
            RpcErrorCode::FatalDeserializingRequest |
            RpcErrorCode::FatalVersionMismatch |
            RpcErrorCode::FatalUnauthorized => true,
            _ => false,
        }
    }
}

/// An internal error type returned by RPC operations.
#[derive(Debug)]
pub enum RpcError {
    /// An IO error.
    Io(io::Error),
    /// A Protobuf error.
    Pb(String),
    /// The RPC completed, but the server was not able to service the request.
    Rpc {
        code: RpcErrorCode,
        message: String,
        unsupported_feature_flags: Vec<u32>,
    },
    /// The `Connection` send queue is full.
    ConnectionQueueFull,
    /// The RPC timed out.
    TimedOut,
}

impl RpcError {
    pub fn is_fatal(&self) -> bool {
        match *self {
            RpcError::Io(..) => true,
            RpcError::Pb(..) => true,
            RpcError::Rpc { code, .. } => code.is_fatal(),
            RpcError::ConnectionQueueFull => false,
            RpcError::TimedOut => false,
        }
    }
    pub fn invalid_rpc_header(message: String) -> RpcError {
        RpcError::Rpc {
            code: RpcErrorCode::FatalInvalidRpcHeader,
            message: message,
            unsupported_feature_flags: Vec::new(),
        }
    }
}

impl Clone for RpcError {
    fn clone(&self) -> RpcError {
        match *self {
            RpcError::Io(ref e) => RpcError::Io(io::Error::new(e.kind(),
                                                               error::Error::description(e).clone())),
            RpcError::Pb(ref msg) => RpcError::Pb(msg.clone()),
            RpcError::Rpc { ref code, ref message, ref unsupported_feature_flags } => {
                RpcError::Rpc {
                    code: code.clone(),
                    message: message.clone(),
                    unsupported_feature_flags: unsupported_feature_flags.clone()
                }
            },
            RpcError::ConnectionQueueFull => RpcError::ConnectionQueueFull,
            RpcError::TimedOut => RpcError::TimedOut,
        }
    }
}

impl fmt::Display for RpcError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}

impl error::Error for RpcError {
    fn description(&self) -> &str {
        match *self {
            RpcError::Io(ref error) => error.description(),
            RpcError::Pb(ref msg) => msg,
            RpcError::Rpc { ref message, .. } => message,
            RpcError::ConnectionQueueFull => "connection queue full",
            RpcError::TimedOut => "RPC timed out",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            RpcError::Io(ref error) => error.cause(),
            _ => None,
        }
    }
}

impl From<rpc_header::ErrorStatusPB> for RpcError {
    fn from(mut error: rpc_header::ErrorStatusPB) -> RpcError {
        let code = match error.get_code() {
            RpcErrorCodePB::FATAL_UNKNOWN => RpcErrorCode::FatalUnknown,
            RpcErrorCodePB::ERROR_APPLICATION => RpcErrorCode::ApplicationError,
            RpcErrorCodePB::ERROR_NO_SUCH_METHOD => RpcErrorCode::NoSuchMethod,
            RpcErrorCodePB::ERROR_NO_SUCH_SERVICE => RpcErrorCode::NoSuchService,
            RpcErrorCodePB::ERROR_SERVER_TOO_BUSY => RpcErrorCode::ServerTooBusy,
            RpcErrorCodePB::ERROR_INVALID_REQUEST => RpcErrorCode::InvalidRequest,
            RpcErrorCodePB::FATAL_SERVER_SHUTTING_DOWN => RpcErrorCode::FatalServerShuttingDown,
            RpcErrorCodePB::FATAL_INVALID_RPC_HEADER => RpcErrorCode::FatalInvalidRpcHeader,
            RpcErrorCodePB::FATAL_DESERIALIZING_REQUEST => RpcErrorCode::FatalDeserializingRequest,
            RpcErrorCodePB::FATAL_VERSION_MISMATCH => RpcErrorCode::FatalVersionMismatch,
            RpcErrorCodePB::FATAL_UNAUTHORIZED => RpcErrorCode::FatalUnauthorized,
        };

        let message = mem::replace(error.mut_message(), String::new());
        let unsupported_feature_flags = mem::replace(error.mut_unsupported_feature_flags(), Vec::new());

        RpcError::Rpc {
            code: code,
            message: message,
            unsupported_feature_flags: unsupported_feature_flags,
        }
    }
}

impl From<io::Error> for RpcError {
    fn from(error: io::Error) -> RpcError {
        RpcError::Io(error)
    }
}

impl From<ProtobufError> for RpcError {
    fn from(error: ProtobufError) -> RpcError {
        match error {
            ProtobufError::IoError(error) => RpcError::Io(error),
            ProtobufError::WireError(msg) => RpcError::Pb(msg),
            ProtobufError::MessageNotInitialized { message } =>
                // This should never happen, all Protobuf messages are initialized internally.
                panic!("Protobuf message not initialized: {}", message),
        }
    }
}

pub type RpcResult = result::Result<(), RpcError>;

/// A callback that will be executed when the RPC is complete. If the RPC succeeds, the result will
/// be `Ok`, and the RPC will contain the response and sidecars. Othewise, the result will contain
/// the failure.
pub trait Callback: Send + 'static {
    fn callback(self: Box<Self>, result: RpcResult, rpc: Rpc);

}

impl<F> Callback for F where F: FnOnce(RpcResult, Rpc) + Send + 'static {
    fn callback(self: Box<F>, result: RpcResult, rpc: Rpc) {
        (*self)(result, rpc)
    }
}

pub struct Rpc {
    pub addr: SocketAddr,
    pub service_name: &'static str,
    pub method_name: &'static str,
    pub deadline: Instant,
    pub required_feature_flags: Vec<u32>,
    pub request: Box<Message>,
    pub response: Box<Message>,
    pub sidecars: Vec<Vec<u8>>,
    pub callback: Option<Box<Callback>>,
}

impl Rpc {
    fn complete(mut self) {
        if let Some(callback) = self.callback.take() {
            callback.callback(Ok(()), self)
        }
    }

    fn fail(mut self, error: RpcError) {
        if let Some(callback) = self.callback.take() {
            callback.callback(Err(error), self)
        }
    }
}

impl fmt::Debug for Rpc {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Rpc {{ service: {}, method: {}, deadline: {:?} }}",
               self.service_name, self.method_name, self.deadline)
    }
}

#[cfg(test)]
mod test {
    use std::time::{Duration, Instant};

    use mini_cluster::{MiniCluster, MiniClusterConfig};
    use rpc::messenger;
    use super::*;

    use env_logger;
    use kudu_pb;

    #[test]
    fn test_master_ping() {
        let _ = env_logger::init();
        let cluster = MiniCluster::new(MiniClusterConfig::default()
                                                         .num_tservers(0)
                                                         .log_rpc_negotiation_trace(true)
                                                         .log_rpc_trace(true));
        let messenger = messenger::Messenger::new().unwrap();
        let rpc = master::ping(cluster.master_addrs()[0],
                               Instant::now() + Duration::from_secs(5),
                               kudu_pb::master::PingRequestPB::new());

        let (result, _rpc) = messenger.send_sync(rpc);
        result.unwrap();
    }
}
<|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/. */

//! Rust wrappers around the raw JS apis

use libc::types::os::arch::c95::{size_t, c_uint};
use libc::c_char;
use std::ffi;
use std::rc;
use std::str;
use std::u32;
use jsapi::*;
use jsapi::JSVersion::JSVERSION_LATEST;
use jsval::{JSVal, NullValue};
use default_stacksize;
use default_heapsize;
use JSOPTION_VAROBJFIX;
use JSOPTION_METHODJIT;
use JSOPTION_TYPE_INFERENCE;
use JSOPTION_DONT_REPORT_UNCAUGHT;
use JSOPTION_AUTOJSAPI_OWNS_ERROR_REPORTING;
use ERR;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

/// A wrapper for the `JSRuntime` and `JSContext` structures in SpiderMonkey.
pub struct Runtime {
    pub rt: rt,
    pub cx: rc::Rc<Cx>,
}

impl Runtime {
    /// Creates a new `JSRuntime` and `JSContext`.
    pub fn new() -> Runtime {
        let js_runtime = unsafe { JS_Init(default_heapsize) };
        assert!(!js_runtime.is_null());

        // Unconstrain the runtime's threshold on nominal heap size, to avoid
        // triggering GC too often if operating continuously near an arbitrary
        // finite threshold. This leaves the maximum-JS_malloc-bytes threshold
        // still in effect to cause periodical, and we hope hygienic,
        // last-ditch GCs from within the GC's allocator.
        unsafe {
            JS_SetGCParameter(js_runtime, JSGC_MAX_BYTES, u32::MAX);
        }

        let js_context = unsafe {
            JS_NewContext(js_runtime, default_stacksize as size_t)
        };
        assert!(!js_context.is_null());

        unsafe {
            JS_SetOptions(js_context,
                          JSOPTION_VAROBJFIX |
                          JSOPTION_METHODJIT |
                          JSOPTION_TYPE_INFERENCE |
                          JSOPTION_DONT_REPORT_UNCAUGHT |
                          JSOPTION_AUTOJSAPI_OWNS_ERROR_REPORTING);

            JS_SetVersion(js_context, JSVERSION_LATEST);
            JS_SetErrorReporter(js_context,
                                Some(reportError as unsafe extern "C"
                                     fn(*mut JSContext, *const c_char, *mut JSErrorReport)));
            JS_SetGCZeal(js_context, 0, JS_DEFAULT_ZEAL_FREQ);
        }

        let js_runtime = rc::Rc::new(rt_rsrc {
            ptr: js_runtime
        });
        let js_context = rc::Rc::new(Cx {
            ptr: js_context,
            rt: js_runtime.clone(),
        });
        Runtime {
            rt: js_runtime,
            cx: js_context,
        }
    }

    /// Returns the `JSRuntime` object.
    pub fn rt(&self) -> *mut JSRuntime {
        self.rt.ptr
    }

    /// Returns the `JSContext` object.
    pub fn cx(&self) -> *mut JSContext {
        self.cx.ptr
    }
}

pub type rt = rc::Rc<rt_rsrc>;

pub struct rt_rsrc {
    pub ptr : *mut JSRuntime,
}

impl Drop for rt_rsrc {
    fn drop(&mut self) {
        unsafe {
            JS_Finish(self.ptr);
        }
    }
}

// ___________________________________________________________________________
// contexts

pub struct Cx {
    pub ptr: *mut JSContext,
    pub rt: rt,
}

impl Drop for Cx {
    fn drop(&mut self) {
        unsafe {
            JS_DestroyContext(self.ptr);
        }
    }
}

impl Cx {
    pub fn evaluate_script(&self, glob: *mut JSObject, script: String, filename: String, line_num: usize)
                    -> Result<(),()> {
        let script_utf16: Vec<u16> = script.utf16_units().collect();
        let filename_cstr = ffi::CString::new(filename.as_bytes()).unwrap();
        let mut rval: JSVal = NullValue();
        debug!("Evaluating script from {} with content {}", filename, script);
        // SpiderMonkey does not approve of null pointers.
        let (ptr, len) = if script_utf16.len() == 0 {
            static empty: &'static [u16] = &[];
            (empty.as_ptr(), 0)
        } else {
            (script_utf16.as_ptr(), script_utf16.len() as c_uint)
        };
        assert!(!ptr.is_null());
        unsafe {
            if ERR == JS_EvaluateUCScript(self.ptr, glob, ptr, len,
                                          filename_cstr.as_ptr(), line_num as c_uint,
                                          &mut rval) {
                debug!("...err!");
                Err(())
            } else {
                // we could return the script result but then we'd have
                // to root it and so forth and, really, who cares?
                debug!("...ok!");
                Ok(())
            }
        }
    }
}

pub unsafe extern fn reportError(_cx: *mut JSContext, msg: *const c_char, report: *mut JSErrorReport) {
    let fnptr = (*report).filename;
    let fname = if !fnptr.is_null() {
        let c_str = ffi::CStr::from_ptr(fnptr);
        str::from_utf8(c_str.to_bytes()).ok().unwrap().to_string()
    } else {
        "none".to_string()
    };
    let lineno = (*report).lineno;
    let c_str = ffi::CStr::from_ptr(msg);
    let msg = str::from_utf8(c_str.to_bytes()).ok().unwrap().to_string();
    error!("Error at {}:{}: {}\n", fname, lineno, msg);
}

pub fn with_compartment<R, F: FnMut() -> R>(cx: *mut JSContext, object: *mut JSObject, mut cb: F) -> R {
    unsafe {
        let call = JS_EnterCrossCompartmentCall(cx, object);
        let result = cb();
        JS_LeaveCrossCompartmentCall(call);
        result
    }
}

#[cfg(test)]
pub mod test {
    use super::Runtime;

    #[test]
    pub fn dummy() {
        let _rt = Runtime::new();
    }

}
<commit_msg>Implement Clone for Runtime.<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/. */

//! Rust wrappers around the raw JS apis

use libc::types::os::arch::c95::{size_t, c_uint};
use libc::c_char;
use std::ffi;
use std::rc;
use std::str;
use std::u32;
use jsapi::*;
use jsapi::JSVersion::JSVERSION_LATEST;
use jsval::{JSVal, NullValue};
use default_stacksize;
use default_heapsize;
use JSOPTION_VAROBJFIX;
use JSOPTION_METHODJIT;
use JSOPTION_TYPE_INFERENCE;
use JSOPTION_DONT_REPORT_UNCAUGHT;
use JSOPTION_AUTOJSAPI_OWNS_ERROR_REPORTING;
use ERR;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

/// A wrapper for the `JSRuntime` and `JSContext` structures in SpiderMonkey.
#[derive(Clone)]
pub struct Runtime {
    pub rt: rt,
    pub cx: rc::Rc<Cx>,
}

impl Runtime {
    /// Creates a new `JSRuntime` and `JSContext`.
    pub fn new() -> Runtime {
        let js_runtime = unsafe { JS_Init(default_heapsize) };
        assert!(!js_runtime.is_null());

        // Unconstrain the runtime's threshold on nominal heap size, to avoid
        // triggering GC too often if operating continuously near an arbitrary
        // finite threshold. This leaves the maximum-JS_malloc-bytes threshold
        // still in effect to cause periodical, and we hope hygienic,
        // last-ditch GCs from within the GC's allocator.
        unsafe {
            JS_SetGCParameter(js_runtime, JSGC_MAX_BYTES, u32::MAX);
        }

        let js_context = unsafe {
            JS_NewContext(js_runtime, default_stacksize as size_t)
        };
        assert!(!js_context.is_null());

        unsafe {
            JS_SetOptions(js_context,
                          JSOPTION_VAROBJFIX |
                          JSOPTION_METHODJIT |
                          JSOPTION_TYPE_INFERENCE |
                          JSOPTION_DONT_REPORT_UNCAUGHT |
                          JSOPTION_AUTOJSAPI_OWNS_ERROR_REPORTING);

            JS_SetVersion(js_context, JSVERSION_LATEST);
            JS_SetErrorReporter(js_context,
                                Some(reportError as unsafe extern "C"
                                     fn(*mut JSContext, *const c_char, *mut JSErrorReport)));
            JS_SetGCZeal(js_context, 0, JS_DEFAULT_ZEAL_FREQ);
        }

        let js_runtime = rc::Rc::new(rt_rsrc {
            ptr: js_runtime
        });
        let js_context = rc::Rc::new(Cx {
            ptr: js_context,
            rt: js_runtime.clone(),
        });
        Runtime {
            rt: js_runtime,
            cx: js_context,
        }
    }

    /// Returns the `JSRuntime` object.
    pub fn rt(&self) -> *mut JSRuntime {
        self.rt.ptr
    }

    /// Returns the `JSContext` object.
    pub fn cx(&self) -> *mut JSContext {
        self.cx.ptr
    }
}

pub type rt = rc::Rc<rt_rsrc>;

pub struct rt_rsrc {
    pub ptr : *mut JSRuntime,
}

impl Drop for rt_rsrc {
    fn drop(&mut self) {
        unsafe {
            JS_Finish(self.ptr);
        }
    }
}

// ___________________________________________________________________________
// contexts

pub struct Cx {
    pub ptr: *mut JSContext,
    pub rt: rt,
}

impl Drop for Cx {
    fn drop(&mut self) {
        unsafe {
            JS_DestroyContext(self.ptr);
        }
    }
}

impl Cx {
    pub fn evaluate_script(&self, glob: *mut JSObject, script: String, filename: String, line_num: usize)
                    -> Result<(),()> {
        let script_utf16: Vec<u16> = script.utf16_units().collect();
        let filename_cstr = ffi::CString::new(filename.as_bytes()).unwrap();
        let mut rval: JSVal = NullValue();
        debug!("Evaluating script from {} with content {}", filename, script);
        // SpiderMonkey does not approve of null pointers.
        let (ptr, len) = if script_utf16.len() == 0 {
            static empty: &'static [u16] = &[];
            (empty.as_ptr(), 0)
        } else {
            (script_utf16.as_ptr(), script_utf16.len() as c_uint)
        };
        assert!(!ptr.is_null());
        unsafe {
            if ERR == JS_EvaluateUCScript(self.ptr, glob, ptr, len,
                                          filename_cstr.as_ptr(), line_num as c_uint,
                                          &mut rval) {
                debug!("...err!");
                Err(())
            } else {
                // we could return the script result but then we'd have
                // to root it and so forth and, really, who cares?
                debug!("...ok!");
                Ok(())
            }
        }
    }
}

pub unsafe extern fn reportError(_cx: *mut JSContext, msg: *const c_char, report: *mut JSErrorReport) {
    let fnptr = (*report).filename;
    let fname = if !fnptr.is_null() {
        let c_str = ffi::CStr::from_ptr(fnptr);
        str::from_utf8(c_str.to_bytes()).ok().unwrap().to_string()
    } else {
        "none".to_string()
    };
    let lineno = (*report).lineno;
    let c_str = ffi::CStr::from_ptr(msg);
    let msg = str::from_utf8(c_str.to_bytes()).ok().unwrap().to_string();
    error!("Error at {}:{}: {}\n", fname, lineno, msg);
}

pub fn with_compartment<R, F: FnMut() -> R>(cx: *mut JSContext, object: *mut JSObject, mut cb: F) -> R {
    unsafe {
        let call = JS_EnterCrossCompartmentCall(cx, object);
        let result = cb();
        JS_LeaveCrossCompartmentCall(call);
        result
    }
}

#[cfg(test)]
pub mod test {
    use super::Runtime;

    #[test]
    pub fn dummy() {
        let _rt = Runtime::new();
    }

}
<|endoftext|>


<commit_before>extern crate syntax;

pub use syntax::ast;
pub use syntax::ptr::P;
pub use syntax::codemap::DUMMY_SP;
pub use syntax::ext::base::ExtCtxt;
pub use syntax::ast::{Mod, Item, Expr, TokenTree};
pub use syntax::parse::token::str_to_ident;
pub use syntax::ext::build::AstBuilder;
pub use syntax::print::pprust::{expr_to_string, item_to_string};

pub fn module(items: Vec<P<Item>>) -> P<Mod> {
	P(Mod{
		inner: DUMMY_SP,
		items: items,
	})
}

pub fn parse_path(ctxt: &ExtCtxt, e: &str) -> ast::Path {
	let mut p = syntax::parse::new_parser_from_source_str(&ctxt.parse_sess, Vec::new(), "<peg>".to_string(), e.to_string());
	let r = panictry!(p.parse_path(syntax::parse::parser::NoTypesAllowed));
	p.abort_if_errors();
	r
}

pub fn parse_path_vec(s: &str) -> Vec<ast::Ident> {
	s.split("::").map(|i| str_to_ident(i)).collect()
}

pub fn parse_block(ctxt: &ExtCtxt, e: &str) -> P<ast::Block> {
	let mut p = syntax::parse::new_parser_from_source_str(&ctxt.parse_sess, Vec::new(), "<peg>".to_string(), e.to_string());
	let r = panictry!(p.parse_block());
	p.abort_if_errors();
	r
}

pub fn parse_type(ctxt: &ExtCtxt, e: &str) -> P<ast::Ty> {
	let mut p = syntax::parse::new_parser_from_source_str(&ctxt.parse_sess, Vec::new(), "<peg>".to_string(), e.to_string());
	let r = panictry!(p.parse_ty());
	p.abort_if_errors();
	r
}
<commit_msg>rust: PathParsingMode -> PathStyle<commit_after>extern crate syntax;

pub use syntax::ast;
pub use syntax::ptr::P;
pub use syntax::codemap::DUMMY_SP;
pub use syntax::ext::base::ExtCtxt;
pub use syntax::ast::{Mod, Item, Expr, TokenTree};
pub use syntax::parse::token::str_to_ident;
pub use syntax::ext::build::AstBuilder;
pub use syntax::print::pprust::{expr_to_string, item_to_string};

pub fn module(items: Vec<P<Item>>) -> P<Mod> {
	P(Mod{
		inner: DUMMY_SP,
		items: items,
	})
}

pub fn parse_path(ctxt: &ExtCtxt, e: &str) -> ast::Path {
	let mut p = syntax::parse::new_parser_from_source_str(&ctxt.parse_sess, Vec::new(), "<peg>".to_string(), e.to_string());
	let r = panictry!(p.parse_path(syntax::parse::parser::PathStyle::Mod));
	p.abort_if_errors();
	r
}

pub fn parse_path_vec(s: &str) -> Vec<ast::Ident> {
	s.split("::").map(|i| str_to_ident(i)).collect()
}

pub fn parse_block(ctxt: &ExtCtxt, e: &str) -> P<ast::Block> {
	let mut p = syntax::parse::new_parser_from_source_str(&ctxt.parse_sess, Vec::new(), "<peg>".to_string(), e.to_string());
	let r = panictry!(p.parse_block());
	p.abort_if_errors();
	r
}

pub fn parse_type(ctxt: &ExtCtxt, e: &str) -> P<ast::Ty> {
	let mut p = syntax::parse::new_parser_from_source_str(&ctxt.parse_sess, Vec::new(), "<peg>".to_string(), e.to_string());
	let r = panictry!(p.parse_ty());
	p.abort_if_errors();
	r
}
<|endoftext|>


<commit_before>use std::from_str::FromStr;

use super::ScanCursor;
use super::{ScanError, OtherScanError};

macro_rules! from_str_scanner {
	($scan_fn:path -> $T:ty as $name:expr) => {
		impl Scanner<$T> for $T {
			fn scan<'a, Cur: ScanCursor<'a>>(cursor: &Cur) -> Result<($T, Cur), ScanError> {
				let err = |cur:&Cur| Err(OtherScanError(format!(concat!("expected ",$name,", got `{}`"), cur.tail_str()), cursor.consumed()));

				let end = match $scan_fn(cursor.tail_str()) {
					Some(i) => i,
					None => return err(cursor)
				};

				let s = cursor.str_slice_to(end);
				let cursor = cursor.slice_from(end);

				FromStr::from_str(s)
					.map(ref |i| Ok((i, cursor.clone())))
					.unwrap_or_else(|| err(&cursor))
			}
		}
	};
}

pub trait Scanner<T> {
	fn scan<'a, Cur: ScanCursor<'a>>(cursor: &Cur) -> Result<(Self, Cur), ScanError>;
}

impl Scanner<bool> for bool {
	fn scan<'a, Cur: ScanCursor<'a>>(cursor: &Cur) -> Result<(bool, Cur), ScanError> {
		cursor.expect_tok("true").map(|c| (true, c))
			.or_else(|_| cursor.expect_tok("false").map(|c| (false, c)))
			.or_else(|_| Err(OtherScanError(format!("expected `true` or `false`, got `{}`", cursor.tail_str()), cursor.consumed())))
	}
}

from_str_scanner! { scan_int -> i8 as "8-bit integer" }
from_str_scanner! { scan_int -> i16 as "16-bit integer" }
from_str_scanner! { scan_int -> i32 as "32-bit integer" }
from_str_scanner! { scan_int -> i64 as "64-bit integer" }
from_str_scanner! { scan_int -> int as "integer" }
from_str_scanner! { scan_uint -> u8 as "8-bit unsigned integer" }
from_str_scanner! { scan_uint -> u16 as "16-bit unsigned integer" }
from_str_scanner! { scan_uint -> u32 as "32-bit unsigned integer" }
from_str_scanner! { scan_uint -> u64 as "64-bit unsigned integer" }
from_str_scanner! { scan_uint -> uint as "unsigned integer" }

fn next_char_at(s: &str, at: uint) -> uint {
	let ::std::str::CharRange { ch: _, next } = s.char_range_at(at);
	next
}

fn scan_uint<'a>(s: &'a str) -> Option<uint> {
	s.char_indices()
		.take_while(|&(_,c)| '0' <= c && c <= '9')
		.map(|(i,_)| Some(next_char_at(s, i)))
		.last().unwrap_or(None)
}

fn scan_int<'a>(s: &'a str) -> Option<uint> {
	if s.len() == 0 { return None }

	let (s, off) = if s.char_at(0) == '-' {
		(s.slice_from(1), 1)
	} else {
		(s, 0)
	};

	scan_uint(s).map(|end| end+off)
}

#[cfg(test)]
mod test {
	use Cursor;
	use ScanError;
	use super::Scanner;
	use tokenizer::WordsAndInts;
	use whitespace::Ignore;

	fn cur<'a>(s: &'a str) -> Cursor<'a, WordsAndInts, Ignore> {
		Cursor::new(s, WordsAndInts, Ignore)
	}

	fn scan_a<'a, T: Scanner<T>>(s: &'a str) -> Result<(T, Cursor<'a, WordsAndInts, Ignore>), ScanError> {
		Scanner::scan(&cur(s))
	}

	#[test]
	fn test_bool() {
		assert!(scan_a::<bool>("").err().is_some());
		assert!(scan_a::<bool>("true").unwrap().0 == true);
		assert!(scan_a::<bool>("false").unwrap().0 == false);
		assert!(scan_a::<bool>("yes").err().is_some());
		assert!(scan_a::<bool>("no").err().is_some());
		assert!(scan_a::<bool>("on").err().is_some());
		assert!(scan_a::<bool>("off").err().is_some());
		assert!(scan_a::<bool>("1").err().is_some());
		assert!(scan_a::<bool>("0").err().is_some());
	}

	#[test]
	fn test_sized_ints() {
		use std::fmt::Show;
		use std::num::{Bounded, Int, Zero};

		fn test<'a, I: Int + Scanner<I> + Show>(check_past: bool) {
			let zero: I = Zero::zero();
			let min: I = Bounded::min_value();
			let max: I = Bounded::max_value();

			assert!(scan_a::<I>("").err().is_some());
			assert!(scan_a::<I>("0").ok().unwrap().0 == zero);
			assert!(scan_a::<I>(format!("{}", min).as_slice()).ok().unwrap().0 == min);
			assert!(scan_a::<I>(format!("{}", max).as_slice()).ok().unwrap().0 == max);

			if check_past {
				let past_min: i64 = (min.to_i64()).unwrap() - 1;
				let past_max: u64 = (max.to_u64()).unwrap() + 1;
				assert!(scan_a::<I>(format!("{}", past_min).as_slice()).err().is_some());
				assert!(scan_a::<I>(format!("{}", past_max).as_slice()).err().is_some());
			}
		}

		test::<i8>(true);
		test::<i16>(true);
		test::<i32>(true);
		test::<i64>(false);
		test::<u8>(true);
		test::<u16>(true);
		test::<u32>(true);
		test::<u64>(false);
	}

	#[test]
	fn test_int() {
		assert!(scan_a::<int>("").err().is_some());
		assert!(scan_a::<int>("0").ok().unwrap().0 == 0);
		assert!(scan_a::<int>("42").ok().unwrap().0 == 42);
		assert!(scan_a::<int>("1_234").ok().unwrap().0 == 1);
		assert!(scan_a::<int>("x").err().is_some());
		assert!(scan_a::<int>("0x").ok().unwrap().0 == 0);
		assert!(scan_a::<int>("42x").ok().unwrap().0 == 42);
		assert!(scan_a::<int>("-").err().is_some());
		assert!(scan_a::<int>("-0").ok().unwrap().0 == 0);
		assert!(scan_a::<int>("-42").ok().unwrap().0 == -42);
		assert!(scan_a::<int>("-1_234").ok().unwrap().0 == -1);
	}

	#[test]
	fn test_uint() {
		assert!(scan_a::<uint>("").err().is_some());
		assert!(scan_a::<uint>("0").ok().unwrap().0 == 0);
		assert!(scan_a::<uint>("42").ok().unwrap().0 == 42);
		assert!(scan_a::<uint>("1_234").ok().unwrap().0 == 1);
		assert!(scan_a::<uint>("x").err().is_some());
		assert!(scan_a::<uint>("0x").ok().unwrap().0 == 0);
		assert!(scan_a::<uint>("42x").ok().unwrap().0 == 42);
		assert!(scan_a::<uint>("-").err().is_some());
		assert!(scan_a::<uint>("-0").err().is_some());
		assert!(scan_a::<uint>("-42").err().is_some());
		assert!(scan_a::<uint>("-1_234").err().is_some());
	}
}
<commit_msg>Added f32 and f64 scanners.<commit_after>use std::from_str::FromStr;

use super::ScanCursor;
use super::{ScanError, OtherScanError};

macro_rules! from_str_scanner {
	($scan_fn:path -> $T:ty as $name:expr) => {
		impl Scanner<$T> for $T {
			fn scan<'a, Cur: ScanCursor<'a>>(cursor: &Cur) -> Result<($T, Cur), ScanError> {
				let err = |cur:&Cur| Err(OtherScanError(format!(concat!("expected ",$name,", got `{}`"), cur.tail_str()), cursor.consumed()));

				let end = match $scan_fn(cursor.tail_str()) {
					Some(i) => i,
					None => return err(cursor)
				};

				let s = cursor.str_slice_to(end);
				let cursor = cursor.slice_from(end);

				FromStr::from_str(s)
					.map(ref |i| Ok((i, cursor.clone())))
					.unwrap_or_else(|| err(&cursor))
			}
		}
	};
}

pub trait Scanner<T> {
	fn scan<'a, Cur: ScanCursor<'a>>(cursor: &Cur) -> Result<(Self, Cur), ScanError>;
}

impl Scanner<bool> for bool {
	fn scan<'a, Cur: ScanCursor<'a>>(cursor: &Cur) -> Result<(bool, Cur), ScanError> {
		cursor.expect_tok("true").map(|c| (true, c))
			.or_else(|_| cursor.expect_tok("false").map(|c| (false, c)))
			.or_else(|_| Err(OtherScanError(format!("expected `true` or `false`, got `{}`", cursor.tail_str()), cursor.consumed())))
	}
}

from_str_scanner! { scan_float -> f32 as "real number" }
from_str_scanner! { scan_float -> f64 as "real number" }
from_str_scanner! { scan_int -> i8 as "8-bit integer" }
from_str_scanner! { scan_int -> i16 as "16-bit integer" }
from_str_scanner! { scan_int -> i32 as "32-bit integer" }
from_str_scanner! { scan_int -> i64 as "64-bit integer" }
from_str_scanner! { scan_int -> int as "integer" }
from_str_scanner! { scan_uint -> u8 as "8-bit unsigned integer" }
from_str_scanner! { scan_uint -> u16 as "16-bit unsigned integer" }
from_str_scanner! { scan_uint -> u32 as "32-bit unsigned integer" }
from_str_scanner! { scan_uint -> u64 as "64-bit unsigned integer" }
from_str_scanner! { scan_uint -> uint as "unsigned integer" }

fn next_char_at(s: &str, at: uint) -> uint {
	let ::std::str::CharRange { ch: _, next } = s.char_range_at(at);
	next
}

fn scan_float(s: &str) -> Option<uint> {
	enum State {
		Start,
		Whole,
		Suffix,
		ExponentStart,
		Exponent,
	}

	let mut state = Start;

	for (i,c) in s.char_indices() {
		match state {
			Start => {
				assert!(i == 0);
				match c {
					'0'..'9' | '-' => state = Whole,
					_ => return None
				}
			},
			Whole => match c {
				'0'..'9' => (),
				'.' => state = Suffix,
				'e' | 'E' => state = ExponentStart,
				_ => return Some(i)
			},
			Suffix => match c {
				'0'..'9' => (),
				'e' | 'E' => state = ExponentStart,
				_ => return Some(i),
			},
			ExponentStart => match c {
				'+' | '-' | '0'..'9' => state = Exponent,
				_ => return Some(i)
			},
			Exponent => match c {
				'0'..'9' => (),
				_ => return Some(i)
			}
		}
	}

	return Some(s.len())
}

fn scan_uint<'a>(s: &'a str) -> Option<uint> {
	s.char_indices()
		.take_while(|&(_,c)| '0' <= c && c <= '9')
		.map(|(i,_)| Some(next_char_at(s, i)))
		.last().unwrap_or(None)
}

fn scan_int<'a>(s: &'a str) -> Option<uint> {
	if s.len() == 0 { return None }

	let (s, off) = if s.char_at(0) == '-' {
		(s.slice_from(1), 1)
	} else {
		(s, 0)
	};

	scan_uint(s).map(|end| end+off)
}

#[cfg(test)]
mod test {
	use Cursor;
	use ScanError;
	use super::Scanner;
	use tokenizer::WordsAndInts;
	use whitespace::Ignore;

	fn cur<'a>(s: &'a str) -> Cursor<'a, WordsAndInts, Ignore> {
		Cursor::new(s, WordsAndInts, Ignore)
	}

	fn scan_a<'a, T: Scanner<T>>(s: &'a str) -> Result<(T, Cursor<'a, WordsAndInts, Ignore>), ScanError> {
		Scanner::scan(&cur(s))
	}

	#[test]
	fn test_bool() {
		assert!(scan_a::<bool>("").err().is_some());
		assert!(scan_a::<bool>("true").unwrap().0 == true);
		assert!(scan_a::<bool>("false").unwrap().0 == false);
		assert!(scan_a::<bool>("yes").err().is_some());
		assert!(scan_a::<bool>("no").err().is_some());
		assert!(scan_a::<bool>("on").err().is_some());
		assert!(scan_a::<bool>("off").err().is_some());
		assert!(scan_a::<bool>("1").err().is_some());
		assert!(scan_a::<bool>("0").err().is_some());
	}

	#[test]
	fn test_floats() {
		use std::from_str::FromStr;
		use std::num::{Float, Zero};

		fn test<F: Float + Scanner<F> + FromStr>() {
			let f = |v:F| v;
			let fs = |s:&str| -> F FromStr::from_str(s).unwrap();

			assert!(scan_a::<F>("").err().is_some());
			assert!(scan_a::<F>("0").ok().unwrap().0 == f(Zero::zero()));
			assert!(scan_a::<F>("0.0").ok().unwrap().0 == f(Zero::zero()));
			assert!(scan_a::<F>("-0").ok().unwrap().0 == -f(Zero::zero()));
			assert!(scan_a::<F>("1.0").ok().unwrap().0 == fs("1.0"));
			assert!(scan_a::<F>("1.00").ok().unwrap().0 == fs("1.0"));
			assert!(scan_a::<F>("1.0e0").ok().unwrap().0 == fs("1.0"));
			assert!(scan_a::<F>("1.0e1").ok().unwrap().0 == fs("10.0"));
		}

		test::<f32>();
		test::<f64>();
	}

	#[test]
	fn test_sized_ints() {
		use std::fmt::Show;
		use std::num::{Bounded, Int, Zero};

		fn test<'a, I: Int + Scanner<I> + Show>(check_past: bool) {
			let zero: I = Zero::zero();
			let min: I = Bounded::min_value();
			let max: I = Bounded::max_value();

			assert!(scan_a::<I>("").err().is_some());
			assert!(scan_a::<I>("0").ok().unwrap().0 == zero);
			assert!(scan_a::<I>(format!("{}", min).as_slice()).ok().unwrap().0 == min);
			assert!(scan_a::<I>(format!("{}", max).as_slice()).ok().unwrap().0 == max);

			if check_past {
				let past_min: i64 = (min.to_i64()).unwrap() - 1;
				let past_max: u64 = (max.to_u64()).unwrap() + 1;
				assert!(scan_a::<I>(format!("{}", past_min).as_slice()).err().is_some());
				assert!(scan_a::<I>(format!("{}", past_max).as_slice()).err().is_some());
			}
		}

		test::<i8>(true);
		test::<i16>(true);
		test::<i32>(true);
		test::<i64>(false);
		test::<u8>(true);
		test::<u16>(true);
		test::<u32>(true);
		test::<u64>(false);
	}

	#[test]
	fn test_int() {
		assert!(scan_a::<int>("").err().is_some());
		assert!(scan_a::<int>("0").ok().unwrap().0 == 0);
		assert!(scan_a::<int>("42").ok().unwrap().0 == 42);
		assert!(scan_a::<int>("1_234").ok().unwrap().0 == 1);
		assert!(scan_a::<int>("x").err().is_some());
		assert!(scan_a::<int>("0x").ok().unwrap().0 == 0);
		assert!(scan_a::<int>("42x").ok().unwrap().0 == 42);
		assert!(scan_a::<int>("-").err().is_some());
		assert!(scan_a::<int>("-0").ok().unwrap().0 == 0);
		assert!(scan_a::<int>("-42").ok().unwrap().0 == -42);
		assert!(scan_a::<int>("-1_234").ok().unwrap().0 == -1);
	}

	#[test]
	fn test_uint() {
		assert!(scan_a::<uint>("").err().is_some());
		assert!(scan_a::<uint>("0").ok().unwrap().0 == 0);
		assert!(scan_a::<uint>("42").ok().unwrap().0 == 42);
		assert!(scan_a::<uint>("1_234").ok().unwrap().0 == 1);
		assert!(scan_a::<uint>("x").err().is_some());
		assert!(scan_a::<uint>("0x").ok().unwrap().0 == 0);
		assert!(scan_a::<uint>("42x").ok().unwrap().0 == 42);
		assert!(scan_a::<uint>("-").err().is_some());
		assert!(scan_a::<uint>("-0").err().is_some());
		assert!(scan_a::<uint>("-42").err().is_some());
		assert!(scan_a::<uint>("-1_234").err().is_some());
	}
}
<|endoftext|>


<commit_before>//! Module defining all sensor related structures.

use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};
use optional::Optional;

//--- Templates ---//

/// A trait for all possible sensor templates.
/// the `SensorTemplate`s are capable of registering themselves in a `Sensors` struct
pub trait SensorTemplate : Send+Sync {
    fn to_sensor(&self, value_str: &str, sensors: &mut Sensors);
}

#[derive(Debug, Clone)]
pub struct PeopleNowPresentSensorTemplate {
    pub location: Optional<String>,
    pub name: Optional<String>,
    pub names: Optional<Vec<String>>,
    pub description: Optional<String>,
}

impl SensorTemplate for PeopleNowPresentSensorTemplate {
    fn to_sensor(&self, value_str: &str, sensors: &mut Sensors) {
        if value_str.parse::<i64>().map(|value|{
            let sensor = PeopleNowPresentSensor {
                location: self.location.clone(),
                name: self.name.clone(),
                names: self.names.clone(),
                description: self.description.clone(),
                value: value,
            };

            match sensors.people_now_present {
                Optional::Value(ref mut vec_sensors) => {
                    vec_sensors.push(sensor)
                }
                Optional::Absent => {
                    sensors.people_now_present = Optional::Value(vec![sensor])
                }
            }
        }).is_err() {
            warn!("Could not parse value '{}', omiting PeopleNowPresentSensor", value_str);
        }
    }
}

#[derive(Debug, Clone)]
pub struct TemperatureSensorTemplate {
    pub unit: String,
    pub location: String,
    pub name: Optional<String>,
    pub description: Optional<String>,
}

impl SensorTemplate for TemperatureSensorTemplate {
    fn to_sensor(&self, value_str: &str, sensors: &mut Sensors) {
        if value_str.parse::<f64>().map(|value|{
            let sensor = TemperatureSensor {
                unit: self.unit.clone(),
                location: self.location.clone(),
                name: self.name.clone(),
                description: self.description.clone(),
                value: value,
            };
            match sensors.temperature {
                Optional::Value(ref mut vec_sensors) => {
                    vec_sensors.push(sensor)
                }
                Optional::Absent => {
                    sensors.temperature = Optional::Value(vec![sensor])
                }
            }
        }).is_err() {
            warn!("Could not parse value '{}', omiting TemperatureSensor", value_str);
        }
    }
}

//--- Structures ---//

#[derive(Debug, Clone)]
pub struct PeopleNowPresentSensor {
    pub location: Optional<String>,
    pub name: Optional<String>,
    pub names: Optional<Vec<String>>,
    pub description: Optional<String>,
    pub value: i64,
}

#[derive(Debug, Clone)]
pub struct TemperatureSensor {
    pub unit: String,
    pub location: String,
    pub name: Optional<String>,
    pub description: Optional<String>,
    pub value: f64,
}

#[derive(Debug, Clone)]
pub struct Sensors {
    pub people_now_present: Optional<Vec<PeopleNowPresentSensor>>,
    pub temperature: Optional<Vec<TemperatureSensor>>,
}

//--- Serialization ---//

impl ToJson for Sensors {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        self.people_now_present.as_ref().map_or((), |v| { d.insert("people_now_present".to_string(), v.to_json()); });
        self.temperature.as_ref().map_or((), |v| { d.insert("temperature".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for PeopleNowPresentSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        self.location.as_ref().map_or((), |v| { d.insert("location".to_string(), v.to_json()); });
        self.name.as_ref().map_or((), |v| { d.insert("name".to_string(), v.to_json()); });
        self.names.as_ref().map_or((), |v| { d.insert("names".to_string(), v.to_json()); });
        self.description.as_ref().map_or((), |v| { d.insert("description".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for TemperatureSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        d.insert("unit".to_string(), self.unit.to_json());
        d.insert("location".to_string(), self.location.to_json());
        self.name.as_ref().map_or((), |v| { d.insert("name".to_string(), v.to_json()); });
        self.description.as_ref().map_or((), |v| { d.insert("description".to_string(), v.to_json()); });
        Json::Object(d)
    }
}
<commit_msg>Prevent moving the SpaceapiServer into the handler<commit_after>//! Module defining all sensor related structures.

use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};
use optional::Optional;

//--- Templates ---//

/// A trait for all possible sensor templates.
///
/// A sensor template is like a sensor struct, but without the actual data in it.
/// A `SensorTemplate` is capable of registering itself in a `Sensors` struct.
pub trait SensorTemplate : Send+Sync {
    fn to_sensor(&self, value_str: &str, sensors: &mut Sensors);
}

#[derive(Debug, Clone)]
pub struct PeopleNowPresentSensorTemplate {
    pub location: Optional<String>,
    pub name: Optional<String>,
    pub names: Optional<Vec<String>>,
    pub description: Optional<String>,
}

impl SensorTemplate for PeopleNowPresentSensorTemplate {
    fn to_sensor(&self, value_str: &str, sensors: &mut Sensors) {
        if value_str.parse::<i64>().map(|value|{
            let sensor = PeopleNowPresentSensor {
                location: self.location.clone(),
                name: self.name.clone(),
                names: self.names.clone(),
                description: self.description.clone(),
                value: value,
            };

            match sensors.people_now_present {
                Optional::Value(ref mut vec_sensors) => {
                    vec_sensors.push(sensor)
                }
                Optional::Absent => {
                    sensors.people_now_present = Optional::Value(vec![sensor])
                }
            }
        }).is_err() {
            warn!("Could not parse value '{}', omiting PeopleNowPresentSensor", value_str);
        }
    }
}

#[derive(Debug, Clone)]
pub struct TemperatureSensorTemplate {
    pub unit: String,
    pub location: String,
    pub name: Optional<String>,
    pub description: Optional<String>,
}

impl SensorTemplate for TemperatureSensorTemplate {
    fn to_sensor(&self, value_str: &str, sensors: &mut Sensors) {
        if value_str.parse::<f64>().map(|value|{
            let sensor = TemperatureSensor {
                unit: self.unit.clone(),
                location: self.location.clone(),
                name: self.name.clone(),
                description: self.description.clone(),
                value: value,
            };
            match sensors.temperature {
                Optional::Value(ref mut vec_sensors) => {
                    vec_sensors.push(sensor)
                }
                Optional::Absent => {
                    sensors.temperature = Optional::Value(vec![sensor])
                }
            }
        }).is_err() {
            warn!("Could not parse value '{}', omiting TemperatureSensor", value_str);
        }
    }
}

//--- Structures ---//

#[derive(Debug, Clone)]
pub struct PeopleNowPresentSensor {
    pub location: Optional<String>,
    pub name: Optional<String>,
    pub names: Optional<Vec<String>>,
    pub description: Optional<String>,
    pub value: i64,
}

#[derive(Debug, Clone)]
pub struct TemperatureSensor {
    pub unit: String,
    pub location: String,
    pub name: Optional<String>,
    pub description: Optional<String>,
    pub value: f64,
}

#[derive(Debug, Clone)]
pub struct Sensors {
    pub people_now_present: Optional<Vec<PeopleNowPresentSensor>>,
    pub temperature: Optional<Vec<TemperatureSensor>>,
}

//--- Serialization ---//

impl ToJson for Sensors {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        self.people_now_present.as_ref().map_or((), |v| { d.insert("people_now_present".to_string(), v.to_json()); });
        self.temperature.as_ref().map_or((), |v| { d.insert("temperature".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for PeopleNowPresentSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        self.location.as_ref().map_or((), |v| { d.insert("location".to_string(), v.to_json()); });
        self.name.as_ref().map_or((), |v| { d.insert("name".to_string(), v.to_json()); });
        self.names.as_ref().map_or((), |v| { d.insert("names".to_string(), v.to_json()); });
        self.description.as_ref().map_or((), |v| { d.insert("description".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for TemperatureSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        d.insert("unit".to_string(), self.unit.to_json());
        d.insert("location".to_string(), self.location.to_json());
        self.name.as_ref().map_or((), |v| { d.insert("name".to_string(), v.to_json()); });
        self.description.as_ref().map_or((), |v| { d.insert("description".to_string(), v.to_json()); });
        Json::Object(d)
    }
}
<|endoftext|>