<commit_before>/// The Toml Read extensions

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

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

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

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 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 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, ::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 std::collections::BTreeMap;
        use insert::TomlValueInsertExt;
        use read::TomlValueReadExt;

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

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

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

        assert!(true);
    }

}

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

    use std::path::PathBuf;
    use std::sync::Arc;
    use std::collections::BTreeMap;

    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 = BTreeMap::new();
            tbl.insert(String::from("value"), Value::String(String::from("foobar")));
            Value::Table(tbl)
        };

        let obj : TestObj = tbl.read_partial::<TestObj>().unwrap().unwrap();
        assert_eq!(obj.value, "foobar");
    }
}
<commit_msg>Add test for testing proc macro<commit_after>/// The Toml Read extensions

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

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

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

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 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 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, ::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 std::collections::BTreeMap;
        use insert::TomlValueInsertExt;
        use read::TomlValueReadExt;

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

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

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

        assert!(true);
    }

}

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

    use std::path::PathBuf;
    use std::sync::Arc;
    use std::collections::BTreeMap;

    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 = BTreeMap::new();
            tbl.insert(String::from("value"), Value::String(String::from("foobar")));
            Value::Table(tbl)
        };

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

    //
    // Tests with proc macro
    //

    #[derive(Debug, Deserialize, Serialize)]
    #[tq_partial_document(location = "foo")]
    struct TestObjDerived {
        pub value : String,
    }

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

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

}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Read;

pub mod gb_proc;

use self::gb_proc::opcodes::OpCode;

