<commit_before>/// The Toml Insert extensions

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

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

pub trait TomlValueInsertExt {
    /// Extension function for inserting a value in the current toml::Value document
    /// using a custom seperator.
    ///
    /// For difference to TomlSetExt::set() and friends, read [#semantics].
    ///
    /// # Semantics
    ///
    /// The function automatically creates intermediate data structures based on the query string.
    /// That means, if the query string is `"a.b.c.[0]"`, but only a table `"a"` exists in the
    /// document, the function automatically creates a table `"b"` inside `"a"` and `"c"` inside
    /// `"b"`, and an array in `"c"`. The array index is ignored if the array is created.
    ///
    /// If an Array exists, but the specified index is larger than the last index, the array will
    /// be expanded by one element: If the array has a length of 3, but the query string specifies
    /// that the element should be put at 1000, the function ignores the large index and simply
    /// appends the value to the index.
    ///
    /// If a Value is inserted into an Array, the array indexes are shifted. Semantically this is
    /// the same as doing a `array.insert(4, _)` (see the standard library).
    ///
    /// ## Known Bugs
    ///
    /// The current implementation does _not_ create intermediate Arrays as described above.
    /// This is a known bug. So queries like "foo.bar.[0].baz" (or any query which has an array
    /// element) will fail with an error rather than work.
    ///
    /// # Return value
    ///
    /// If the insert operation worked correctly, `Ok(None)` is returned.
    /// If the insert operation replaced an existing value `Ok(Some(old_value))` is returned
    /// On failure, `Err(e)` is returned
    ///
    /// # Examples
    ///
    /// The following example shows a working `insert_with_seperator()` call on an empty toml
    /// document. The Value is inserted as `"foo.bar = 1"` in the document.
    ///
    /// ```rust
    /// extern crate toml;
    /// extern crate toml_query;
    ///
    /// let mut toml : toml::Value = toml::from_str("").unwrap();
    /// let query = "foo.bar";
    /// let sep = '.';
    /// let val = toml::Value::Integer(1);
    ///
    /// let res = toml_query::insert::TomlValueInsertExt::insert_with_seperator(&mut toml, query, sep, val);
    /// assert!(res.is_ok());
    /// let res = res.unwrap();
    /// assert!(res.is_none());
    /// ```
    ///
    /// The following example shows a failing `insert_with_seperator()` call on an empty toml
    /// document. The Query does contain an array token, which does not yet work.
    ///
    /// ```rust,should_panic
    /// extern crate toml;
    /// extern crate toml_query;
    ///
    /// let mut toml : toml::Value = toml::from_str("").unwrap();
    /// let query = "foo.[0]";
    /// let sep = '.';
    /// let val = toml::Value::Integer(1);
    ///
    /// let res = toml_query::insert::TomlValueInsertExt::insert_with_seperator(&mut toml, query, sep, val);
    /// assert!(res.is_ok()); // panics
    /// ```
    ///
    fn insert_with_seperator(
        &mut self,
        query: &str,
        sep: char,
        value: Value,
    ) -> Result<Option<Value>>;

    /// Extension function for inserting a value from the current toml::Value document
    ///
    /// See documentation of `TomlValueinsertExt::insert_with_seperator`
    fn insert(&mut self, query: &str, value: Value) -> Result<Option<Value>> {
        self.insert_with_seperator(query, '.', value)
    }

    /// A convenience method for inserting any arbitrary serializable value.
    #[cfg(feature = "typed")]
    fn insert_serialized<S: Serialize>(&mut self, query: &str, value: S) -> Result<Option<Value>> {
        let value = Value::try_from(value).map_err(Error::TomlSerialize)?;
        self.insert(query, value)
    }
}

impl TomlValueInsertExt for Value {
    fn insert_with_seperator(
        &mut self,
        query: &str,
        sep: char,
        value: Value,
    ) -> Result<Option<Value>> {
        use crate::resolver::mut_creating_resolver::resolve;

        let mut tokens = tokenize_with_seperator(query, sep)?;
        let (val, last) = match tokens.pop_last() {
            None => (self, Box::new(tokens)),
            Some(last) => (resolve(self, &tokens)?, last),
        };

        match *last {
            Token::Identifier { ident, .. } => match val {
                &mut Value::Table(ref mut t) => Ok(t.insert(ident, value)),
                _ => Err(Error::NoIdentifierInArray(ident.clone())),
            },

            Token::Index { idx, .. } => match val {
                &mut Value::Array(ref mut a) => {
                    if a.len() > idx {
                        a.insert(idx, value);
                        Ok(None)
                    } else {
                        a.push(value);
                        Ok(None)
                    }
                }
                _ => Err(Error::NoIndexInTable(idx)),
            },
        }
    }
}

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

    #[test]
    fn test_insert_one_token() {
        use toml::map::Map;
        let mut toml = Value::Table(Map::new());

        let res = toml.insert(&String::from("value"), Value::Integer(1));
        println!("TOML: {:?}", toml);
        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let val = t.get("value");
                assert!(
                    val.is_some(),
                    "'value' from table {:?} should be Some(_), is None",
                    t
                );
                let val = val.unwrap();

                assert!(is_match!(val, &Value::Integer(1)), "Is not one: {:?}", val);
            }
            _ => panic!("What just happenend?"),
        }
    }

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

        let res = toml.insert_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let table = t.get("table");
                assert!(table.is_some());

                let table = table.unwrap();
                assert!(is_match!(table, &Value::Table(_)));
                match table {
                    &Value::Table(ref t) => {
                        assert!(!t.is_empty());

                        let a = t.get("a");
                        assert!(a.is_some());

                        let a = a.unwrap();
                        assert!(is_match!(a, &Value::Integer(1)));
                    }
                    _ => panic!("What just happenend?"),
                }
            }
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_insert_with_seperator_into_array() {
        use std::ops::Index;

        let mut toml: Value = toml_from_str(
            r#"
        array = []
        "#,
        )
        .unwrap();

        let res = toml.insert_with_seperator(&String::from("array.[0]"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let array = t.get("array");
                assert!(array.is_some());

                let array = array.unwrap();
                assert!(is_match!(array, &Value::Array(_)));
                match array {
                    &Value::Array(ref a) => {
                        assert!(!a.is_empty());
                        assert!(is_match!(a.index(0), &Value::Integer(1)));
                    }
                    _ => panic!("What just happenend?"),
                }
            }
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_insert_with_seperator_into_nested_table() {
        let mut toml: Value = toml_from_str(
            r#"
        [a.b.c]
        "#,
        )
        .unwrap();

        let res = toml.insert_with_seperator(&String::from("a.b.c.d"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref outer) => {
                assert!(!outer.is_empty());
                let a_tab = outer.get("a");
                assert!(a_tab.is_some());

                let a_tab = a_tab.unwrap();
                assert!(is_match!(a_tab, &Value::Table(_)));
                match a_tab {
                    &Value::Table(ref a) => {
                        assert!(!a.is_empty());

                        let b_tab = a.get("b");
                        assert!(b_tab.is_some());

                        let b_tab = b_tab.unwrap();
                        assert!(is_match!(b_tab, &Value::Table(_)));
                        match b_tab {
                            &Value::Table(ref b) => {
                                assert!(!b.is_empty());

                                let c_tab = b.get("c");
                                assert!(c_tab.is_some());

                                let c_tab = c_tab.unwrap();
                                assert!(is_match!(c_tab, &Value::Table(_)));
                                match c_tab {
                                    &Value::Table(ref c) => {
                                        assert!(!c.is_empty());

                                        let d = c.get("d");
                                        assert!(d.is_some());

                                        let d = d.unwrap();
                                        assert!(is_match!(d, &Value::Integer(1)));
                                    }
                                    _ => panic!("What just happenend?"),
                                }
                            }
                            _ => panic!("What just happenend?"),
                        }
                    }
                    _ => panic!("What just happenend?"),
                }
            }
            _ => panic!("What just happened?"),
        }
    }

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

        let res = toml.insert_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_err());

        let err = res.unwrap_err();
        assert!(is_match!(err, Error::NoIdentifierInArray(_)));
    }

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

        let res = toml.insert_with_seperator(&String::from("table.[0]"), '.', Value::Integer(1));

        assert!(res.is_err());

        let err = res.unwrap_err();
        assert!(is_match!(err, Error::NoIndexInTable(_)));
    }

    #[test]
    fn test_insert_with_seperator_into_array_between_values() {
        use std::ops::Index;

        let mut toml: Value = toml_from_str(
            r#"
        array = [1, 2, 3, 4, 5]
        "#,
        )
        .unwrap();

        let res = toml.insert_with_seperator(&String::from("array.[2]"), '.', Value::Integer(6));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let array = t.get("array");
                assert!(array.is_some());

                let array = array.unwrap();
                assert!(is_match!(array, &Value::Array(_)));
                match array {
                    &Value::Array(ref a) => {
                        assert!(!a.is_empty());
                        assert!(is_match!(a.index(0), &Value::Integer(1)));
                        assert!(is_match!(a.index(1), &Value::Integer(2)));
                        assert!(is_match!(a.index(2), &Value::Integer(6)));
                        assert!(is_match!(a.index(3), &Value::Integer(3)));
                        assert!(is_match!(a.index(4), &Value::Integer(4)));
                        assert!(is_match!(a.index(5), &Value::Integer(5)));
                    }
                    _ => panic!("What just happenend?"),
                }
            }
            _ => panic!("What just happenend?"),
        }
    }

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

        let res = toml.insert_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let table = t.get("table");
                assert!(table.is_some());

                let table = table.unwrap();
                assert!(is_match!(table, &Value::Table(_)));
                match table {
                    &Value::Table(ref t) => {
                        assert!(!t.is_empty());

                        let a = t.get("a");
                        assert!(a.is_some());

                        let a = a.unwrap();
                        assert!(is_match!(a, &Value::Integer(1)));
                    }
                    _ => panic!("What just happenend?"),
                }
            }
            _ => panic!("What just happenend?"),
        }
    }

}
<commit_msg>fix TomlValueInsertExt name in docs<commit_after>/// The Toml Insert extensions

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

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