pub fn main() {
    println!("YEE");
    let mut f = File::open("rom.gb").unwrap();
    let mut s = vec![];

    f.read_to_end(&mut s);

    let mut i = 0x100;
    while i < 0x5400 {
        print!("[{:x}] ", i);
        let op = if s[i] == 0xCB {
            i += 1;
            OpCode::from_byte(s[i], true)
        } else if s[i] == 0xE3 || s[i] == 0xE4 || s[i] == 0xF4 || s[i] == 0xFD ||
            s[i] == 0xEC || s[i] == 0xDD || s[i] == 0xDB || s[i] == 0xFC || s[i] == 0xED ||
            s[i] == 0xD3 || s[i] == 0xEB {
            OpCode::Nop
        } else {
            OpCode::from_byte(s[i], false)
        };

        i += 1;

        print!("{}", op.to_string());

        match op {
            OpCode::LdBn | OpCode::LdCn | OpCode::LdDn | OpCode::LdEn | OpCode::LdHn | OpCode::LdLn |
            OpCode::LdHLn | OpCode::LdAx | OpCode::LdhAn | OpCode::AddAx | OpCode::AdcAx |
            OpCode::SubAx | OpCode::AndAx | OpCode::OrAx | OpCode::XorAx | OpCode::CpAx |
            OpCode::LdhnA | OpCode::LdhlSPn | OpCode::AddSPx | OpCode::Jrn | OpCode::JrNZn |
            OpCode::JrZn | OpCode::JrNCn | OpCode::JrCn
            => {
                println!(" 0x{:x}", s[i]);
                i += 1;
            },
            OpCode::LdAnn | OpCode::LdBCnn | OpCode::LdDEnn | OpCode::LdHLnn |
            OpCode::LdSPnn | OpCode::LdnnSP | OpCode::Jpnn | OpCode::Callnn | OpCode::CallNZnn |
            OpCode::CallZnn | OpCode::CallNCnn | OpCode::CallCnn | OpCode::LdnnA | OpCode::JpCnn |
            OpCode::JpNCnn | OpCode::JpZnn | OpCode::JpNZnn
            => {
                println!(" ${:02X}{:02X}", s[i], s[i+1]);
                i += 2;
            },
            _ => { println!("") }
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Delete unused file read.rs.<commit_after><|endoftext|>


<commit_before>//! Matrix rooms.

use std::convert::{TryFrom, TryInto};

use diesel::{Connection, ExecuteDsl, LoadDsl, insert};
use diesel::pg::PgConnection;
use diesel::pg::data_types::PgTimestamp;
use rand::{Rng, thread_rng};
use ruma_events::EventType;
use ruma_events::room::create::{CreateEvent, CreateEventContent};
use ruma_events::room::history_visibility::{
    HistoryVisibility,
    HistoryVisibilityEvent,
    HistoryVisibilityEventContent,
};
use ruma_events::room::join_rules::{
    JoinRule,
    JoinRulesEvent,
    JoinRulesEventContent,
};
use ruma_events::room::member::{
    MemberEvent,
    MemberEventContent,
    MemberEventExtraContent,
    MembershipState,
};
use ruma_events::room::name::{NameEvent, NameEventContent};
use ruma_events::room::topic::{TopicEvent, TopicEventContent};

use error::APIError;
use event::{NewEvent, generate_event_id};
use room_alias::{NewRoomAlias, RoomAlias};
use schema::{events, rooms};
use user::UserId;

/// Options provided by the user to customize the room upon creation.
pub struct CreationOptions {
    /// An initial alias for the room.
    pub alias: Option<String>,
    /// Whehter or not the room should be federated.
    pub federate: bool,
    /// A list of users to invite to the room.
    pub invite_list: Option<Vec<String>>,
    /// An initial name for the room.
    pub name: Option<String>,
    /// A convenience parameter for setting a few default state events.
    pub preset: Option<RoomPreset>,
    /// An initial topic for the room.
    pub topic: Option<String>,
}

/// A new Matrix room, not yet saved.
#[derive(Debug)]
#[insertable_into(rooms)]
pub struct NewRoom {
    /// The room's unique ID.
    pub id: String,
    /// The ID of the user creating the room.
    pub user_id: String,
    /// Whether or not the room is visible in the directory.
    pub public: bool,
}

/// A Matrix room.
#[derive(Debug, Queryable)]
pub struct Room {
    /// The room's unique ID.
    pub id: String,
    /// The ID of the user who created the room.
    pub user_id: String,
    /// Whether or not the room is visible in the directory.
    pub public: bool,
    /// The time the room was created.
    pub created_at: PgTimestamp,
}

/// A convenience parameter for setting a few default state events.
#[derive(Clone, Copy, Debug, Deserialize)]
pub enum RoomPreset {
    /// `join_rules` is set to `invite` and `history_visibility` is set to `shared`.
    PrivateChat,
    /// `join_rules` is set to `public` and `history_visibility` is set to `shared`.
    PublicChat,
    /// Same as `PrivateChat`, but all initial invitees get the same power level as the creator.
    TrustedPrivateChat,
}

impl Room {
    /// Creates a new room in the database.
    pub fn create(
        connection: &PgConnection,
        new_room: &NewRoom,
        homeserver_domain: &str,
        creation_options: &CreationOptions,
    ) -> Result<Room, APIError> {
        connection.transaction::<Room, APIError, _>(|| {
            let room: Room = insert(new_room)
                .into(rooms::table)
                .get_result(connection)
                .map_err(APIError::from)?;

            if let Some(ref alias) = creation_options.alias {
                let new_room_alias = NewRoomAlias {
                    alias: alias.to_string(),
                    room_id: room.id.clone(),
                    servers: vec![homeserver_domain.to_string()],
                };

                RoomAlias::create(connection, &new_room_alias)?;
            }

            let mut new_events = Vec::new();

            let new_create_event: NewEvent = CreateEvent {
                content: CreateEventContent {
                    creator: new_room.user_id.clone(),
                    federate: creation_options.federate,
                },
                event_id: generate_event_id(),
                event_type: EventType::RoomCreate,
                extra_content: (),
                prev_content: None,
                room_id: room.id.clone(),
                state_key: "".to_string(),
                unsigned: None,
                user_id: new_room.user_id.clone(),
            }.try_into()?;

            new_events.push(new_create_event);

            if let Some(ref name) = creation_options.name {
                let new_name_event: NewEvent = NameEvent {
                    content: NameEventContent {
                        name: name.to_string(),
                    },
                    event_id: generate_event_id(),
                    event_type: EventType::RoomName,
                    extra_content: (),
                    prev_content: None,
                    room_id: room.id.clone(),
                    state_key: "".to_string(),
                    unsigned: None,
                    user_id: new_room.user_id.clone(),
                }.try_into()?;

                new_events.push(new_name_event);
            }

            if let Some(ref topic) = creation_options.topic {
                let new_topic_event: NewEvent = TopicEvent {
                    content: TopicEventContent {
                        topic: topic.to_string(),
                    },
                    event_id: generate_event_id(),
                    event_type: EventType::RoomTopic,
                    extra_content: (),
                    prev_content: None,
                    room_id: room.id.clone(),
                    state_key: "".to_string(),
                    unsigned: None,
                    user_id: new_room.user_id.clone(),
                }.try_into()?;

                new_events.push(new_topic_event);
            }

            if let Some(preset) = creation_options.preset {
                let new_history_visibility_event: NewEvent = HistoryVisibilityEvent {
                    content: HistoryVisibilityEventContent {
                        history_visibility: HistoryVisibility::Shared,
                    },
                    event_id: generate_event_id(),
                    event_type: EventType::RoomHistoryVisibility,
                    extra_content: (),
                    prev_content: None,
                    room_id: room.id.clone(),
                    state_key: "".to_string(),
                    unsigned: None,
                    user_id: new_room.user_id.clone(),
                }.try_into()?;

                new_events.push(new_history_visibility_event);

                match preset {
                    RoomPreset::PrivateChat => {
                        let new_join_rules_event: NewEvent = JoinRulesEvent {
                            content: JoinRulesEventContent {
                                join_rule: JoinRule::Invite,
                            },
                            event_id: generate_event_id(),
                            event_type: EventType::RoomJoinRules,
                            extra_content: (),
                            prev_content: None,
                            room_id: room.id.clone(),
                            state_key: "".to_string(),
                            unsigned: None,
                            user_id: new_room.user_id.clone(),
                        }.try_into()?;

                        new_events.push(new_join_rules_event);
                    }
                    RoomPreset::PublicChat => {
                        let new_join_rules_event: NewEvent = JoinRulesEvent {
                            content: JoinRulesEventContent {
                                join_rule: JoinRule::Public,
                            },
                            event_id: generate_event_id(),
                            event_type: EventType::RoomJoinRules,
                            extra_content: (),
                            prev_content: None,
                            room_id: room.id.clone(),
                            state_key: "".to_string(),
                            unsigned: None,
                            user_id: new_room.user_id.clone(),
                        }.try_into()?;

                        new_events.push(new_join_rules_event);
                    }
                    RoomPreset::TrustedPrivateChat => {
                        let new_join_rules_event: NewEvent = JoinRulesEvent {
                            content: JoinRulesEventContent {
                                join_rule: JoinRule::Invite,
                            },
                            event_id: generate_event_id(),
                            event_type: EventType::RoomJoinRules,
                            extra_content: (),
                            prev_content: None,
                            room_id: room.id.clone(),
                            state_key: "".to_string(),
                            unsigned: None,
                            user_id: new_room.user_id.clone(),
                        }.try_into()?;

                        new_events.push(new_join_rules_event);
                    }
                }
            }

            if let Some(ref invite_list) = creation_options.invite_list {
                for invitee in invite_list {
                    let invitee_user_id = UserId::try_from(invitee)?;

                    if invitee_user_id.domain != homeserver_domain {
                        return Err(
                            APIError::unknown_from_string(
                                "Federation is not yet supported.".to_string()
                            )
                        );
                    }

                    let new_member_event: NewEvent = MemberEvent {
                        content: MemberEventContent {
                            avatar_url: None,
                            displayname: None,
                            membership: MembershipState::Invite,
                            third_party_invite: (),
                        },
                        event_id: generate_event_id(),
                        event_type: EventType::RoomMember,
                        extra_content: MemberEventExtraContent {
                            invite_room_state: None,
                        },
                        prev_content: None,
                        room_id: room.id.clone(),
                        state_key: invitee.to_string(),
                        unsigned: None,
                        user_id: new_room.user_id.clone(),
                    }.try_into()?;

                    new_events.push(new_member_event);
                }
            }

            insert(&new_events)
                .into(events::table)
                .execute(connection)
                .map_err(APIError::from)?;

            Ok(room)
        }).map_err(APIError::from)
    }

    /// Generate a random room ID.
    pub fn generate_room_id() -> String {
        thread_rng().gen_ascii_chars().take(12).collect()
    }
}
<commit_msg>Load invited users and ensure all of them exist.<commit_after>//! Matrix rooms.

use std::collections::HashSet;
use std::convert::{TryFrom, TryInto};

use diesel::{Connection, ExecuteDsl, ExpressionMethods, FilterDsl, LoadDsl, insert};
use diesel::pg::PgConnection;
use diesel::pg::data_types::PgTimestamp;
use diesel::pg::expression::dsl::any;
use rand::{Rng, thread_rng};
use ruma_events::EventType;
use ruma_events::room::create::{CreateEvent, CreateEventContent};
use ruma_events::room::history_visibility::{
    HistoryVisibility,
    HistoryVisibilityEvent,
    HistoryVisibilityEventContent,
};
use ruma_events::room::join_rules::{
    JoinRule,
    JoinRulesEvent,
    JoinRulesEventContent,
};
use ruma_events::room::member::{
    MemberEvent,
    MemberEventContent,
    MemberEventExtraContent,
    MembershipState,
};
use ruma_events::room::name::{NameEvent, NameEventContent};
use ruma_events::room::topic::{TopicEvent, TopicEventContent};

use error::APIError;
use event::{NewEvent, generate_event_id};
use room_alias::{NewRoomAlias, RoomAlias};
use schema::{events, rooms, users};
use user::{User, UserId};

/// Options provided by the user to customize the room upon creation.
pub struct CreationOptions {
    /// An initial alias for the room.
    pub alias: Option<String>,
    /// Whehter or not the room should be federated.
    pub federate: bool,
    /// A list of users to invite to the room.
    pub invite_list: Option<Vec<String>>,
    /// An initial name for the room.
    pub name: Option<String>,
    /// A convenience parameter for setting a few default state events.
    pub preset: Option<RoomPreset>,
    /// An initial topic for the room.
    pub topic: Option<String>,
}

/// A new Matrix room, not yet saved.
#[derive(Debug)]
#[insertable_into(rooms)]
pub struct NewRoom {
    /// The room's unique ID.
    pub id: String,
    /// The ID of the user creating the room.
    pub user_id: String,
    /// Whether or not the room is visible in the directory.
    pub public: bool,
}

/// A Matrix room.
#[derive(Debug, Queryable)]
pub struct Room {
    /// The room's unique ID.
    pub id: String,
    /// The ID of the user who created the room.
    pub user_id: String,
    /// Whether or not the room is visible in the directory.
    pub public: bool,
    /// The time the room was created.
    pub created_at: PgTimestamp,
}

/// A convenience parameter for setting a few default state events.
#[derive(Clone, Copy, Debug, Deserialize)]
pub enum RoomPreset {
    /// `join_rules` is set to `invite` and `history_visibility` is set to `shared`.
    PrivateChat,
    /// `join_rules` is set to `public` and `history_visibility` is set to `shared`.
    PublicChat,
    /// Same as `PrivateChat`, but all initial invitees get the same power level as the creator.
    TrustedPrivateChat,
}

impl Room {
    /// Creates a new room in the database.
    pub fn create(
        connection: &PgConnection,
        new_room: &NewRoom,
        homeserver_domain: &str,
        creation_options: &CreationOptions,
    ) -> Result<Room, APIError> {
        connection.transaction::<Room, APIError, _>(|| {
            let room: Room = insert(new_room)
                .into(rooms::table)
                .get_result(connection)
                .map_err(APIError::from)?;

            if let Some(ref alias) = creation_options.alias {
                let new_room_alias = NewRoomAlias {
                    alias: alias.to_string(),
                    room_id: room.id.clone(),
                    servers: vec![homeserver_domain.to_string()],
                };

                RoomAlias::create(connection, &new_room_alias)?;
            }

            let mut new_events = Vec::new();

            let new_create_event: NewEvent = CreateEvent {
                content: CreateEventContent {
                    creator: new_room.user_id.clone(),
                    federate: creation_options.federate,
                },
                event_id: generate_event_id(),
                event_type: EventType::RoomCreate,
                extra_content: (),
                prev_content: None,
                room_id: room.id.clone(),
                state_key: "".to_string(),
                unsigned: None,
                user_id: new_room.user_id.clone(),
            }.try_into()?;

            new_events.push(new_create_event);

            if let Some(ref name) = creation_options.name {
                let new_name_event: NewEvent = NameEvent {
                    content: NameEventContent {
                        name: name.to_string(),
                    },
                    event_id: generate_event_id(),
                    event_type: EventType::RoomName,
                    extra_content: (),
                    prev_content: None,
                    room_id: room.id.clone(),
                    state_key: "".to_string(),
                    unsigned: None,
                    user_id: new_room.user_id.clone(),
                }.try_into()?;

                new_events.push(new_name_event);
            }

            if let Some(ref topic) = creation_options.topic {
                let new_topic_event: NewEvent = TopicEvent {
                    content: TopicEventContent {
                        topic: topic.to_string(),
                    },
                    event_id: generate_event_id(),
                    event_type: EventType::RoomTopic,
                    extra_content: (),
                    prev_content: None,
                    room_id: room.id.clone(),
                    state_key: "".to_string(),
                    unsigned: None,
                    user_id: new_room.user_id.clone(),
                }.try_into()?;

                new_events.push(new_topic_event);
            }

            if let Some(preset) = creation_options.preset {
                let new_history_visibility_event: NewEvent = HistoryVisibilityEvent {
                    content: HistoryVisibilityEventContent {
                        history_visibility: HistoryVisibility::Shared,
                    },
                    event_id: generate_event_id(),
                    event_type: EventType::RoomHistoryVisibility,
                    extra_content: (),
                    prev_content: None,
                    room_id: room.id.clone(),
                    state_key: "".to_string(),
                    unsigned: None,
                    user_id: new_room.user_id.clone(),
                }.try_into()?;

                new_events.push(new_history_visibility_event);

                match preset {
                    RoomPreset::PrivateChat => {
                        let new_join_rules_event: NewEvent = JoinRulesEvent {
                            content: JoinRulesEventContent {
                                join_rule: JoinRule::Invite,
                            },
                            event_id: generate_event_id(),
                            event_type: EventType::RoomJoinRules,
                            extra_content: (),
                            prev_content: None,
                            room_id: room.id.clone(),
                            state_key: "".to_string(),
                            unsigned: None,
                            user_id: new_room.user_id.clone(),
                        }.try_into()?;

                        new_events.push(new_join_rules_event);
                    }
                    RoomPreset::PublicChat => {
                        let new_join_rules_event: NewEvent = JoinRulesEvent {
                            content: JoinRulesEventContent {
                                join_rule: JoinRule::Public,
                            },
                            event_id: generate_event_id(),
                            event_type: EventType::RoomJoinRules,
                            extra_content: (),
                            prev_content: None,
                            room_id: room.id.clone(),
                            state_key: "".to_string(),
                            unsigned: None,
                            user_id: new_room.user_id.clone(),
                        }.try_into()?;

                        new_events.push(new_join_rules_event);
                    }
                    RoomPreset::TrustedPrivateChat => {
                        let new_join_rules_event: NewEvent = JoinRulesEvent {
                            content: JoinRulesEventContent {
                                join_rule: JoinRule::Invite,
                            },
                            event_id: generate_event_id(),
                            event_type: EventType::RoomJoinRules,
                            extra_content: (),
                            prev_content: None,
                            room_id: room.id.clone(),
                            state_key: "".to_string(),
                            unsigned: None,
                            user_id: new_room.user_id.clone(),
                        }.try_into()?;

                        new_events.push(new_join_rules_event);
                    }
                }
            }

            if let Some(ref invite_list) = creation_options.invite_list {
                let mut user_localparts = HashSet::with_capacity(invite_list.len());

                for invitee in invite_list {
                    let invitee_user_id = UserId::try_from(invitee)?;

                    if invitee_user_id.domain != homeserver_domain {
                        return Err(
                            APIError::unknown_from_string(
                                "Federation is not yet supported.".to_string()
                            )
                        );
                    }

                    user_localparts.insert(invitee_user_id.localpart);
                }

                let users: Vec<User> = users::table
                    .filter(users::id.eq(any(
                        user_localparts.iter().cloned().collect::<Vec<String>>()))
                    )
                    .get_results(connection)
                    .map_err(APIError::from)?;

                let loaded_user_localparts: HashSet<String> = users
                    .iter()
                    .map(|user| user.id.clone())
                    .collect();

                let missing_user_localparts: Vec<String> = user_localparts
                    .difference(&loaded_user_localparts)
                    .cloned()
                    .collect();

                if missing_user_localparts.len() > 0 {
                    return Err(
                        APIError::unknown_from_string(format!(
                            "Unknown users in invite list: {}",
                            &missing_user_localparts.join(", ")
                        ))
                    )
                }

                for user in users {
                    let new_member_event: NewEvent = MemberEvent {
                        content: MemberEventContent {
                            avatar_url: None,
                            displayname: None,
                            membership: MembershipState::Invite,
                            third_party_invite: (),
                        },
                        event_id: generate_event_id(),
                        event_type: EventType::RoomMember,
                        extra_content: MemberEventExtraContent {
                            invite_room_state: None,
                        },
                        prev_content: None,
                        room_id: room.id.clone(),
                        state_key: format!("@{}:{}", user.id, homeserver_domain),
                        unsigned: None,
                        user_id: new_room.user_id.clone(),
                    }.try_into()?;

                    new_events.push(new_member_event);
                }
            }

            insert(&new_events)
                .into(events::table)
                .execute(connection)
                .map_err(APIError::from)?;

            Ok(room)
        }).map_err(APIError::from)
    }

    /// Generate a random room ID.
    pub fn generate_room_id() -> String {
        thread_rng().gen_ascii_chars().take(12).collect()
    }
}
<|endoftext|>


<commit_before>extern crate farmhash;
extern crate byteorder;

use std::io::Cursor;
use self::byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
use bucket::{Fingerprint};

pub fn get_hash(data: &[u8]) -> Vec<u8> {
    let hash32 = farmhash::hash32(data);
    let mut hash = vec![];
    hash.write_u32::<BigEndian>(hash32).unwrap();
    return hash;
}

pub fn get_alt_index(fp: &Fingerprint, i: usize) -> usize {
    let hash = get_hash(&[fp.0]);
    let mut rdr = Cursor::new(hash);
    let alt_i = rdr.read_u32::<BigEndian>().unwrap() as usize;
    return (i ^ alt_i) as usize;
}

pub struct FaI {
    pub fp: Fingerprint,
    pub i1: usize,
    pub i2: usize
}

pub fn get_fai(data: &[u8]) -> FaI {
    let hash = get_hash(data);
    let f = Fingerprint(hash[0]);
    let mut rdr = Cursor::new(hash);
    let i1 = rdr.read_u32::<BigEndian>().unwrap() as usize;
    let i2 = get_alt_index(&f, i1);
    return FaI {
        fp: f, i1: i1, i2: i2
    }
}

#[test]
fn test_fp_and_index() {
    let data = &"seif".as_bytes();
    let fai = get_fai(data);
    let fp = &fai.fp;
    let i1 = fai.i1;
    let i2 = fai.i2;
    let i11 = get_alt_index(fp, i2);
    assert_eq!(i11, i1);

    let i22 = get_alt_index(fp, i11);
    assert_eq!(i22, i2);
}
<commit_msg>Removed unneeded 'return' statements.<commit_after>extern crate farmhash;
extern crate byteorder;

use std::io::Cursor;
use self::byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
use bucket::{Fingerprint};

pub fn get_hash(data: &[u8]) -> Vec<u8> {
    let hash32 = farmhash::hash32(data);
    let mut hash = vec![];
    hash.write_u32::<BigEndian>(hash32).unwrap();
    hash
}

pub fn get_alt_index(fp: &Fingerprint, i: usize) -> usize {
    let hash = get_hash(&[fp.0]);
    let mut rdr = Cursor::new(hash);
    let alt_i = rdr.read_u32::<BigEndian>().unwrap() as usize;
    (i ^ alt_i) as usize
}

pub struct FaI {
    pub fp: Fingerprint,
    pub i1: usize,
    pub i2: usize
}

pub fn get_fai(data: &[u8]) -> FaI {
    let hash = get_hash(data);
    let f = Fingerprint(hash[0]);
    let mut rdr = Cursor::new(hash);
    let i1 = rdr.read_u32::<BigEndian>().unwrap() as usize;
    let i2 = get_alt_index(&f, i1);
    FaI {
        fp: f, i1: i1, i2: i2
    }
}

#[test]
fn test_fp_and_index() {
    let data = &"seif".as_bytes();
    let fai = get_fai(data);
    let fp = &fai.fp;
    let i1 = fai.i1;
    let i2 = fai.i2;
    let i11 = get_alt_index(fp, i2);
    assert_eq!(i11, i1);

    let i22 = get_alt_index(fp, i11);
    assert_eq!(i22, i2);
}
<|endoftext|>


<commit_before>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Miscellaneous utilities for low level networking

extern crate libc;

use packet::PrimitiveValues;
use packet::ip::IpNextHeaderProtocol;
use datalink::NetworkInterface;
use pnet_macros_support::types::u16be;

use std::fmt;
use std::str::FromStr;
use std::u8;
use std::net::{IpAddr, Ipv4Addr};
use std::mem;
use std::slice;

use internal;
use sockets;

/// A MAC address
#[derive(PartialEq, Eq, Clone, Copy, Hash)]
pub struct MacAddr(pub u8, pub u8, pub u8, pub u8, pub u8, pub u8);

impl MacAddr {
    /// Construct a new MacAddr
    pub fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> MacAddr {
        MacAddr(a, b, c, d, e, f)
    }
}

impl PrimitiveValues for MacAddr {
    type T = (u8, u8, u8, u8, u8, u8);
    fn to_primitive_values(&self) -> (u8, u8, u8, u8, u8, u8) {
        (self.0, self.1, self.2, self.3, self.4, self.5)
    }
}

impl fmt::Display for MacAddr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt,
               "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
               self.0,
               self.1,
               self.2,
               self.3,
               self.4,
               self.5)
    }
}

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

// FIXME Is this the right way to do this? Which occurs is an implementation
//       issue rather than actually defined - is it useful to provide these
//       errors, or would it be better to just give ()?
/// Represents an error which occurred whilst parsing a MAC address
#[derive(Copy, Debug, PartialEq, Eq, Clone)]
pub enum ParseMacAddrErr {
    /// The MAC address has too many components, eg. 00:11:22:33:44:55:66
    TooManyComponents,
    /// The MAC address has too few components, eg. 00:11
    TooFewComponents,
    /// One of the components contains an invalid value, eg. 00:GG:22:33:44:55
    InvalidComponent,
}

impl FromStr for MacAddr {
    type Err = ParseMacAddrErr;
    fn from_str(s: &str) -> Result<MacAddr, ParseMacAddrErr> {
        let mut parts = [0u8; 6];
        let splits = s.split(':');
        let mut i = 0;
        for split in splits {
            if i == 6 {
                return Err(ParseMacAddrErr::TooManyComponents);
            }
            match u8::from_str_radix(split, 16) {
                Ok(b) if split.len() != 0 => parts[i] = b,
                _ => return Err(ParseMacAddrErr::InvalidComponent),
            }
            i += 1;
        }

        if i == 6 {
            Ok(MacAddr(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5]))
        } else {
            Err(ParseMacAddrErr::TooFewComponents)
        }
    }
}