pub trait TomlValueInsertExt {
    /// Extension function for inserting a value in the current toml::Value document
    /// using a custom seperator.
    ///
    /// For difference to TomlSetExt::set() and friends, read [#semantics].
    ///
    /// # Semantics
    ///
    /// The function automatically creates intermediate data structures based on the query string.
    /// That means, if the query string is `"a.b.c.[0]"`, but only a table `"a"` exists in the
    /// document, the function automatically creates a table `"b"` inside `"a"` and `"c"` inside
    /// `"b"`, and an array in `"c"`. The array index is ignored if the array is created.
    ///
    /// If an Array exists, but the specified index is larger than the last index, the array will
    /// be expanded by one element: If the array has a length of 3, but the query string specifies
    /// that the element should be put at 1000, the function ignores the large index and simply
    /// appends the value to the index.
    ///
    /// If a Value is inserted into an Array, the array indexes are shifted. Semantically this is
    /// the same as doing a `array.insert(4, _)` (see the standard library).
    ///
    /// ## Known Bugs
    ///
    /// The current implementation does _not_ create intermediate Arrays as described above.
    /// This is a known bug. So queries like "foo.bar.[0].baz" (or any query which has an array
    /// element) will fail with an error rather than work.
    ///
    /// # Return value
    ///
    /// If the insert operation worked correctly, `Ok(None)` is returned.
    /// If the insert operation replaced an existing value `Ok(Some(old_value))` is returned
    /// On failure, `Err(e)` is returned
    ///
    /// # Examples
    ///
    /// The following example shows a working `insert_with_seperator()` call on an empty toml
    /// document. The Value is inserted as `"foo.bar = 1"` in the document.
    ///
    /// ```rust
    /// extern crate toml;
    /// extern crate toml_query;
    ///
    /// let mut toml : toml::Value = toml::from_str("").unwrap();
    /// let query = "foo.bar";
    /// let sep = '.';
    /// let val = toml::Value::Integer(1);
    ///
    /// let res = toml_query::insert::TomlValueInsertExt::insert_with_seperator(&mut toml, query, sep, val);
    /// assert!(res.is_ok());
    /// let res = res.unwrap();
    /// assert!(res.is_none());
    /// ```
    ///
    /// The following example shows a failing `insert_with_seperator()` call on an empty toml
    /// document. The Query does contain an array token, which does not yet work.
    ///
    /// ```rust,should_panic
    /// extern crate toml;
    /// extern crate toml_query;
    ///
    /// let mut toml : toml::Value = toml::from_str("").unwrap();
    /// let query = "foo.[0]";
    /// let sep = '.';
    /// let val = toml::Value::Integer(1);
    ///
    /// let res = toml_query::insert::TomlValueInsertExt::insert_with_seperator(&mut toml, query, sep, val);
    /// assert!(res.is_ok()); // panics
    /// ```
    ///
    fn insert_with_seperator(
        &mut self,
        query: &str,
        sep: char,
        value: Value,
    ) -> Result<Option<Value>>;

    /// Extension function for inserting a value from the current toml::Value document
    ///
    /// See documentation of `TomlValueInsertExt::insert_with_seperator`
    fn insert(&mut self, query: &str, value: Value) -> Result<Option<Value>> {
        self.insert_with_seperator(query, '.', value)
    }

    /// A convenience method for inserting any arbitrary serializable value.
    #[cfg(feature = "typed")]
    fn insert_serialized<S: Serialize>(&mut self, query: &str, value: S) -> Result<Option<Value>> {
        let value = Value::try_from(value).map_err(Error::TomlSerialize)?;
        self.insert(query, value)
    }
}

impl TomlValueInsertExt for Value {
    fn insert_with_seperator(
        &mut self,
        query: &str,
        sep: char,
        value: Value,
    ) -> Result<Option<Value>> {
        use crate::resolver::mut_creating_resolver::resolve;

        let mut tokens = tokenize_with_seperator(query, sep)?;
        let (val, last) = match tokens.pop_last() {
            None => (self, Box::new(tokens)),
            Some(last) => (resolve(self, &tokens)?, last),
        };

        match *last {
            Token::Identifier { ident, .. } => match val {
                &mut Value::Table(ref mut t) => Ok(t.insert(ident, value)),
                _ => Err(Error::NoIdentifierInArray(ident.clone())),
            },

            Token::Index { idx, .. } => match val {
                &mut Value::Array(ref mut a) => {
                    if a.len() > idx {
                        a.insert(idx, value);
                        Ok(None)
                    } else {
                        a.push(value);
                        Ok(None)
                    }
                }
                _ => Err(Error::NoIndexInTable(idx)),
            },
        }
    }
}

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

    #[test]
    fn test_insert_one_token() {
        use toml::map::Map;
        let mut toml = Value::Table(Map::new());

        let res = toml.insert(&String::from("value"), Value::Integer(1));
        println!("TOML: {:?}", toml);
        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let val = t.get("value");
                assert!(
                    val.is_some(),
                    "'value' from table {:?} should be Some(_), is None",
                    t
                );
                let val = val.unwrap();

                assert!(is_match!(val, &Value::Integer(1)), "Is not one: {:?}", val);
            }
            _ => panic!("What just happenend?"),
        }
    }

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

        let res = toml.insert_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let table = t.get("table");
                assert!(table.is_some());

                let table = table.unwrap();
                assert!(is_match!(table, &Value::Table(_)));
                match table {
                    &Value::Table(ref t) => {
                        assert!(!t.is_empty());

                        let a = t.get("a");
                        assert!(a.is_some());

                        let a = a.unwrap();
                        assert!(is_match!(a, &Value::Integer(1)));
                    }
                    _ => panic!("What just happenend?"),
                }
            }
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_insert_with_seperator_into_array() {
        use std::ops::Index;

        let mut toml: Value = toml_from_str(
            r#"
        array = []
        "#,
        )
        .unwrap();

        let res = toml.insert_with_seperator(&String::from("array.[0]"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let array = t.get("array");
                assert!(array.is_some());

                let array = array.unwrap();
                assert!(is_match!(array, &Value::Array(_)));
                match array {
                    &Value::Array(ref a) => {
                        assert!(!a.is_empty());
                        assert!(is_match!(a.index(0), &Value::Integer(1)));
                    }
                    _ => panic!("What just happenend?"),
                }
            }
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_insert_with_seperator_into_nested_table() {
        let mut toml: Value = toml_from_str(
            r#"
        [a.b.c]
        "#,
        )
        .unwrap();

        let res = toml.insert_with_seperator(&String::from("a.b.c.d"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref outer) => {
                assert!(!outer.is_empty());
                let a_tab = outer.get("a");
                assert!(a_tab.is_some());

                let a_tab = a_tab.unwrap();
                assert!(is_match!(a_tab, &Value::Table(_)));
                match a_tab {
                    &Value::Table(ref a) => {
                        assert!(!a.is_empty());

                        let b_tab = a.get("b");
                        assert!(b_tab.is_some());

                        let b_tab = b_tab.unwrap();
                        assert!(is_match!(b_tab, &Value::Table(_)));
                        match b_tab {
                            &Value::Table(ref b) => {
                                assert!(!b.is_empty());

                                let c_tab = b.get("c");
                                assert!(c_tab.is_some());

                                let c_tab = c_tab.unwrap();
                                assert!(is_match!(c_tab, &Value::Table(_)));
                                match c_tab {
                                    &Value::Table(ref c) => {
                                        assert!(!c.is_empty());

                                        let d = c.get("d");
                                        assert!(d.is_some());

                                        let d = d.unwrap();
                                        assert!(is_match!(d, &Value::Integer(1)));
                                    }
                                    _ => panic!("What just happenend?"),
                                }
                            }
                            _ => panic!("What just happenend?"),
                        }
                    }
                    _ => panic!("What just happenend?"),
                }
            }
            _ => panic!("What just happened?"),
        }
    }

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

        let res = toml.insert_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_err());

        let err = res.unwrap_err();
        assert!(is_match!(err, Error::NoIdentifierInArray(_)));
    }

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

        let res = toml.insert_with_seperator(&String::from("table.[0]"), '.', Value::Integer(1));

        assert!(res.is_err());

        let err = res.unwrap_err();
        assert!(is_match!(err, Error::NoIndexInTable(_)));
    }

    #[test]
    fn test_insert_with_seperator_into_array_between_values() {
        use std::ops::Index;

        let mut toml: Value = toml_from_str(
            r#"
        array = [1, 2, 3, 4, 5]
        "#,
        )
        .unwrap();

        let res = toml.insert_with_seperator(&String::from("array.[2]"), '.', Value::Integer(6));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let array = t.get("array");
                assert!(array.is_some());

                let array = array.unwrap();
                assert!(is_match!(array, &Value::Array(_)));
                match array {
                    &Value::Array(ref a) => {
                        assert!(!a.is_empty());
                        assert!(is_match!(a.index(0), &Value::Integer(1)));
                        assert!(is_match!(a.index(1), &Value::Integer(2)));
                        assert!(is_match!(a.index(2), &Value::Integer(6)));
                        assert!(is_match!(a.index(3), &Value::Integer(3)));
                        assert!(is_match!(a.index(4), &Value::Integer(4)));
                        assert!(is_match!(a.index(5), &Value::Integer(5)));
                    }
                    _ => panic!("What just happenend?"),
                }
            }
            _ => panic!("What just happenend?"),
        }
    }

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

        let res = toml.insert_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let table = t.get("table");
                assert!(table.is_some());

                let table = table.unwrap();
                assert!(is_match!(table, &Value::Table(_)));
                match table {
                    &Value::Table(ref t) => {
                        assert!(!t.is_empty());

                        let a = t.get("a");
                        assert!(a.is_some());

                        let a = a.unwrap();
                        assert!(is_match!(a, &Value::Integer(1)));
                    }
                    _ => panic!("What just happenend?"),
                }
            }
            _ => panic!("What just happenend?"),
        }
    }

}
<|endoftext|>