#[test]
fn mac_addr_from_str() {
    assert_eq!("00:00:00:00:00:00".parse(), Ok(MacAddr(0, 0, 0, 0, 0, 0)));
    assert_eq!("ff:ff:ff:ff:ff:ff".parse(),
               Ok(MacAddr(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)));
    assert_eq!("12:34:56:78:90:ab".parse(),
               Ok(MacAddr(0x12, 0x34, 0x56, 0x78, 0x90, 0xAB)));
    assert_eq!("::::::".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("0::::::".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("::::0::".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("12:34:56:78".parse::<MacAddr>(),
               Err(ParseMacAddrErr::TooFewComponents));
    assert_eq!("12:34:56:78:".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("12:34:56:78:90".parse::<MacAddr>(),
               Err(ParseMacAddrErr::TooFewComponents));
    assert_eq!("12:34:56:78:90:".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("12:34:56:78:90:00:00".parse::<MacAddr>(),
               Err(ParseMacAddrErr::TooManyComponents));
    assert_eq!("xx:xx:xx:xx:xx:xx".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
}

#[cfg(target_os = "linux")]
fn sockaddr_to_network_addr(sa: *const sockets::SockAddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use std::net::SocketAddr;

    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == libc::AF_PACKET {
            let sll: *const libc::sockaddr_ll = mem::transmute(sa);
            let mac = MacAddr((*sll).sll_addr[0],
                              (*sll).sll_addr[1],
                              (*sll).sll_addr[2],
                              (*sll).sll_addr[3],
                              (*sll).sll_addr[4],
                              (*sll).sll_addr[5]);

            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                                  mem::size_of::<sockets::SockAddrStorage>());

            match addr {
                Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))),
                Ok(SocketAddr::V6(sa)) => (None, Some(IpAddr::V6(*sa.ip()))),
                Err(_) => (None, None),
            }
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "macos"))]
fn sockaddr_to_network_addr(sa: *const sockets::SockAddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use bindings::bpf;
    use std::net::SocketAddr;

    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == bpf::AF_LINK {
            let sdl: *const bpf::sockaddr_dl = mem::transmute(sa);
            let nlen = (*sdl).sdl_nlen as usize;
            let mac = MacAddr((*sdl).sdl_data[nlen] as u8,
                              (*sdl).sdl_data[nlen + 1] as u8,
                              (*sdl).sdl_data[nlen + 2] as u8,
                              (*sdl).sdl_data[nlen + 3] as u8,
                              (*sdl).sdl_data[nlen + 4] as u8,
                              (*sdl).sdl_data[nlen + 5] as u8);

            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                                  mem::size_of::<sockets::SockAddrStorage>());

            match addr {
                Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))),
                Ok(SocketAddr::V6(sa)) => (None, Some(IpAddr::V6(*sa.ip()))),
                Err(_) => (None, None),
            }
        }
    }
}

/// Get a list of available network interfaces for the current machine.
/// Deprecated. Instead use the implementation available for your backend.
/// The default one is at `pnet::datalink::interfaces`.
#[deprecated(note="Moved to datalink::interfaces()")]
#[inline]
pub fn get_network_interfaces() -> Vec<NetworkInterface> {
    ::datalink::interfaces()
}

/// Convert value to byte array
pub trait Octets {
    /// Output type - bytes array
    type Output;

    /// Return value as bytes (big-endian order)
    fn octets(&self) -> Self::Output;
}

impl Octets for u64 {
    type Output = [u8; 8];

    fn octets(&self) -> Self::Output {
        [(*self >> 56) as u8, (*self >> 48) as u8, (*self >> 40) as u8, (*self >> 32) as u8,
         (*self >> 24) as u8, (*self >> 16) as u8, (*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u32 {
    type Output = [u8; 4];

    fn octets(&self) -> Self::Output {
        [(*self >> 24) as u8, (*self >> 16) as u8 , (*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u16 {
    type Output = [u8; 2];

    fn octets(&self) -> Self::Output {
        [(*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u8 {
    type Output = [u8; 1];

    fn octets(&self) -> Self::Output {
        [*self]
    }
}

/// Calculates a checksum. Used by ipv4 and icmp. The two bytes starting at `skipword * 2` will be
/// ignored. Supposed to be the checksum field, which is regarded as zero during calculation.
pub fn checksum(data: &[u8], skipword: Option<usize>) -> u16be {
    let mut sum = sum_be_words(data, skipword);
    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }
    !sum as u16
}

/// Calculate the checksum for a packet built on IPv4. Used by udp and tcp.
pub fn ipv4_checksum(data: &[u8],
                     ipv4_source: Ipv4Addr,
                     ipv4_destination: Ipv4Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv4_word_sum(ipv4_source);
    sum += ipv4_word_sum(ipv4_destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    sum += data.len() as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, None);

    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }

    !sum as u16
}

fn ipv4_word_sum(ip: Ipv4Addr) -> u32 {
    let octets = ip.octets();
    ((octets[0] as u32) << 8 | octets[1] as u32) + ((octets[2] as u32) << 8 | octets[3] as u32)
}

/// Sum all words (16 bit chunks) in the given data. The word at word offset `skipword` will be
/// ignored if passed. Each word is treated as big endian.
fn sum_be_words(data: &[u8], skipword: Option<usize>) -> u32 {
    let len = data.len();
    let wdata: &[u16] = unsafe { slice::from_raw_parts(data.as_ptr() as *const u16, len / 2) };

    let mut sum = 0u32;
    let mut i = 0;
    if let Some(skipword) = skipword {
        assert!(skipword <= wdata.len());
        while i < skipword {
            sum += u16::from_be(unsafe { *wdata.get_unchecked(i) }) as u32;
            i += 1;
        }
        i += 1;
    }
    while i < wdata.len() {
        sum += u16::from_be(unsafe { *wdata.get_unchecked(i) }) as u32;
        i += 1;
    }
    // If the length is odd, make sure to checksum the final byte
    if len & 1 != 0 {
        sum += (data[len - 1] as u32) << 8;
    }

    sum
}

#[cfg(all(test, feature = "benchmark"))]
mod checksum_benchmarks {
    use super::checksum;
    use test::{Bencher, black_box};

    #[bench]
    fn bench_checksum_small(b: &mut Bencher) {
        let data = vec![99u8; 20];
        b.iter(|| checksum(black_box(&data), Some(5)));
    }

    #[bench]
    fn bench_checksum_large(b: &mut Bencher) {
        let data = vec![123u8; 1024];
        b.iter(|| checksum(black_box(&data), Some(5)));
    }
}
<commit_msg>Remove one more bounds check<commit_after>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Miscellaneous utilities for low level networking

extern crate libc;

use packet::PrimitiveValues;
use packet::ip::IpNextHeaderProtocol;
use datalink::NetworkInterface;
use pnet_macros_support::types::u16be;

use std::fmt;
use std::str::FromStr;
use std::u8;
use std::net::{IpAddr, Ipv4Addr};
use std::mem;
use std::slice;

use internal;
use sockets;

/// A MAC address
#[derive(PartialEq, Eq, Clone, Copy, Hash)]
pub struct MacAddr(pub u8, pub u8, pub u8, pub u8, pub u8, pub u8);

impl MacAddr {
    /// Construct a new MacAddr
    pub fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> MacAddr {
        MacAddr(a, b, c, d, e, f)
    }
}

impl PrimitiveValues for MacAddr {
    type T = (u8, u8, u8, u8, u8, u8);
    fn to_primitive_values(&self) -> (u8, u8, u8, u8, u8, u8) {
        (self.0, self.1, self.2, self.3, self.4, self.5)
    }
}

impl fmt::Display for MacAddr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt,
               "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
               self.0,
               self.1,
               self.2,
               self.3,
               self.4,
               self.5)
    }
}

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

// FIXME Is this the right way to do this? Which occurs is an implementation
//       issue rather than actually defined - is it useful to provide these
//       errors, or would it be better to just give ()?
/// Represents an error which occurred whilst parsing a MAC address
#[derive(Copy, Debug, PartialEq, Eq, Clone)]
pub enum ParseMacAddrErr {
    /// The MAC address has too many components, eg. 00:11:22:33:44:55:66
    TooManyComponents,
    /// The MAC address has too few components, eg. 00:11
    TooFewComponents,
    /// One of the components contains an invalid value, eg. 00:GG:22:33:44:55
    InvalidComponent,
}

impl FromStr for MacAddr {
    type Err = ParseMacAddrErr;
    fn from_str(s: &str) -> Result<MacAddr, ParseMacAddrErr> {
        let mut parts = [0u8; 6];
        let splits = s.split(':');
        let mut i = 0;
        for split in splits {
            if i == 6 {
                return Err(ParseMacAddrErr::TooManyComponents);
            }
            match u8::from_str_radix(split, 16) {
                Ok(b) if split.len() != 0 => parts[i] = b,
                _ => return Err(ParseMacAddrErr::InvalidComponent),
            }
            i += 1;
        }

        if i == 6 {
            Ok(MacAddr(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5]))
        } else {
            Err(ParseMacAddrErr::TooFewComponents)
        }
    }
}

#[test]
fn mac_addr_from_str() {
    assert_eq!("00:00:00:00:00:00".parse(), Ok(MacAddr(0, 0, 0, 0, 0, 0)));
    assert_eq!("ff:ff:ff:ff:ff:ff".parse(),
               Ok(MacAddr(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)));
    assert_eq!("12:34:56:78:90:ab".parse(),
               Ok(MacAddr(0x12, 0x34, 0x56, 0x78, 0x90, 0xAB)));
    assert_eq!("::::::".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("0::::::".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("::::0::".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("12:34:56:78".parse::<MacAddr>(),
               Err(ParseMacAddrErr::TooFewComponents));
    assert_eq!("12:34:56:78:".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("12:34:56:78:90".parse::<MacAddr>(),
               Err(ParseMacAddrErr::TooFewComponents));
    assert_eq!("12:34:56:78:90:".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
    assert_eq!("12:34:56:78:90:00:00".parse::<MacAddr>(),
               Err(ParseMacAddrErr::TooManyComponents));
    assert_eq!("xx:xx:xx:xx:xx:xx".parse::<MacAddr>(),
               Err(ParseMacAddrErr::InvalidComponent));
}

#[cfg(target_os = "linux")]
fn sockaddr_to_network_addr(sa: *const sockets::SockAddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use std::net::SocketAddr;

    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == libc::AF_PACKET {
            let sll: *const libc::sockaddr_ll = mem::transmute(sa);
            let mac = MacAddr((*sll).sll_addr[0],
                              (*sll).sll_addr[1],
                              (*sll).sll_addr[2],
                              (*sll).sll_addr[3],
                              (*sll).sll_addr[4],
                              (*sll).sll_addr[5]);

            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                                  mem::size_of::<sockets::SockAddrStorage>());

            match addr {
                Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))),
                Ok(SocketAddr::V6(sa)) => (None, Some(IpAddr::V6(*sa.ip()))),
                Err(_) => (None, None),
            }
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "macos"))]
fn sockaddr_to_network_addr(sa: *const sockets::SockAddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use bindings::bpf;
    use std::net::SocketAddr;

    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == bpf::AF_LINK {
            let sdl: *const bpf::sockaddr_dl = mem::transmute(sa);
            let nlen = (*sdl).sdl_nlen as usize;
            let mac = MacAddr((*sdl).sdl_data[nlen] as u8,
                              (*sdl).sdl_data[nlen + 1] as u8,
                              (*sdl).sdl_data[nlen + 2] as u8,
                              (*sdl).sdl_data[nlen + 3] as u8,
                              (*sdl).sdl_data[nlen + 4] as u8,
                              (*sdl).sdl_data[nlen + 5] as u8);

            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                                  mem::size_of::<sockets::SockAddrStorage>());

            match addr {
                Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))),
                Ok(SocketAddr::V6(sa)) => (None, Some(IpAddr::V6(*sa.ip()))),
                Err(_) => (None, None),
            }
        }
    }
}

/// Get a list of available network interfaces for the current machine.
/// Deprecated. Instead use the implementation available for your backend.
/// The default one is at `pnet::datalink::interfaces`.
#[deprecated(note="Moved to datalink::interfaces()")]
#[inline]
pub fn get_network_interfaces() -> Vec<NetworkInterface> {
    ::datalink::interfaces()
}

/// Convert value to byte array
pub trait Octets {
    /// Output type - bytes array
    type Output;