<commit_before>#![feature(alloc)]
#![feature(asm)]
#![feature(box_syntax)]
#![feature(core_simd)]
#![feature(core_slice_ext)]
#![feature(core_str_ext)]
#![feature(fnbox)]
#![feature(fundamental)]
#![feature(lang_items)]
#![feature(no_std)]
#![feature(rc_unique)]
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![no_std]

extern crate alloc;

#[macro_use]
extern crate mopa;

use core::fmt;
use core::mem::size_of;
use core::mem::swap;
use core::ptr;

use common::pio::*;
use common::memory::*;

use drivers::disk::*;
use drivers::keyboard::keyboard_init;
use drivers::mouse::mouse_init;
use drivers::pci::*;
use drivers::ps2::*;
use drivers::serial::*;

use filesystems::unfs::*;

use graphics::bmp::*;
use graphics::color::*;

use programs::filemanager::*;
use programs::common::*;
use programs::session::*;

use schemes::file::*;
use schemes::http::*;
use schemes::memory::*;
use schemes::pci::*;
use schemes::random::*;

mod common {
    pub mod debug;
    pub mod elf;
    pub mod event;
    pub mod memory;
    pub mod pci;
    pub mod pio;
    pub mod random;
    pub mod resource;
    pub mod string;
    pub mod vec;
}

mod drivers {
    pub mod disk;
    pub mod keyboard;
    pub mod mouse;
    pub mod pci;
    pub mod ps2;
    pub mod serial;
}

mod filesystems {
    pub mod unfs;
}

mod graphics {
    pub mod bmp;
    pub mod color;
    pub mod display;
    pub mod point;
    pub mod size;
    pub mod window;
}

mod network {
    pub mod arp;
    pub mod common;
    pub mod ethernet;
    pub mod icmp;
    pub mod intel8254x;
    pub mod ipv4;
    pub mod rtl8139;
    pub mod tcp;
    pub mod udp;
}

mod programs {
    pub mod common;
    pub mod editor;
    pub mod executor;
    pub mod filemanager;
    pub mod session;
    pub mod viewer;
}

mod schemes {
    pub mod file;
    pub mod http;
    pub mod ide;
    pub mod memory;
    pub mod pci;
    pub mod random;
}

mod usb {
    pub mod xhci;
}

static mut debug_display: *mut Display = 0 as *mut Display;
static mut debug_point: Point = Point{ x: 0, y: 0 };
static mut debug_draw: bool = false;
static mut debug_redraw: bool = false;

static mut session_ptr: *mut Session = 0 as *mut Session;
static mut events_ptr: *mut Vec<Event> = 0 as *mut Vec<Event>;

unsafe fn test_disk(disk: Disk){
    if disk.identify() {
        d("  Disk Found\n");

        let unfs = UnFS::from_disk(disk);
        if unfs.valid() {
            d("  UnFS Filesystem\n");
        }else{
            d("  Unknown Filesystem\n");
        }
    }else{
        d("  Disk Not Found\n");
    }
}

unsafe fn init(font_data: usize, cursor_data: usize){
    debug_display = 0 as *mut Display;
    debug_point = Point{ x: 0, y: 0 };
    debug_draw = false;
    debug_redraw = false;

    session_ptr = 0 as *mut Session;
    events_ptr = 0 as *mut Vec<Event>;

    debug_init();

    dd(size_of::<usize>() * 8);
    d(" bits");
    dl();

    page_init();
    cluster_init();

    debug_display = alloc(size_of::<Session>()) as *mut Display;
    ptr::write(debug_display, Display::new());
    (*debug_display).fonts = font_data;
    (*debug_display).set(Color::new(0, 0, 0));
    debug_draw = true;

    session_ptr = alloc(size_of::<Session>()) as *mut Session;
    ptr::write(session_ptr, Session::new());
    events_ptr = alloc(size_of::<Vec<Event>>()) as *mut Vec<Event>;
    ptr::write(events_ptr, Vec::new());

    let session = &mut *session_ptr;
    session.display.fonts = font_data;
    session.display.cursor = BMP::from_data(cursor_data);

    keyboard_init();
    mouse_init();

    session.modules.push(Rc::new(PS2));
    session.modules.push(Rc::new(Serial::new(0x3F8, 0x4)));

    pci_init(session);

    d("Primary Master\n");
    test_disk(Disk::primary_master());

    d("Primary Slave\n");
    test_disk(Disk::primary_slave());

    d("Secondary Master\n");
    test_disk(Disk::secondary_master());

    d("Secondary Slave\n");
    test_disk(Disk::secondary_slave());

    session.modules.push(Rc::new(FileScheme{
        unfs: UnFS::from_disk(Disk::primary_master())
    }));

    session.modules.push(Rc::new(HTTPScheme));
    session.modules.push(Rc::new(MemoryScheme));
    session.modules.push(Rc::new(PCIScheme));
    session.modules.push(Rc::new(RandomScheme));

    /*
    URL::from_string("file:///background.bmp".to_string()).open_async(box |mut resource: Box<Resource>|{
        let mut vec: Vec<u8> = Vec::new();
        match resource.read_to_end(&mut vec) {
            Option::Some(0) => d("No background data\n"),
            Option::Some(len) => {
                (*session_ptr).display.background = BMP::from_data(vec.as_ptr() as usize);
            },
            Option::None => d("Background load error\n")
        }
    });
    */

    session.items.insert(0, Rc::new(FileManager::new()));
}

fn dr(reg: &str, value: u32){
    d(reg);
    d(": ");
    dh(value as usize);
    dl();
}

#[no_mangle]
//Take regs for kernel calls and exceptions
pub unsafe fn kernel(interrupt: u32, edi: u32, esi: u32, ebp: u32, esp: u32, ebx: u32, edx: u32, ecx: u32, eax: u32, eip: u32, eflags: u32) {
    let exception = |name: &str|{
        d(name);
        dl();

        dr("INT", interrupt);
        dr("EIP", eip);
        dr("EFLAGS", eflags);
        dr("EAX", eax);
        dr("EBX", ebx);
        dr("ECX", ecx);
        dr("EDX", edx);
        dr("EDI", edi);
        dr("ESI", esi);
        dr("EBP", ebp);
        dr("ESP", esp);

        asm!("cli");
        asm!("hlt");
        loop{}
    };

    match interrupt {
        0x20 => (), //timer
        0x21 => (*session_ptr).on_irq(0x1), //keyboard
        0x23 => (*session_ptr).on_irq(0x3), // serial 2 and 4
        0x24 => (*session_ptr).on_irq(0x4), // serial 1 and 3
        0x29 => (*session_ptr).on_irq(0x9), //pci
        0x2A => (*session_ptr).on_irq(0xA), //pci
        0x2B => (*session_ptr).on_irq(0xB), //pci
        0x2C => (*session_ptr).on_irq(0xC), //mouse
        0x2E => (*session_ptr).on_irq(0xE), //disk
        0x2F => (*session_ptr).on_irq(0xF), //disk
        0x80 => { // kernel calls
            match eax {
                0x0 => { //Debug
                    if debug_display as usize > 0 {
                        if ebx == 10 {
                            debug_point.x = 0;
                            debug_point.y += 16;
                            debug_redraw = true;
                        }else{
                            (*debug_display).char(debug_point, (ebx as u8) as char, Color::new(255, 255, 255));
                            debug_point.x += 8;
                        }
                        if debug_point.x >= (*debug_display).width as isize {
                            debug_point.x = 0;
                            debug_point.y += 16;
                        }
                        while debug_point.y + 16 > (*debug_display).height as isize {
                            (*debug_display).scroll(16);
                            debug_point.y -= 16;
                        }
                        if debug_draw && debug_redraw {
                            debug_redraw = false;
                            (*debug_display).flip();
                        }
                    }else{
                        outb(0x3F8, ebx as u8);
                    }
                }
                0x1 => {
                    d("Open: ");
                    let url: &URL = &*(ebx as *const URL);
                    url.d();

                    let session = &mut *session_ptr;
                    ptr::write(ecx as *mut Box<Resource>, session.open(url));
                },
                0x2 => {
                    d("Open Async: ");
                    let url: &URL = &*(ebx as *const URL);
                    let callback: Box<FnBox(Box<Resource>)> = ptr::read(ecx as *const Box<FnBox(Box<Resource>)>);
                    unalloc(ecx as usize);
                    url.d();

                    let session = &mut *session_ptr;
                    session.open_async(url, callback);
                },
                0x3 => {
                    (*events_ptr).push(*(ebx as *const Event));
                }
                _ => {
                    d("System Call");
                    d(" EAX:");
                    dh(eax as usize);
                    d(" EBX:");
                    dh(ebx as usize);
                    d(" ECX:");
                    dh(ecx as usize);
                    d(" EDX:");
                    dh(edx as usize);
                    dl();
                }
            }
        },
        0xFF => { // main loop
            init(eax as usize, ebx as usize);

            let session = &mut *session_ptr;
            loop {
                //Polling must take place without interrupts to avoid interruption during I/O logic
                asm!("cli");
                    session.on_poll();
                loop {
                    //Copying the events must take place without interrupts to avoid pushes of events
                    asm!("cli");
                        let mut events_copy: Vec<Event> = Vec::new();
                        swap(&mut events_copy, &mut *events_ptr);

                        for event in events_copy.iter() {
                            if event.code == 'k' && event.b == 0x3B && event.c > 0 {
                                debug_draw = true;
                                debug_redraw = true;
                            }
                            if event.code == 'k' && event.b == 0x3C && event.c > 0 {
                                debug_draw = false;
                                (*events_ptr).push(RedrawEvent {
                                    redraw: REDRAW_ALL
                                }.to_event());
                            }
                        }

                    if debug_draw {
                        if debug_display as usize > 0 && debug_redraw {
                            debug_redraw = false;
                            (*debug_display).flip();
                        }
                    }else{
                        //Can preempt event handling and redraw
                        //asm!("sti");
                            session.handle_events(&mut events_copy);
                            session.redraw();
                    }

                    //Checking for new events must take place without interrupts to avoid pushes of events
                    asm!("cli");
                        if (*events_ptr).len() == 0 {
                            break;
                        }
                }
                //On no new events, halt
                asm!("sti");
                asm!("hlt");
            }
        },
        0x0 => exception("Divide by zero exception"),
        0x1 => exception("Debug exception"),
        0x2 => exception("Non-maskable interrupt"),
        0x3 => exception("Breakpoint exception"),
        0x4 => exception("Overflow exception"),
        0x5 => exception("Bound range exceeded exception"),
        0x6 => exception("Invalid opcode exception"),
        0x7 => exception("Device not available exception"),
        0x8 => exception("Double fault"),
        0xA => exception("Invalid TSS exception"),
        0xB => exception("Segment not present exception"),
        0xC => exception("Stack-segment fault"),
        0xD => exception("General protection fault"),
        0xE => exception("Page fault"),
        0x10 => exception("x87 floating-point exception"),
        0x11 => exception("Alignment check exception"),
        0x12 => exception("Machine check exception"),
        0x13 => exception("SIMD floating-point exception"),
        0x14 => exception("Virtualization exception"),
        0x1E => exception("Security exception"),
        _ => {
            d("Interrupt: ");
            dh(interrupt as usize);
            dl();
        }
    }

    if interrupt >= 0x20 && interrupt < 0x30 {
        if interrupt >= 0x28 {
            outb(0xA0, 0x20);
        }

        outb(0x20, 0x20);
    }
}

#[lang = "panic_fmt"]
pub extern fn panic_fmt(fmt: fmt::Arguments, file: &'static str, line: u32) -> ! {
    d("PANIC: ");
    d(file);
    d(": ");
    dh(line as usize);
    dl();
    unsafe{
        asm!("cli");
        asm!("hlt");
    }
    loop{}
}

#[no_mangle]
pub extern "C" fn memcmp(a: *mut u8, b: *const u8, len: isize) -> isize {
    unsafe {
        let mut i = 0;
        while i < len {
            let c_a = *a.offset(i);
            let c_b = *b.offset(i);
            if c_a != c_b{
                return c_a as isize - c_b as isize;
            }
            i += 1;
        }
        return 0;
    }
}

#[no_mangle]
pub extern "C" fn memmove(dst: *mut u8, src: *const u8, len: isize){
    unsafe {
        if src < dst {
            let mut i = len;
            while i > 0 {
                i -= 1;
                *dst.offset(i) = *src.offset(i);
            }
        }else{
            let mut i = 0;
            while i < len {
                *dst.offset(i) = *src.offset(i);
                i += 1;
            }
        }
    }
}

#[no_mangle]
pub extern "C" fn memcpy(dst: *mut u8, src: *const u8, len: isize){
    unsafe {
        let mut i = 0;
        while i < len {
            *dst.offset(i) = *src.offset(i);
            i += 1;
        }
    }
}

#[no_mangle]
pub extern "C" fn memset(src: *mut u8, c: i32, len: isize) {
    unsafe {
        let mut i = 0;
        while i < len {
            *src.offset(i) = c as u8;
            i += 1;
        }
    }
}
<commit_msg>Readd background image<commit_after>#![feature(alloc)]
#![feature(asm)]
#![feature(box_syntax)]
#![feature(core_simd)]
#![feature(core_slice_ext)]
#![feature(core_str_ext)]
#![feature(fnbox)]
#![feature(fundamental)]
#![feature(lang_items)]
#![feature(no_std)]
#![feature(rc_unique)]
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![no_std]

extern crate alloc;

#[macro_use]
extern crate mopa;

use core::fmt;
use core::mem::size_of;
use core::mem::swap;
use core::ptr;

use common::pio::*;
use common::memory::*;

use drivers::disk::*;
use drivers::keyboard::keyboard_init;
use drivers::mouse::mouse_init;
use drivers::pci::*;
use drivers::ps2::*;
use drivers::serial::*;

use filesystems::unfs::*;

use graphics::bmp::*;
use graphics::color::*;

use programs::filemanager::*;
use programs::common::*;
use programs::session::*;

use schemes::file::*;
use schemes::http::*;
use schemes::memory::*;
use schemes::pci::*;
use schemes::random::*;

mod common {
    pub mod debug;
    pub mod elf;
    pub mod event;
    pub mod memory;
    pub mod pci;
    pub mod pio;
    pub mod random;
    pub mod resource;
    pub mod string;
    pub mod vec;
}

mod drivers {
    pub mod disk;
    pub mod keyboard;
    pub mod mouse;
    pub mod pci;
    pub mod ps2;
    pub mod serial;
}

mod filesystems {
    pub mod unfs;
}

mod graphics {
    pub mod bmp;
    pub mod color;
    pub mod display;
    pub mod point;
    pub mod size;
    pub mod window;
}

mod network {
    pub mod arp;
    pub mod common;
    pub mod ethernet;
    pub mod icmp;
    pub mod intel8254x;
    pub mod ipv4;
    pub mod rtl8139;
    pub mod tcp;
    pub mod udp;
}

mod programs {
    pub mod common;
    pub mod editor;
    pub mod executor;
    pub mod filemanager;
    pub mod session;
    pub mod viewer;
}

mod schemes {
    pub mod file;
    pub mod http;
    pub mod ide;
    pub mod memory;
    pub mod pci;
    pub mod random;
}

mod usb {
    pub mod xhci;
}

static mut debug_display: *mut Display = 0 as *mut Display;
static mut debug_point: Point = Point{ x: 0, y: 0 };
static mut debug_draw: bool = false;
static mut debug_redraw: bool = false;

static mut session_ptr: *mut Session = 0 as *mut Session;
static mut events_ptr: *mut Vec<Event> = 0 as *mut Vec<Event>;

unsafe fn test_disk(disk: Disk){
    if disk.identify() {
        d("  Disk Found\n");

        let unfs = UnFS::from_disk(disk);
        if unfs.valid() {
            d("  UnFS Filesystem\n");
        }else{
            d("  Unknown Filesystem\n");
        }
    }else{
        d("  Disk Not Found\n");
    }
}