    /// Return value as bytes (big-endian order)
    fn octets(&self) -> Self::Output;
}

impl Octets for u64 {
    type Output = [u8; 8];

    fn octets(&self) -> Self::Output {
        [(*self >> 56) as u8, (*self >> 48) as u8, (*self >> 40) as u8, (*self >> 32) as u8,
         (*self >> 24) as u8, (*self >> 16) as u8, (*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u32 {
    type Output = [u8; 4];

    fn octets(&self) -> Self::Output {
        [(*self >> 24) as u8, (*self >> 16) as u8 , (*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u16 {
    type Output = [u8; 2];

    fn octets(&self) -> Self::Output {
        [(*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u8 {
    type Output = [u8; 1];

    fn octets(&self) -> Self::Output {
        [*self]
    }
}

/// Calculates a checksum. Used by ipv4 and icmp. The two bytes starting at `skipword * 2` will be
/// ignored. Supposed to be the checksum field, which is regarded as zero during calculation.
pub fn checksum(data: &[u8], skipword: Option<usize>) -> u16be {
    let mut sum = sum_be_words(data, skipword);
    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }
    !sum as u16
}

/// Calculate the checksum for a packet built on IPv4. Used by udp and tcp.
pub fn ipv4_checksum(data: &[u8],
                     ipv4_source: Ipv4Addr,
                     ipv4_destination: Ipv4Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv4_word_sum(ipv4_source);
    sum += ipv4_word_sum(ipv4_destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    sum += data.len() as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, None);

    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }

    !sum as u16
}

fn ipv4_word_sum(ip: Ipv4Addr) -> u32 {
    let octets = ip.octets();
    ((octets[0] as u32) << 8 | octets[1] as u32) + ((octets[2] as u32) << 8 | octets[3] as u32)
}

/// Sum all words (16 bit chunks) in the given data. The word at word offset `skipword` will be
/// ignored if passed. Each word is treated as big endian.
fn sum_be_words(data: &[u8], skipword: Option<usize>) -> u32 {
    let len = data.len();
    let wdata: &[u16] = unsafe { slice::from_raw_parts(data.as_ptr() as *const u16, len / 2) };

    let mut sum = 0u32;
    let mut i = 0;
    if let Some(skipword) = skipword {
        assert!(skipword <= wdata.len());
        while i < skipword {
            sum += u16::from_be(unsafe { *wdata.get_unchecked(i) }) as u32;
            i += 1;
        }
        i += 1;
    }
    while i < wdata.len() {
        sum += u16::from_be(unsafe { *wdata.get_unchecked(i) }) as u32;
        i += 1;
    }
    // If the length is odd, make sure to checksum the final byte
    if len & 1 != 0 {
        sum += (unsafe { *data.get_unchecked(len - 1) } as u32) << 8;
    }

    sum
}

#[cfg(all(test, feature = "benchmark"))]
mod checksum_benchmarks {
    use super::checksum;
    use test::{Bencher, black_box};

    #[bench]
    fn bench_checksum_small(b: &mut Bencher) {
        let data = vec![99u8; 20];
        b.iter(|| checksum(black_box(&data), Some(5)));
    }

    #[bench]
    fn bench_checksum_large(b: &mut Bencher) {
        let data = vec![123u8; 1024];
        b.iter(|| checksum(black_box(&data), Some(5)));
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use texturegl::Texture;

use geom::matrix::{Matrix4, identity};
use geom::size::Size2D;
use geom::rect::Rect;
use std::cell::RefCell;
use std::rc::Rc;

pub enum Format {
    ARGB32Format,
    RGB24Format
}

#[deriving(Clone)]
pub enum Layer {
    ContainerLayerKind(Rc<ContainerLayer>),
    TextureLayerKind(Rc<TextureLayer>),
}

impl Layer {
    pub fn with_common<T>(&self, f: |&mut CommonLayer| -> T) -> T {
        match *self {
            ContainerLayerKind(ref container_layer) => {
                f(&mut *container_layer.common.borrow_mut())
            },
            TextureLayerKind(ref texture_layer) => {
                f(&mut *texture_layer.common.borrow_mut())
            },
        }
    }
}

pub struct CommonLayer {
    pub parent: Option<Layer>,
    pub prev_sibling: Option<Layer>,
    pub next_sibling: Option<Layer>,

    pub transform: Matrix4<f32>,
}

impl CommonLayer {
    // FIXME: Workaround for cross-crate bug regarding mutability of class fields
    pub fn set_transform(&mut self, new_transform: Matrix4<f32>) {
        self.transform = new_transform;
    }
}

pub fn CommonLayer() -> CommonLayer {
    CommonLayer {
        parent: None,
        prev_sibling: None,
        next_sibling: None,
        transform: identity(),
    }
}

pub struct ContainerLayer {
    pub common: RefCell<CommonLayer>,
    pub first_child: RefCell<Option<Layer>>,
    pub last_child: RefCell<Option<Layer>>,
    pub scissor: RefCell<Option<Rect<f32>>>,
}

pub fn ContainerLayer() -> ContainerLayer {
    ContainerLayer {
        common: RefCell::new(CommonLayer()),
        first_child: RefCell::new(None),
        last_child: RefCell::new(None),
        scissor: RefCell::new(None),
    }
}

pub struct ChildIterator {
    current: Option<Layer>,
}

impl Iterator<Layer> for ChildIterator {
    fn next(&mut self) -> Option<Layer> {
        let (new_current, result) =
            match self.current {
                None => (None, None),
                Some(ref child) => {
                    (child.with_common(|x| x.next_sibling.clone()),
                     Some(child.clone()))
                }
            };
        self.current = new_current;
        result
    }
}

impl ContainerLayer {
    pub fn children(&self) -> ChildIterator {
        ChildIterator {
            current: self.first_child.borrow().clone(),
        }
    }

    /// Adds a child to the beginning of the list.
    /// Only works when the child is disconnected from the layer tree.
    pub fn add_child_start(pseudo_self: Rc<ContainerLayer>, new_child: Layer) {
        new_child.with_common(|new_child_common| {
            assert!(new_child_common.parent.is_none());
            assert!(new_child_common.prev_sibling.is_none());
            assert!(new_child_common.next_sibling.is_none());

            new_child_common.parent = Some(ContainerLayerKind(pseudo_self.clone()));

            match *pseudo_self.first_child.borrow() {
                None => {}
                Some(ref first_child) => {
                    first_child.with_common(|first_child_common| {
                        assert!(first_child_common.prev_sibling.is_none());
                        first_child_common.prev_sibling = Some(new_child.clone());
                        new_child_common.next_sibling = Some(first_child.clone());
                    });
                }
            }

            *pseudo_self.first_child.borrow_mut() = Some(new_child.clone());

            let should_set = pseudo_self.last_child.borrow().is_none();
            if should_set {
                *pseudo_self.last_child.borrow_mut() = Some(new_child.clone());
            }
        });
    }

    /// Adds a child to the end of the list.
    /// Only works when the child is disconnected from the layer tree.
    pub fn add_child_end(pseudo_self: Rc<ContainerLayer>, new_child: Layer) {
        new_child.with_common(|new_child_common| {
            assert!(new_child_common.parent.is_none());
            assert!(new_child_common.prev_sibling.is_none());
            assert!(new_child_common.next_sibling.is_none());

            new_child_common.parent = Some(ContainerLayerKind(pseudo_self.clone()));

            match *pseudo_self.last_child.borrow() {
                None => {}
                Some(ref last_child) => {
                    last_child.with_common(|last_child_common| {
                        assert!(last_child_common.next_sibling.is_none());
                        last_child_common.next_sibling = Some(new_child.clone());
                        new_child_common.prev_sibling = Some(last_child.clone());
                    });
                }
            }

            *pseudo_self.last_child.borrow_mut() = Some(new_child.clone());

            let mut child = pseudo_self.first_child.borrow_mut();
            match *child {
                Some(_) => {},
                None => *child = Some(new_child.clone()),
            }
        });
    }

    pub fn remove_child(pseudo_self: Rc<ContainerLayer>, child: Layer) {
        child.with_common(|child_common| {
            assert!(child_common.parent.is_some());
            match child_common.parent {
                Some(ContainerLayerKind(ref container)) => {
                    assert!(container.deref() as *ContainerLayer ==
                            pseudo_self.deref() as *ContainerLayer);
                },
                _ => fail!("Invalid parent of child in layer tree"),
            }

            match child_common.next_sibling {
                None => { // this is the last child
                    *pseudo_self.last_child.borrow_mut() = child_common.prev_sibling.clone();
                },
                Some(ref sibling) => {
                    sibling.with_common(|sibling_common| {
                        sibling_common.prev_sibling = child_common.prev_sibling.clone();
                    });
                }
            }
            match child_common.prev_sibling {
                None => { // this is the first child
                    *pseudo_self.first_child.borrow_mut() = child_common.next_sibling.clone();
                },
                Some(ref sibling) => {
                    sibling.with_common(|sibling_common| {
                        sibling_common.next_sibling = child_common.next_sibling.clone();
                    });
                }
            }
        });
    }
}

/// Whether a texture should be flipped.
#[deriving(Eq)]
pub enum Flip {
    /// The texture should not be flipped.
    NoFlip,
    /// The texture should be flipped vertically.
    VerticalFlip,
}

pub struct TextureLayer {
    pub common: RefCell<CommonLayer>,
    /// A handle to the GPU texture.
    pub texture: Texture,
    /// The size of the texture in pixels.
    size: Size2D<uint>,
    /// Whether this texture is flipped vertically.
    pub flip: Flip,
}

impl TextureLayer {
    pub fn new(texture: Texture, size: Size2D<uint>, flip: Flip) -> TextureLayer {
        TextureLayer {
            common: RefCell::new(CommonLayer()),
            texture: texture,
            size: size,
            flip: flip,
        }
    }
}

<commit_msg>Add ContainerLayer::remove_all_children method<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use texturegl::Texture;

use geom::matrix::{Matrix4, identity};
use geom::size::Size2D;
use geom::rect::Rect;
use std::cell::RefCell;
use std::rc::Rc;

pub enum Format {
    ARGB32Format,
    RGB24Format
}

#[deriving(Clone)]
pub enum Layer {
    ContainerLayerKind(Rc<ContainerLayer>),
    TextureLayerKind(Rc<TextureLayer>),
}

impl Layer {
    pub fn with_common<T>(&self, f: |&mut CommonLayer| -> T) -> T {
        match *self {
            ContainerLayerKind(ref container_layer) => {
                f(&mut *container_layer.common.borrow_mut())
            },
            TextureLayerKind(ref texture_layer) => {
                f(&mut *texture_layer.common.borrow_mut())
            },
        }
    }
}

pub struct CommonLayer {
    pub parent: Option<Layer>,
    pub prev_sibling: Option<Layer>,
    pub next_sibling: Option<Layer>,

    pub transform: Matrix4<f32>,
}

impl CommonLayer {
    // FIXME: Workaround for cross-crate bug regarding mutability of class fields
    pub fn set_transform(&mut self, new_transform: Matrix4<f32>) {
        self.transform = new_transform;
    }
}

pub fn CommonLayer() -> CommonLayer {
    CommonLayer {
        parent: None,
        prev_sibling: None,
        next_sibling: None,
        transform: identity(),
    }
}

pub struct ContainerLayer {
    pub common: RefCell<CommonLayer>,
    pub first_child: RefCell<Option<Layer>>,
    pub last_child: RefCell<Option<Layer>>,
    pub scissor: RefCell<Option<Rect<f32>>>,
}

pub fn ContainerLayer() -> ContainerLayer {
    ContainerLayer {
        common: RefCell::new(CommonLayer()),
        first_child: RefCell::new(None),
        last_child: RefCell::new(None),
        scissor: RefCell::new(None),
    }
}

pub struct ChildIterator {
    current: Option<Layer>,
}

impl Iterator<Layer> for ChildIterator {
    fn next(&mut self) -> Option<Layer> {
        let (new_current, result) =
            match self.current {
                None => (None, None),
                Some(ref child) => {
                    (child.with_common(|x| x.next_sibling.clone()),
                     Some(child.clone()))
                }
            };
        self.current = new_current;
        result
    }
}

impl ContainerLayer {
    pub fn children(&self) -> ChildIterator {
        ChildIterator {
            current: self.first_child.borrow().clone(),
        }
    }

    /// Adds a child to the beginning of the list.
    /// Only works when the child is disconnected from the layer tree.
    pub fn add_child_start(pseudo_self: Rc<ContainerLayer>, new_child: Layer) {
        new_child.with_common(|new_child_common| {
            assert!(new_child_common.parent.is_none());
            assert!(new_child_common.prev_sibling.is_none());
            assert!(new_child_common.next_sibling.is_none());

            new_child_common.parent = Some(ContainerLayerKind(pseudo_self.clone()));

            match *pseudo_self.first_child.borrow() {
                None => {}
                Some(ref first_child) => {
                    first_child.with_common(|first_child_common| {
                        assert!(first_child_common.prev_sibling.is_none());
                        first_child_common.prev_sibling = Some(new_child.clone());
                        new_child_common.next_sibling = Some(first_child.clone());
                    });
                }
            }

            *pseudo_self.first_child.borrow_mut() = Some(new_child.clone());

            let should_set = pseudo_self.last_child.borrow().is_none();
            if should_set {
                *pseudo_self.last_child.borrow_mut() = Some(new_child.clone());
            }
        });
    }

    /// Adds a child to the end of the list.
    /// Only works when the child is disconnected from the layer tree.
    pub fn add_child_end(pseudo_self: Rc<ContainerLayer>, new_child: Layer) {
        new_child.with_common(|new_child_common| {
            assert!(new_child_common.parent.is_none());
            assert!(new_child_common.prev_sibling.is_none());
            assert!(new_child_common.next_sibling.is_none());

            new_child_common.parent = Some(ContainerLayerKind(pseudo_self.clone()));

            match *pseudo_self.last_child.borrow() {
                None => {}
                Some(ref last_child) => {
                    last_child.with_common(|last_child_common| {
                        assert!(last_child_common.next_sibling.is_none());
                        last_child_common.next_sibling = Some(new_child.clone());
                        new_child_common.prev_sibling = Some(last_child.clone());
                    });
                }
            }

            *pseudo_self.last_child.borrow_mut() = Some(new_child.clone());

            let mut child = pseudo_self.first_child.borrow_mut();
            match *child {
                Some(_) => {},
                None => *child = Some(new_child.clone()),
            }
        });
    }

    pub fn remove_child(pseudo_self: Rc<ContainerLayer>, child: Layer) {
        child.with_common(|child_common| {
            assert!(child_common.parent.is_some());
            match child_common.parent {
                Some(ContainerLayerKind(ref container)) => {
                    assert!(container.deref() as *ContainerLayer ==
                            pseudo_self.deref() as *ContainerLayer);
                },
                _ => fail!("Invalid parent of child in layer tree"),
            }

            match child_common.next_sibling {
                None => { // this is the last child
                    *pseudo_self.last_child.borrow_mut() = child_common.prev_sibling.clone();
                },
                Some(ref sibling) => {
                    sibling.with_common(|sibling_common| {
                        sibling_common.prev_sibling = child_common.prev_sibling.clone();
                    });
                }
            }
            match child_common.prev_sibling {
                None => { // this is the first child
                    *pseudo_self.first_child.borrow_mut() = child_common.next_sibling.clone();
                },
                Some(ref sibling) => {
                    sibling.with_common(|sibling_common| {
                        sibling_common.next_sibling = child_common.next_sibling.clone();
                    });
                }
            }
        });
    }

    pub fn remove_all_children(&self) {
        *self.first_child.borrow_mut() = None;
        *self.last_child.borrow_mut() = None;
    }
}

/// Whether a texture should be flipped.
#[deriving(Eq)]
pub enum Flip {
    /// The texture should not be flipped.
    NoFlip,
    /// The texture should be flipped vertically.
    VerticalFlip,
}

pub struct TextureLayer {
    pub common: RefCell<CommonLayer>,
    /// A handle to the GPU texture.
    pub texture: Texture,
    /// The size of the texture in pixels.
    size: Size2D<uint>,
    /// Whether this texture is flipped vertically.
    pub flip: Flip,
}

impl TextureLayer {
    pub fn new(texture: Texture, size: Size2D<uint>, flip: Flip) -> TextureLayer {
        TextureLayer {
            common: RefCell::new(CommonLayer()),
            texture: texture,
            size: size,
            flip: flip,
        }
    }
}

<|endoftext|>


<commit_before>extern mod extra;
extern mod std;

use std::hashmap::HashMap;
use std::path::PosixPath;

use std::io::{File,result, IoError};
use std::io::mem::BufReader;

use std::num::FromPrimitive;

use std::str::from_utf8_owned_opt;

use extra::future::Future;
use extra::arc::Arc;

mod class;
mod def;

fn build_classpath(invar : &str) -> ~[~str] {
	// current folder is always included
	let mut v = ~[~"."];

	// TODO: how to construct a vector directly from an iter?
	for s in invar.split_str(";")
		.map(|s : &str| { s.trim().to_owned() })
		.filter(|s : &~str| {s.len() > 0}){

		v.push(s);
	}
	return v;
}

pub struct ClassLoader {
	priv classpath : ~[~str],
	priv classes : HashMap<~str, ~class::JavaClass>
}

static INITIAL_CLASSLOADER_CAPACITY : uint = 1024;

impl ClassLoader {

	// ----------------------------------------------
	// Constructs a ClassLoader given a CLASSPATH that consists of one or
	// more .class search paths separated by semicolons.
	pub fn new(classpath : &str) -> ~ClassLoader {
		~ClassLoader {
			classpath : build_classpath(classpath),
			classes : HashMap::with_capacity(INITIAL_CLASSLOADER_CAPACITY),
		}
	}

	// ----------------------------------------------
	// Loads a class given its fully qualified class name.
	//
	// This triggers recursive loading of dependent classes.
	//
	// add_from_classfile("de.fruits.Apple") loads <class-path>/de/fruits/Apple.class
	pub fn add_from_classfile(self, name : &str) ->
		Future<
			Result<Arc<class::JavaClass>,~str>
		>
	{
		let cname = name.to_owned();
		let pname = cname.replace(&".", "/") + ".class";
		do Future::spawn {
			for path in self.classpath.iter() {

				match result(|| {
					let p = *path + "/" + pname;
					debug!("load class {}, trying path {}", cname, p);
					File::open(&PosixPath::new(p)).read_to_end()
				}) {
					Err(e) => continue,
					Ok(bytes) => return self.add_from_classfile_bytes(bytes)
						.unwrap()
				};
			}
			return Err(~"failed to locate class file for " + cname);
		}
	}

	// IMPL

	// ----------------------------------------------
	fn add_from_classfile_bytes(self, bytes : ~[u8]) ->
		Future<
			Result<Arc<class::JavaClass>,~str>
		>
	{
		do Future::spawn {
			match result(|| {
				let mut reader = BufReader::new(bytes);

				let magic = reader.read_be_u32() as uint;
				let major = reader.read_be_u16() as uint;
				let minor = reader.read_be_u16() as uint;
				let cpool_count = reader.read_be_u16() as uint;
				if cpool_count == 0 {
					return Err(~"invalid constant pool size");
				}

				let mut constants : ~[def::Constant] = ~[];

				// read constant pool
				let mut i = cpool_count - 1 as uint;
				while i > 0 {
					let tag = reader.read_u8();
					let parsed_tag : Option<def::ConstantPoolTags> =
						FromPrimitive::from_u8(tag);

					let mut skip = 0;
					let maybe_centry = match parsed_tag {
						None => Err(format!("constant pool tag not recognized: {}", tag)),
						Some(c) => {
							ClassLoader::read_cpool_entry_body(c,
								&mut reader as &mut Reader,
								cpool_count as uint,
								&mut skip
							)
						}
					};

					// if that was ok, add it to the list and advance
					match maybe_centry {
						Err(e) => return Err(e),
						Ok(centry) => constants.push(centry)
					}

					assert!(i > skip);
					i -= skip;

					--i;
				}

				let access = reader.read_be_u16() as uint;
				let this_class = reader.read_be_u16() as uint;
				let super_class = reader.read_be_u16() as uint;
				let ifaces_count = reader.read_be_u16() as uint;

				// read interfaces

				let fields_count = reader.read_be_u16() as uint;
				let methods_count = reader.read_be_u16() as uint;

				// read methods

				let attrs_count = reader.read_be_u16() as uint;

				// read attributes
				return Ok(Arc::new(class::JavaClass::new()))
			}) {
				Err(e) => Err(~"classloader: unexpected end-of-file or read error"),
				Ok(T) => T
			}
		}
	}

	// ----------------------------------------------
	fn read_cpool_entry_body(tag : def::ConstantPoolTags, reader : &mut Reader, count : uint,
		skip : &mut uint) ->
		Result<def::Constant, ~str>
	{
		let mut err : Option<~str> = None;
		let cindex = || {
			// indices are in [1,count)
			let index = reader.read_be_u16();
			if index == 0 || (index as uint) >= count {
				err = Some(format!("constant pool index out of range: {}", index));
			}
			return index;
		};

		// TODO: verify the type of cross-referenced cpool entries
		// TODO: do the read_be .. variants properly raise io_error
		// for our caller to trap?

		let res = match tag {
			def::CONSTANT_class =>
				def::CONSTANT_class_info(cindex()),
			def::CONSTANT_fieldref =>
				def::CONSTANT_fieldref_info(cindex(), cindex()),
			def::CONSTANT_methodref =>
				def::CONSTANT_methodref_info(cindex(), cindex()),
			def::CONSTANT_ifacemethodref =>
				def::CONSTANT_ifacemethodref_info(cindex(), cindex()),
			def::CONSTANT_string =>
				def::CONSTANT_string_info(cindex()),
			def::CONSTANT_integer =>
				def::CONSTANT_integer_info(reader.read_be_i32()),
			def::CONSTANT_float =>
				def::CONSTANT_float_info(reader.read_be_f32()),
			def::CONSTANT_long =>
				def::CONSTANT_long_info(reader.read_be_i64()),
			def::CONSTANT_double =>
				def::CONSTANT_double_info(reader.read_be_f64()),
			def::CONSTANT_nameandtype =>
				def::CONSTANT_nameandtype_info(cindex(),cindex()),
			def::CONSTANT_utf8 => {
				let length = reader.read_be_u16() as uint;
				let raw = reader.read_bytes(length);

				// TODO: Java uses a "modified UTF8", which
				//  - encodes NIL as two bytes
				//  - uss two three-byte sequences to encode four byte encodings
				let s = from_utf8_owned_opt(raw);
				match s {
					None => {
						err = Some(~"constant pool entry is not  valid UTF8 string");
						def::CONSTANT_utf8_info(~"")
					},
					Some(s) => def::CONSTANT_utf8_info(s)
				}
			},
			def::CONSTANT_methodhandle =>
				def::CONSTANT_methodhandle_info(reader.read_u8(), cindex()),
			def::CONSTANT_methodtype =>
				def::CONSTANT_methodtype_info(cindex()),
			def::CONSTANT_invokedynamic =>
				def::CONSTANT_invokedynamic_info(reader.read_be_u16(), cindex()),
		};

		// some cpool entries take two indices. According to the spec,
		// this was "a poor choice".
		*skip = match tag {
			def::CONSTANT_long | def::CONSTANT_double => 1,
			_ => 0
		};

		match err {
			None => Ok(res),
			Some(msg) => Err(msg)
		}
	}
}

#[test]
fn test_class_path_decomposition() {
	let cp = build_classpath("~/some/other/bar; /bar/baz;dir ;");
	assert_eq!(cp,~[~".",~"~/some/other/bar", ~"/bar/baz", ~"dir"]);
}

#[test]
fn test_class_loader_fail() {
	let cl = ClassLoader::new("");
	assert!(cl.add_from_classfile("FooClassDoesNotExist").unwrap().is_err());
}

fn assert_no_err<T> (given : Result<T, ~str>) {
	match given {
		Err(s) => fail!("expected no error, error is: {}", s),
		_ => ()
	}
}

#[test]
fn test_class_loader_good() {
	let cl = ClassLoader::new("../test/java");
	let v = cl.add_from_classfile("EmptyClass").unwrap();
	assert_no_err(v);
}

<commit_msg>move assert_no_err to separate util module<commit_after>extern mod extra;
extern mod std;

use std::hashmap::HashMap;
use std::path::PosixPath;

use std::io::{File,result, IoError};
use std::io::mem::BufReader;

use std::num::FromPrimitive;

use std::str::from_utf8_owned_opt;

use extra::future::Future;
use extra::arc::Arc;

mod util;
mod class;
mod def;

fn build_classpath(invar : &str) -> ~[~str] {
	// current folder is always included
	let mut v = ~[~"."];

	// TODO: how to construct a vector directly from an iter?
	for s in invar.split_str(";")
		.map(|s : &str| { s.trim().to_owned() })
		.filter(|s : &~str| {s.len() > 0}){

		v.push(s);
	}
	return v;
}

pub struct ClassLoader {
	priv classpath : ~[~str],
	priv classes : HashMap<~str, ~class::JavaClass>
}

static INITIAL_CLASSLOADER_CAPACITY : uint = 1024;

impl ClassLoader {

	// ----------------------------------------------
	// Constructs a ClassLoader given a CLASSPATH that consists of one or
	// more .class search paths separated by semicolons.
	pub fn new(classpath : &str) -> ~ClassLoader {
		~ClassLoader {
			classpath : build_classpath(classpath),
			classes : HashMap::with_capacity(INITIAL_CLASSLOADER_CAPACITY),
		}
	}

	// ----------------------------------------------
	// Loads a class given its fully qualified class name.
	//
	// This triggers recursive loading of dependent classes.
	//
	// add_from_classfile("de.fruits.Apple") loads <class-path>/de/fruits/Apple.class
	pub fn add_from_classfile(self, name : &str) ->
		Future<
			Result<Arc<class::JavaClass>,~str>
		>
	{
		let cname = name.to_owned();
		let pname = cname.replace(&".", "/") + ".class";
		do Future::spawn {
			for path in self.classpath.iter() {

				match result(|| {
					let p = *path + "/" + pname;
					debug!("load class {}, trying path {}", cname, p);
					File::open(&PosixPath::new(p)).read_to_end()
				}) {
					Err(e) => continue,
					Ok(bytes) => return self.add_from_classfile_bytes(bytes)
						.unwrap()
				};
			}
			return Err(~"failed to locate class file for " + cname);
		}
	}

	// IMPL

	// ----------------------------------------------
	fn add_from_classfile_bytes(self, bytes : ~[u8]) ->
		Future<
			Result<Arc<class::JavaClass>,~str>
		>
	{
		do Future::spawn {
			match result(|| {
				let mut reader = BufReader::new(bytes);

				let magic = reader.read_be_u32() as uint;
				let major = reader.read_be_u16() as uint;
				let minor = reader.read_be_u16() as uint;
				let cpool_count = reader.read_be_u16() as uint;
				if cpool_count == 0 {
					return Err(~"invalid constant pool size");
				}

				let mut constants : ~[def::Constant] = ~[];

				// read constant pool
				let mut i = cpool_count - 1 as uint;
				while i > 0 {
					let tag = reader.read_u8();
					let parsed_tag : Option<def::ConstantPoolTags> =
						FromPrimitive::from_u8(tag);

					let mut skip = 0;
					let maybe_centry = match parsed_tag {
						None => Err(format!("constant pool tag not recognized: {}", tag)),
						Some(c) => {
							ClassLoader::read_cpool_entry_body(c,
								&mut reader as &mut Reader,
								cpool_count as uint,
								&mut skip
							)
						}
					};

					// if that was ok, add it to the list and advance
					match maybe_centry {
						Err(e) => return Err(e),
						Ok(centry) => constants.push(centry)
					}

					assert!(i > skip);
					i -= skip;

					--i;
				}

				let access = reader.read_be_u16() as uint;
				let this_class = reader.read_be_u16() as uint;
				let super_class = reader.read_be_u16() as uint;
				let ifaces_count = reader.read_be_u16() as uint;

				// read interfaces

				let fields_count = reader.read_be_u16() as uint;
				let methods_count = reader.read_be_u16() as uint;

				// read methods

				let attrs_count = reader.read_be_u16() as uint;

				// read attributes
				return Ok(Arc::new(class::JavaClass::new()))
			}) {
				Err(e) => Err(~"classloader: unexpected end-of-file or read error"),
				Ok(T) => T
			}
		}
	}

	// ----------------------------------------------
	fn read_cpool_entry_body(tag : def::ConstantPoolTags, reader : &mut Reader, count : uint,
		skip : &mut uint) ->
		Result<def::Constant, ~str>
	{
		let mut err : Option<~str> = None;
		let cindex = || {
			// indices are in [1,count)
			let index = reader.read_be_u16();
			if index == 0 || (index as uint) >= count {
				err = Some(format!("constant pool index out of range: {}", index));
			}
			return index;
		};

		// TODO: verify the type of cross-referenced cpool entries
		// TODO: do the read_be .. variants properly raise io_error
		// for our caller to trap?

		let res = match tag {
			def::CONSTANT_class =>
				def::CONSTANT_class_info(cindex()),
			def::CONSTANT_fieldref =>
				def::CONSTANT_fieldref_info(cindex(), cindex()),
			def::CONSTANT_methodref =>
				def::CONSTANT_methodref_info(cindex(), cindex()),
			def::CONSTANT_ifacemethodref =>
				def::CONSTANT_ifacemethodref_info(cindex(), cindex()),
			def::CONSTANT_string =>
				def::CONSTANT_string_info(cindex()),
			def::CONSTANT_integer =>
				def::CONSTANT_integer_info(reader.read_be_i32()),
			def::CONSTANT_float =>
				def::CONSTANT_float_info(reader.read_be_f32()),
			def::CONSTANT_long =>
				def::CONSTANT_long_info(reader.read_be_i64()),
			def::CONSTANT_double =>
				def::CONSTANT_double_info(reader.read_be_f64()),
			def::CONSTANT_nameandtype =>
				def::CONSTANT_nameandtype_info(cindex(),cindex()),
			def::CONSTANT_utf8 => {
				let length = reader.read_be_u16() as uint;
				let raw = reader.read_bytes(length);

				// TODO: Java uses a "modified UTF8", which
				//  - encodes NIL as two bytes
				//  - uss two three-byte sequences to encode four byte encodings
				let s = from_utf8_owned_opt(raw);
				match s {
					None => {
						err = Some(~"constant pool entry is not  valid UTF8 string");
						def::CONSTANT_utf8_info(~"")
					},
					Some(s) => def::CONSTANT_utf8_info(s)
				}
			},
			def::CONSTANT_methodhandle =>
				def::CONSTANT_methodhandle_info(reader.read_u8(), cindex()),
			def::CONSTANT_methodtype =>
				def::CONSTANT_methodtype_info(cindex()),
			def::CONSTANT_invokedynamic =>
				def::CONSTANT_invokedynamic_info(reader.read_be_u16(), cindex()),
		};

		// some cpool entries take two indices. According to the spec,
		// this was "a poor choice".
		*skip = match tag {
			def::CONSTANT_long | def::CONSTANT_double => 1,
			_ => 0
		};

		match err {
			None => Ok(res),
			Some(msg) => Err(msg)
		}
	}
}

#[test]
fn test_class_path_decomposition() {
	let cp = build_classpath("~/some/other/bar; /bar/baz;dir ;");
	assert_eq!(cp,~[~".",~"~/some/other/bar", ~"/bar/baz", ~"dir"]);
}

#[test]
fn test_class_loader_fail() {
	let cl = ClassLoader::new("");
	assert!(cl.add_from_classfile("FooClassDoesNotExist").unwrap().is_err());
}

#[test]
fn test_class_loader_good() {
	let cl = ClassLoader::new("../test/java");
	let v = cl.add_from_classfile("EmptyClass").unwrap();
	util::assert_no_err(v);
}

<|endoftext|>