unsafe fn init(font_data: usize, cursor_data: usize){
    debug_display = 0 as *mut Display;
    debug_point = Point{ x: 0, y: 0 };
    debug_draw = false;
    debug_redraw = false;

    session_ptr = 0 as *mut Session;
    events_ptr = 0 as *mut Vec<Event>;

    debug_init();

    dd(size_of::<usize>() * 8);
    d(" bits");
    dl();

    page_init();
    cluster_init();

    debug_display = alloc(size_of::<Session>()) as *mut Display;
    ptr::write(debug_display, Display::new());
    (*debug_display).fonts = font_data;
    (*debug_display).set(Color::new(0, 0, 0));
    debug_draw = true;

    session_ptr = alloc(size_of::<Session>()) as *mut Session;
    ptr::write(session_ptr, Session::new());
    events_ptr = alloc(size_of::<Vec<Event>>()) as *mut Vec<Event>;
    ptr::write(events_ptr, Vec::new());

    let session = &mut *session_ptr;
    session.display.fonts = font_data;
    session.display.cursor = BMP::from_data(cursor_data);

    keyboard_init();
    mouse_init();

    session.modules.push(Rc::new(PS2));
    session.modules.push(Rc::new(Serial::new(0x3F8, 0x4)));

    pci_init(session);

    d("Primary Master\n");
    test_disk(Disk::primary_master());

    d("Primary Slave\n");
    test_disk(Disk::primary_slave());

    d("Secondary Master\n");
    test_disk(Disk::secondary_master());

    d("Secondary Slave\n");
    test_disk(Disk::secondary_slave());

    session.modules.push(Rc::new(FileScheme{
        unfs: UnFS::from_disk(Disk::primary_master())
    }));

    session.modules.push(Rc::new(HTTPScheme));
    session.modules.push(Rc::new(MemoryScheme));
    session.modules.push(Rc::new(PCIScheme));
    session.modules.push(Rc::new(RandomScheme));

    URL::from_string("file:///background.bmp".to_string()).open_async(box |mut resource: Box<Resource>|{
        let mut vec: Vec<u8> = Vec::new();
        match resource.read_to_end(&mut vec) {
            Option::Some(0) => d("No background data\n"),
            Option::Some(len) => {
                (*session_ptr).display.background = BMP::from_data(vec.as_ptr() as usize);
            },
            Option::None => d("Background load error\n")
        }
    });

    session.items.insert(0, Rc::new(FileManager::new()));
}

fn dr(reg: &str, value: u32){
    d(reg);
    d(": ");
    dh(value as usize);
    dl();
}

#[no_mangle]
//Take regs for kernel calls and exceptions
pub unsafe fn kernel(interrupt: u32, edi: u32, esi: u32, ebp: u32, esp: u32, ebx: u32, edx: u32, ecx: u32, eax: u32, eip: u32, eflags: u32) {
    let exception = |name: &str|{
        d(name);
        dl();

        dr("INT", interrupt);
        dr("EIP", eip);
        dr("EFLAGS", eflags);
        dr("EAX", eax);
        dr("EBX", ebx);
        dr("ECX", ecx);
        dr("EDX", edx);
        dr("EDI", edi);
        dr("ESI", esi);
        dr("EBP", ebp);
        dr("ESP", esp);

        asm!("cli");
        asm!("hlt");
        loop{}
    };

    match interrupt {
        0x20 => (), //timer
        0x21 => (*session_ptr).on_irq(0x1), //keyboard
        0x23 => (*session_ptr).on_irq(0x3), // serial 2 and 4
        0x24 => (*session_ptr).on_irq(0x4), // serial 1 and 3
        0x29 => (*session_ptr).on_irq(0x9), //pci
        0x2A => (*session_ptr).on_irq(0xA), //pci
        0x2B => (*session_ptr).on_irq(0xB), //pci
        0x2C => (*session_ptr).on_irq(0xC), //mouse
        0x2E => (*session_ptr).on_irq(0xE), //disk
        0x2F => (*session_ptr).on_irq(0xF), //disk
        0x80 => { // kernel calls
            match eax {
                0x0 => { //Debug
                    if debug_display as usize > 0 {
                        if ebx == 10 {
                            debug_point.x = 0;
                            debug_point.y += 16;
                            debug_redraw = true;
                        }else{
                            (*debug_display).char(debug_point, (ebx as u8) as char, Color::new(255, 255, 255));
                            debug_point.x += 8;
                        }
                        if debug_point.x >= (*debug_display).width as isize {
                            debug_point.x = 0;
                            debug_point.y += 16;
                        }
                        while debug_point.y + 16 > (*debug_display).height as isize {
                            (*debug_display).scroll(16);
                            debug_point.y -= 16;
                        }
                        if debug_draw && debug_redraw {
                            debug_redraw = false;
                            (*debug_display).flip();
                        }
                    }else{
                        outb(0x3F8, ebx as u8);
                    }
                }
                0x1 => {
                    d("Open: ");
                    let url: &URL = &*(ebx as *const URL);
                    url.d();

                    let session = &mut *session_ptr;
                    ptr::write(ecx as *mut Box<Resource>, session.open(url));
                },
                0x2 => {
                    d("Open Async: ");
                    let url: &URL = &*(ebx as *const URL);
                    let callback: Box<FnBox(Box<Resource>)> = ptr::read(ecx as *const Box<FnBox(Box<Resource>)>);
                    unalloc(ecx as usize);
                    url.d();

                    let session = &mut *session_ptr;
                    session.open_async(url, callback);
                },
                0x3 => {
                    (*events_ptr).push(*(ebx as *const Event));
                }
                _ => {
                    d("System Call");
                    d(" EAX:");
                    dh(eax as usize);
                    d(" EBX:");
                    dh(ebx as usize);
                    d(" ECX:");
                    dh(ecx as usize);
                    d(" EDX:");
                    dh(edx as usize);
                    dl();
                }
            }
        },
        0xFF => { // main loop
            init(eax as usize, ebx as usize);

            let session = &mut *session_ptr;
            loop {
                //Polling must take place without interrupts to avoid interruption during I/O logic
                asm!("cli");
                    session.on_poll();
                loop {
                    //Copying the events must take place without interrupts to avoid pushes of events
                    asm!("cli");
                        let mut events_copy: Vec<Event> = Vec::new();
                        swap(&mut events_copy, &mut *events_ptr);

                        for event in events_copy.iter() {
                            if event.code == 'k' && event.b == 0x3B && event.c > 0 {
                                debug_draw = true;
                                debug_redraw = true;
                            }
                            if event.code == 'k' && event.b == 0x3C && event.c > 0 {
                                debug_draw = false;
                                (*events_ptr).push(RedrawEvent {
                                    redraw: REDRAW_ALL
                                }.to_event());
                            }
                        }

                    if debug_draw {
                        if debug_display as usize > 0 && debug_redraw {
                            debug_redraw = false;
                            (*debug_display).flip();
                        }
                    }else{
                        //Can preempt event handling and redraw
                        //asm!("sti");
                            session.handle_events(&mut events_copy);
                            session.redraw();
                    }

                    //Checking for new events must take place without interrupts to avoid pushes of events
                    asm!("cli");
                        if (*events_ptr).len() == 0 {
                            break;
                        }
                }
                //On no new events, halt
                asm!("sti");
                asm!("hlt");
            }
        },
        0x0 => exception("Divide by zero exception"),
        0x1 => exception("Debug exception"),
        0x2 => exception("Non-maskable interrupt"),
        0x3 => exception("Breakpoint exception"),
        0x4 => exception("Overflow exception"),
        0x5 => exception("Bound range exceeded exception"),
        0x6 => exception("Invalid opcode exception"),
        0x7 => exception("Device not available exception"),
        0x8 => exception("Double fault"),
        0xA => exception("Invalid TSS exception"),
        0xB => exception("Segment not present exception"),
        0xC => exception("Stack-segment fault"),
        0xD => exception("General protection fault"),
        0xE => exception("Page fault"),
        0x10 => exception("x87 floating-point exception"),
        0x11 => exception("Alignment check exception"),
        0x12 => exception("Machine check exception"),
        0x13 => exception("SIMD floating-point exception"),
        0x14 => exception("Virtualization exception"),
        0x1E => exception("Security exception"),
        _ => {
            d("Interrupt: ");
            dh(interrupt as usize);
            dl();
        }
    }

    if interrupt >= 0x20 && interrupt < 0x30 {
        if interrupt >= 0x28 {
            outb(0xA0, 0x20);
        }

        outb(0x20, 0x20);
    }
}

#[lang = "panic_fmt"]
pub extern fn panic_fmt(fmt: fmt::Arguments, file: &'static str, line: u32) -> ! {
    d("PANIC: ");
    d(file);
    d(": ");
    dh(line as usize);
    dl();
    unsafe{
        asm!("cli");
        asm!("hlt");
    }
    loop{}
}

#[no_mangle]
pub extern "C" fn memcmp(a: *mut u8, b: *const u8, len: isize) -> isize {
    unsafe {
        let mut i = 0;
        while i < len {
            let c_a = *a.offset(i);
            let c_b = *b.offset(i);
            if c_a != c_b{
                return c_a as isize - c_b as isize;
            }
            i += 1;
        }
        return 0;
    }
}

#[no_mangle]
pub extern "C" fn memmove(dst: *mut u8, src: *const u8, len: isize){
    unsafe {
        if src < dst {
            let mut i = len;
            while i > 0 {
                i -= 1;
                *dst.offset(i) = *src.offset(i);
            }
        }else{
            let mut i = 0;
            while i < len {
                *dst.offset(i) = *src.offset(i);
                i += 1;
            }
        }
    }
}

#[no_mangle]
pub extern "C" fn memcpy(dst: *mut u8, src: *const u8, len: isize){
    unsafe {
        let mut i = 0;
        while i < len {
            *dst.offset(i) = *src.offset(i);
            i += 1;
        }
    }
}

#[no_mangle]
pub extern "C" fn memset(src: *mut u8, c: i32, len: isize) {
    unsafe {
        let mut i = 0;
        while i < len {
            *src.offset(i) = c as u8;
            i += 1;
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014-2015 Mathias Hällman
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * A key can be of any of the following types:
 *   - Function key such as F1 or F24
 *   - Symbolic key such as enter or escape
 *   - Unicode codepoint such as a, ä, or あ
 * The key also records key modifier information.
 */
#[derive(Copy, PartialEq)]
#[cfg_attr(test, derive(Debug))]
pub enum Key {
  Fn{num: int, mods: KeyMod},
  Sym{sym: KeySym, mods: KeyMod},
  Unicode{codepoint: char, mods: KeyMod},
}

#[derive(Copy, PartialEq)]
#[cfg_attr(test, derive(Debug))]
pub enum KeySym
{
  Unknown = -1,
  None = 0,

  /* Special names in C0 */
  Backspace,
  Tab,
  Enter,
  Escape,

  /* Special names in G0 */
  Space,
  Del,

  /* Special keys */
  Up,
  Down,
  Left,
  Right,
  Begin,
  Find,
  Insert,
  Delete,
  Select,
  Pageup,
  Pagedown,
  Home,
  End,

  /* Special keys from terminfo */
  Cancel,
  Clear,
  Close,
  Command,
  Copy,
  Exit,
  Help,
  Mark,
  Message,
  Move,
  Open,
  Options,
  Print,
  Redo,
  Reference,
  Refresh,
  Replace,
  Restart,
  Resume,
  Save,
  Suspend,
  Undo,

  /* Numeric keypad special keys */
  KP0,
  KP1,
  KP2,
  KP3,
  KP4,
  KP5,
  KP6,
  KP7,
  KP8,
  KP9,
  KPEnter,
  KPPlus,
  KPMinus,
  KPMult,
  KPDiv,
  KPComma,
  KPPeriod,
  KPEquals,

  /* et cetera ad nauseum */
  NSyms,
}

bitflags! {
  #[cfg_attr(test, derive(Debug))]
  flags KeyMod: u8 {
    const MOD_NONE  = 0,
    const MOD_SHIFT = 1 << 0,
    const MOD_ALT   = 1 << 1,
    const MOD_CTRL  = 1 << 2,
  }
}

#[allow(dead_code)]  // as the name suggests, this function should not be called
fn totally_useless_function_just_to_suppress_warnings_about_dead_code() {
  let mut a = MOD_NONE;
  a.toggle(MOD_NONE); a.remove(MOD_NONE); a.intersects(MOD_NONE);
  a.is_all(); KeyMod::from_bits_truncate(0); KeyMod::from_bits(0);
  a.insert(MOD_NONE); a.contains(MOD_NONE);
}
<commit_msg>Hack: skip cfg_attr<commit_after>/*
 * Copyright (c) 2014-2015 Mathias Hällman
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * A key can be of any of the following types:
 *   - Function key such as F1 or F24
 *   - Symbolic key such as enter or escape
 *   - Unicode codepoint such as a, ä, or あ
 * The key also records key modifier information.
 */
#[derive(Copy, PartialEq)]
#[cfg_attr(test, derive(Debug))]
pub enum Key {
  Fn{num: int, mods: KeyMod},
  Sym{sym: KeySym, mods: KeyMod},
  Unicode{codepoint: char, mods: KeyMod},
}

#[derive(Copy, PartialEq)]
#[cfg_attr(test, derive(Debug))]
pub enum KeySym
{
  Unknown = -1,
  None = 0,

  /* Special names in C0 */
  Backspace,
  Tab,
  Enter,
  Escape,

  /* Special names in G0 */
  Space,
  Del,

  /* Special keys */
  Up,
  Down,
  Left,
  Right,
  Begin,
  Find,
  Insert,
  Delete,
  Select,
  Pageup,
  Pagedown,
  Home,
  End,

  /* Special keys from terminfo */
  Cancel,
  Clear,
  Close,
  Command,
  Copy,
  Exit,
  Help,
  Mark,
  Message,
  Move,
  Open,
  Options,
  Print,
  Redo,
  Reference,
  Refresh,
  Replace,
  Restart,
  Resume,
  Save,
  Suspend,
  Undo,

  /* Numeric keypad special keys */
  KP0,
  KP1,
  KP2,
  KP3,
  KP4,
  KP5,
  KP6,
  KP7,
  KP8,
  KP9,
  KPEnter,
  KPPlus,
  KPMinus,
  KPMult,
  KPDiv,
  KPComma,
  KPPeriod,
  KPEquals,

  /* et cetera ad nauseum */
  NSyms,
}

bitflags! {
  #[derive(Debug)]
  flags KeyMod: u8 {
    const MOD_NONE  = 0,
    const MOD_SHIFT = 1 << 0,
    const MOD_ALT   = 1 << 1,
    const MOD_CTRL  = 1 << 2,
  }
}

#[allow(dead_code)]  // as the name suggests, this function should not be called
fn totally_useless_function_just_to_suppress_warnings_about_dead_code() {
  let mut a = MOD_NONE;
  a.toggle(MOD_NONE); a.remove(MOD_NONE); a.intersects(MOD_NONE);
  a.is_all(); KeyMod::from_bits_truncate(0); KeyMod::from_bits(0);
  a.insert(MOD_NONE); a.contains(MOD_NONE);
}
<|endoftext|>


<commit_before>pub struct Keypad {
    row0: u8,
    row1: u8,
    data: u8,
    pub interrupt: u8,
}

#[derive(Copy, Clone)]
pub enum KeypadKey {
    Right,
    Left,
    Up,
    Down,
    A,
    B,
    Select,
    Start,
}

impl Keypad {
    pub fn new() -> Keypad {
        let mut res = Keypad {
            row0: 0x0F,
            row1: 0x0F,
            data: 0,
            interrupt: 0,
        };
        res.update();
        return res
    }

    pub fn rb(&self) -> u8 {
        self.data
    }

    pub fn wb(&mut self, value: u8) {
        self.data = value;
        self.update();
    }

    fn update(&mut self) {
        self.data &= 0x30;
        if self.data & 0x10 == 0x10 { self.data |= self.row0; }
        if self.data & 0x20 == 0x20 { self.data |= self.row1; }
    }

    pub fn keydown(&mut self, key: KeypadKey) {
        match key {
            KeypadKey::Right => self.row1 &= !(1 << 0),
            KeypadKey::Left => self.row1 &= !(1 << 1),
            KeypadKey::Up => self.row1 &= !(1 << 2),
            KeypadKey::Down => self.row1 &= !(1 << 3),
            KeypadKey::A => self.row0 &= !(1 << 0),
            KeypadKey::B => self.row0 &= !(1 << 1),
            KeypadKey::Select => self.row0 &= !(1 << 2),
            KeypadKey::Start => self.row0 &= !(1 << 3),
        }
        self.interrupt |= 0x10;
        self.update();
    }

    pub fn keyup(&mut self, key: KeypadKey) {
        match key {
            KeypadKey::Right => self.row1 |= 1 << 0,
            KeypadKey::Left => self.row1 |= 1 << 1,
            KeypadKey::Up => self.row1 |= 1 << 2,
            KeypadKey::Down => self.row1 |= 1 << 3,
            KeypadKey::A => self.row0 |= 1 << 0,
            KeypadKey::B => self.row0 |= 1 << 1,
            KeypadKey::Select => self.row0 |= 1 << 2,
            KeypadKey::Start => self.row0 |= 1 << 3,
        }
        self.update();
    }
}

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

    #[test]
    fn keys_row0() {
        let mut keypad = super::Keypad::new();
        let keys0 : [KeypadKey; 4] = [KeypadKey::A, KeypadKey::B, KeypadKey::Select, KeypadKey::Start];

        for i in 0 .. keys0.len() {
            keypad.keydown(keys0[i]);

            keypad.wb(0x00);
            assert_eq!(keypad.rb(), 0x00);

            keypad.wb(0x10);
            assert_eq!(keypad.rb(), 0x1F & !(1 << i));

            keypad.wb(0x20);
            assert_eq!(keypad.rb(), 0x2F);

            keypad.wb(0x30);
            assert_eq!(keypad.rb(), 0x3F);

            keypad.keyup(keys0[i]);
        }
    }

    #[test]
    fn keys_row1() {
        let mut keypad = super::Keypad::new();
        let keys1 : [KeypadKey; 4] = [KeypadKey::Right, KeypadKey::Left, KeypadKey::Up, KeypadKey::Down];

        for i in 0 .. keys1.len() {
            keypad.keydown(keys1[i]);

            keypad.wb(0x00);
            assert_eq!(keypad.rb(), 0x00);

            keypad.wb(0x10);
            assert_eq!(keypad.rb(), 0x1F);

            keypad.wb(0x20);
            assert_eq!(keypad.rb(), 0x2F & !(1 << i));

            keypad.wb(0x30);
            assert_eq!(keypad.rb(), 0x3F);

            keypad.keyup(keys1[i]);
        }
    }
}
<commit_msg>Correct the behaviour of the keypad<commit_after>pub struct Keypad {
    row0: u8,
    row1: u8,
    data: u8,
    pub interrupt: u8,
}

#[derive(Copy, Clone)]
pub enum KeypadKey {
    Right,
    Left,
    Up,
    Down,
    A,
    B,
    Select,
    Start,
}

impl Keypad {
    pub fn new() -> Keypad {
        let mut res = Keypad {
            row0: 0x0F,
            row1: 0x0F,
            data: 0xFF,
            interrupt: 0,
        };
        res.update();
        return res
    }

    pub fn rb(&mut self) -> u8 {
        self.data
    }

    pub fn wb(&mut self, value: u8) {
        self.data = 0xC0 | (value & 0x30) | (self.data & 0x0F);
        self.update();
    }

    fn update(&mut self) {
        let old_values = self.data & 0xF;
        let mut new_values = 0xF;

        if self.data & 0x10 == 0x00 {
            new_values &= self.row0;
        }
        if self.data & 0x20 == 0x00 {
            new_values &= self.row1;
        }

        if old_values == 0xF && new_values != 0xF {
            self.interrupt |= 0x10;
        }

        self.data = (self.data & 0xF0) | new_values;
    }

    pub fn keydown(&mut self, key: KeypadKey) {
        match key {
            KeypadKey::Right =>  self.row0 &= !(1 << 0),
            KeypadKey::Left =>   self.row0 &= !(1 << 1),
            KeypadKey::Up =>     self.row0 &= !(1 << 2),
            KeypadKey::Down =>   self.row0 &= !(1 << 3),
            KeypadKey::A =>      self.row1 &= !(1 << 0),
            KeypadKey::B =>      self.row1 &= !(1 << 1),
            KeypadKey::Select => self.row1 &= !(1 << 2),
            KeypadKey::Start =>  self.row1 &= !(1 << 3),
        }

        self.update();
    }

    pub fn keyup(&mut self, key: KeypadKey) {
        match key {
            KeypadKey::Right =>  self.row0 |= 1 << 0,
            KeypadKey::Left =>   self.row0 |= 1 << 1,
            KeypadKey::Up =>     self.row0 |= 1 << 2,
            KeypadKey::Down =>   self.row0 |= 1 << 3,
            KeypadKey::A =>      self.row1 |= 1 << 0,
            KeypadKey::B =>      self.row1 |= 1 << 1,
            KeypadKey::Select => self.row1 |= 1 << 2,
            KeypadKey::Start =>  self.row1 |= 1 << 3,
        }
        self.update();
    }
}

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

    #[test]
    fn keys_buttons() {
        let mut keypad = super::Keypad::new();
        let keys0 : [KeypadKey; 4] = [KeypadKey::A, KeypadKey::B, KeypadKey::Select, KeypadKey::Start];

        for i in 0 .. keys0.len() {
            keypad.keydown(keys0[i]);

            keypad.wb(0x00);
            assert_eq!(keypad.rb(), 0xCF & !(1 << i));

            keypad.wb(0x10);
            assert_eq!(keypad.rb(), 0xDF & !(1 << i));

            keypad.wb(0x20);
            assert_eq!(keypad.rb(), 0xEF);

            keypad.wb(0x30);
            assert_eq!(keypad.rb(), 0xFF);

            keypad.keyup(keys0[i]);
        }
    }

    #[test]
    fn keys_direction() {
        let mut keypad = super::Keypad::new();
        let keys1 : [KeypadKey; 4] = [KeypadKey::Right, KeypadKey::Left, KeypadKey::Up, KeypadKey::Down];

        for i in 0 .. keys1.len() {
            keypad.keydown(keys1[i]);

            keypad.wb(0x00);
            assert_eq!(keypad.rb(), 0xCF & !(1 << i));

            keypad.wb(0x10);
            assert_eq!(keypad.rb(), 0xDF);

            keypad.wb(0x20);
            assert_eq!(keypad.rb(), 0xEF & !(1 << i));

            keypad.wb(0x30);
            assert_eq!(keypad.rb(), 0xFF);

            keypad.keyup(keys1[i]);
        }
    }
}
<|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 color::Color;
use geometry::{DevicePixel, LayerPixel};
use tiling::{Tile, TileGrid};

use geom::matrix::{Matrix4, identity};
use geom::scale_factor::ScaleFactor;
use geom::size::{Size2D, TypedSize2D};
use geom::point::{Point2D, TypedPoint2D};
use geom::rect::{Rect, TypedRect};
use platform::surface::{NativeCompositingGraphicsContext, NativePaintingGraphicsContext};
use platform::surface::NativeSurface;
use std::cell::{RefCell, RefMut};
use std::rc::Rc;

#[derive(Clone, Copy, PartialEq, PartialOrd)]
pub struct ContentAge {
    age: usize,
}

impl ContentAge {
    pub fn new() -> ContentAge {
        ContentAge {
            age: 0,
        }
    }

    pub fn next(&mut self) {
        self.age += 1;
    }
}

pub struct Layer<T> {
    pub children: RefCell<Vec<Rc<Layer<T>>>>,
    pub transform: RefCell<Matrix4<f32>>,
    pub tile_size: usize,
    pub extra_data: RefCell<T>,
    tile_grid: RefCell<TileGrid>,

    /// The boundaries of this layer in the coordinate system of the parent layer.
    pub bounds: RefCell<TypedRect<LayerPixel, f32>>,

    /// A monotonically increasing counter that keeps track of the current content age.
    pub content_age: RefCell<ContentAge>,

    /// The content offset for this layer in unscaled layer pixels.
    pub content_offset: RefCell<TypedPoint2D<LayerPixel, f32>>,

    /// Whether this layer clips its children to its boundaries.
    pub masks_to_bounds: RefCell<bool>,

    /// The background color for this layer.
    pub background_color: RefCell<Color>,

    /// The opacity of this layer, from 0.0 (fully transparent) to 1.0 (fully opaque).
    pub opacity: RefCell<f32>,
}

impl<T> Layer<T> {
    pub fn new(bounds: TypedRect<LayerPixel, f32>,
               tile_size: usize,
               background_color: Color,
               opacity: f32,
               data: T)
               -> Layer<T> {
        Layer {
            children: RefCell::new(vec!()),
            transform: RefCell::new(identity()),
            bounds: RefCell::new(bounds),
            tile_size: tile_size,
            extra_data: RefCell::new(data),
            tile_grid: RefCell::new(TileGrid::new(tile_size)),
            content_age: RefCell::new(ContentAge::new()),
            masks_to_bounds: RefCell::new(false),
            content_offset: RefCell::new(Point2D::zero()),
            background_color: RefCell::new(background_color),
            opacity: RefCell::new(opacity),
        }
    }

    pub fn children<'a>(&'a self) -> RefMut<'a,Vec<Rc<Layer<T>>>> {
        self.children.borrow_mut()
    }

    pub fn add_child(&self, new_child: Rc<Layer<T>>) {
        self.children().push(new_child);
    }

    pub fn remove_child_at_index(&self, index: usize) {
        self.children().remove(index);
    }

    pub fn get_buffer_requests(&self,
                               rect_in_layer: TypedRect<LayerPixel, f32>,
                               scale: ScaleFactor<LayerPixel, DevicePixel, f32>)
                               -> Vec<BufferRequest> {
        let mut tile_grid = self.tile_grid.borrow_mut();
        return tile_grid.get_buffer_requests_in_rect(rect_in_layer * scale,
                                                     self.bounds.borrow().size * scale,
                                                     *self.content_age.borrow());
    }

    pub fn resize(&self, new_size: TypedSize2D<LayerPixel, f32>) {
        self.bounds.borrow_mut().size = new_size;
    }

    pub fn add_buffer(&self, tile: Box<LayerBuffer>) {
        self.tile_grid.borrow_mut().add_buffer(tile);
    }

    pub fn collect_unused_buffers(&self) -> Vec<Box<LayerBuffer>> {
        self.tile_grid.borrow_mut().take_unused_buffers()
    }

    pub fn collect_buffers(&self) -> Vec<Box<LayerBuffer>> {
        self.tile_grid.borrow_mut().collect_buffers()
    }

    pub fn contents_changed(&self) {
        self.content_age.borrow_mut().next();
    }

    pub fn create_textures(&self, graphics_context: &NativeCompositingGraphicsContext) {
        self.tile_grid.borrow_mut().create_textures(graphics_context);
    }

    pub fn do_for_all_tiles<F: Fn(&Tile)>(&self, f: F) {
        self.tile_grid.borrow().do_for_all_tiles(f);
    }
}

/// A request from the compositor to the renderer for tiles that need to be (re)displayed.
#[derive(Clone, Copy)]
pub struct BufferRequest {
    // The rect in pixels that will be drawn to the screen
    pub screen_rect: Rect<usize>,

    // The rect in page coordinates that this tile represents
    pub page_rect: Rect<f32>,

    /// The content age of that this BufferRequest corresponds to.
    pub content_age: ContentAge,
}

impl BufferRequest {
    pub fn new(screen_rect: Rect<usize>,
               page_rect: Rect<f32>,
               content_age: ContentAge)
               -> BufferRequest {
        BufferRequest {
            screen_rect: screen_rect,
            page_rect: page_rect,
            content_age: content_age,
        }
    }
}

pub struct LayerBuffer {
    /// The native surface which can be shared between threads or processes. On Mac this is an
    /// `IOSurface`; on Linux this is an X Pixmap; on Android this is an `EGLImageKHR`.
    pub native_surface: NativeSurface,

    /// The rect in the containing RenderLayer that this represents.
    pub rect: Rect<f32>,

    /// The rect in pixels that will be drawn to the screen.
    pub screen_pos: Rect<usize>,

    /// The scale at which this tile is rendered
    pub resolution: f32,

    /// NB: stride is in pixels, like OpenGL GL_UNPACK_ROW_LENGTH.
    pub stride: usize,

    /// Whether or not this buffer was painted with the CPU rasterization.
    pub painted_with_cpu: bool,

    /// The content age of that this buffer request corresponds to.
    pub content_age: ContentAge,
}

impl LayerBuffer {
    /// Returns the amount of memory used by the tile
    pub fn get_mem(&self) -> usize {
        // This works for now, but in the future we may want a better heuristic
        self.screen_pos.size.width * self.screen_pos.size.height
    }

    /// Returns true if the tile is displayable at the given scale
    pub fn is_valid(&self, scale: f32) -> bool {
        (self.resolution - scale).abs() < 1.0e-6
    }

    /// Returns the Size2D of the tile
    pub fn get_size_2d(&self) -> Size2D<usize> {
        self.screen_pos.size
    }

    /// Marks the layer buffer as not leaking. See comments on
    /// `NativeSurfaceMethods::mark_wont_leak` for how this is used.
    pub fn mark_wont_leak(&mut self) {
        self.native_surface.mark_wont_leak()
    }

    /// Destroys the layer buffer. Painting task only.
    pub fn destroy(self, graphics_context: &NativePaintingGraphicsContext) {
        let mut this = self;
        this.native_surface.destroy(graphics_context)
    }
}

/// A set of layer buffers. This is an atomic unit used to switch between the front and back
/// buffers.
pub struct LayerBufferSet {
    pub buffers: Vec<Box<LayerBuffer>>
}

impl LayerBufferSet {
    /// Notes all buffer surfaces will leak if not destroyed via a call to `destroy`.
    pub fn mark_will_leak(&mut self) {
        for buffer in self.buffers.iter_mut() {
            buffer.native_surface.mark_will_leak()
        }
    }
}
<commit_msg>Minor indentation cleanup.<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 color::Color;
use geometry::{DevicePixel, LayerPixel};
use tiling::{Tile, TileGrid};

use geom::matrix::{Matrix4, identity};
use geom::scale_factor::ScaleFactor;
use geom::size::{Size2D, TypedSize2D};
use geom::point::{Point2D, TypedPoint2D};
use geom::rect::{Rect, TypedRect};
use platform::surface::{NativeCompositingGraphicsContext, NativePaintingGraphicsContext};
use platform::surface::NativeSurface;
use std::cell::{RefCell, RefMut};
use std::rc::Rc;

#[derive(Clone, Copy, PartialEq, PartialOrd)]
pub struct ContentAge {
    age: usize,
}

impl ContentAge {
    pub fn new() -> ContentAge {
        ContentAge {
            age: 0,
        }
    }

    pub fn next(&mut self) {
        self.age += 1;
    }
}

pub struct Layer<T> {
    pub children: RefCell<Vec<Rc<Layer<T>>>>,
    pub transform: RefCell<Matrix4<f32>>,
    pub tile_size: usize,
    pub extra_data: RefCell<T>,
    tile_grid: RefCell<TileGrid>,

    /// The boundaries of this layer in the coordinate system of the parent layer.
    pub bounds: RefCell<TypedRect<LayerPixel, f32>>,

    /// A monotonically increasing counter that keeps track of the current content age.
    pub content_age: RefCell<ContentAge>,

    /// The content offset for this layer in unscaled layer pixels.
    pub content_offset: RefCell<TypedPoint2D<LayerPixel, f32>>,

    /// Whether this layer clips its children to its boundaries.
    pub masks_to_bounds: RefCell<bool>,

    /// The background color for this layer.
    pub background_color: RefCell<Color>,

    /// The opacity of this layer, from 0.0 (fully transparent) to 1.0 (fully opaque).
    pub opacity: RefCell<f32>,
}

impl<T> Layer<T> {
    pub fn new(bounds: TypedRect<LayerPixel, f32>,
               tile_size: usize,
               background_color: Color,
               opacity: f32,
               data: T)
               -> Layer<T> {
        Layer {
            children: RefCell::new(vec!()),
            transform: RefCell::new(identity()),
            bounds: RefCell::new(bounds),
            tile_size: tile_size,
            extra_data: RefCell::new(data),
            tile_grid: RefCell::new(TileGrid::new(tile_size)),
            content_age: RefCell::new(ContentAge::new()),
            masks_to_bounds: RefCell::new(false),
            content_offset: RefCell::new(Point2D::zero()),
            background_color: RefCell::new(background_color),
            opacity: RefCell::new(opacity),
        }
    }

    pub fn children<'a>(&'a self) -> RefMut<'a,Vec<Rc<Layer<T>>>> {
        self.children.borrow_mut()
    }

    pub fn add_child(&self, new_child: Rc<Layer<T>>) {
        self.children().push(new_child);
    }

    pub fn remove_child_at_index(&self, index: usize) {
        self.children().remove(index);
    }

    pub fn get_buffer_requests(&self,
                               rect_in_layer: TypedRect<LayerPixel, f32>,
                               scale: ScaleFactor<LayerPixel, DevicePixel, f32>)
                               -> Vec<BufferRequest> {
        let mut tile_grid = self.tile_grid.borrow_mut();
        return tile_grid.get_buffer_requests_in_rect(rect_in_layer * scale,
                                                     self.bounds.borrow().size * scale,
                                                     *self.content_age.borrow());
    }

    pub fn resize(&self, new_size: TypedSize2D<LayerPixel, f32>) {
        self.bounds.borrow_mut().size = new_size;
    }

    pub fn add_buffer(&self, tile: Box<LayerBuffer>) {
        self.tile_grid.borrow_mut().add_buffer(tile);
    }

    pub fn collect_unused_buffers(&self) -> Vec<Box<LayerBuffer>> {
        self.tile_grid.borrow_mut().take_unused_buffers()
    }

    pub fn collect_buffers(&self) -> Vec<Box<LayerBuffer>> {
        self.tile_grid.borrow_mut().collect_buffers()
    }

    pub fn contents_changed(&self) {
        self.content_age.borrow_mut().next();
    }

    pub fn create_textures(&self, graphics_context: &NativeCompositingGraphicsContext) {
        self.tile_grid.borrow_mut().create_textures(graphics_context);
    }

    pub fn do_for_all_tiles<F: Fn(&Tile)>(&self, f: F) {
        self.tile_grid.borrow().do_for_all_tiles(f);
    }
}

/// A request from the compositor to the renderer for tiles that need to be (re)displayed.
#[derive(Clone, Copy)]
pub struct BufferRequest {
    // The rect in pixels that will be drawn to the screen
    pub screen_rect: Rect<usize>,

    // The rect in page coordinates that this tile represents
    pub page_rect: Rect<f32>,

    /// The content age of that this BufferRequest corresponds to.
    pub content_age: ContentAge,
}

impl BufferRequest {
    pub fn new(screen_rect: Rect<usize>, page_rect: Rect<f32>, content_age: ContentAge)
               -> BufferRequest {
        BufferRequest {
            screen_rect: screen_rect,
            page_rect: page_rect,
            content_age: content_age,
        }
    }
}

pub struct LayerBuffer {
    /// The native surface which can be shared between threads or processes. On Mac this is an
    /// `IOSurface`; on Linux this is an X Pixmap; on Android this is an `EGLImageKHR`.
    pub native_surface: NativeSurface,

    /// The rect in the containing RenderLayer that this represents.
    pub rect: Rect<f32>,

    /// The rect in pixels that will be drawn to the screen.
    pub screen_pos: Rect<usize>,

    /// The scale at which this tile is rendered
    pub resolution: f32,

    /// NB: stride is in pixels, like OpenGL GL_UNPACK_ROW_LENGTH.
    pub stride: usize,

    /// Whether or not this buffer was painted with the CPU rasterization.
    pub painted_with_cpu: bool,

    /// The content age of that this buffer request corresponds to.
    pub content_age: ContentAge,
}

impl LayerBuffer {
    /// Returns the amount of memory used by the tile
    pub fn get_mem(&self) -> usize {
        // This works for now, but in the future we may want a better heuristic
        self.screen_pos.size.width * self.screen_pos.size.height
    }

    /// Returns true if the tile is displayable at the given scale
    pub fn is_valid(&self, scale: f32) -> bool {
        (self.resolution - scale).abs() < 1.0e-6
    }

    /// Returns the Size2D of the tile
    pub fn get_size_2d(&self) -> Size2D<usize> {
        self.screen_pos.size
    }

    /// Marks the layer buffer as not leaking. See comments on
    /// `NativeSurfaceMethods::mark_wont_leak` for how this is used.
    pub fn mark_wont_leak(&mut self) {
        self.native_surface.mark_wont_leak()
    }

    /// Destroys the layer buffer. Painting task only.
    pub fn destroy(self, graphics_context: &NativePaintingGraphicsContext) {
        let mut this = self;
        this.native_surface.destroy(graphics_context)
    }
}

/// A set of layer buffers. This is an atomic unit used to switch between the front and back
/// buffers.
pub struct LayerBufferSet {
    pub buffers: Vec<Box<LayerBuffer>>
}

impl LayerBufferSet {
    /// Notes all buffer surfaces will leak if not destroyed via a call to `destroy`.
    pub fn mark_will_leak(&mut self) {
        for buffer in self.buffers.iter_mut() {
            buffer.native_surface.mark_will_leak()
        }
    }
}
<|endoftext|>