<commit_before>/// The query resolver that operates on the AST and the TOML object

use std::ops::Deref;
use std::ops::IndexMut;

use toml::Value;
use tokenizer::Token;
use error::*;

fn resolve<'doc>(toml: &'doc mut Value, tokens: &Token) -> Result<&'doc mut Value> {
    match toml {
        &mut Value::Table(ref mut t) => {
            match tokens {
                &Token::Identifier { ident: ref ident, .. } => {
                    match t.get_mut(ident) {
                        None    => {
                            let ek = ErrorKind::IdentifierNotFoundInDocument(ident.clone());
                            Err(Error::from(ek))
                        },
                        Some(sub_document) => {
                            if tokens.has_next() {
                                resolve(sub_document, tokens.next().unwrap().deref())
                            } else {
                                Ok(sub_document)
                            }
                        },
                    }
                },

                &Token::Index { idx: i, .. } => {
                    let kind = ErrorKind::NoIndexInTable(i);
                    Err(Error::from(kind))
                },
            }
        },

        &mut Value::Array(ref mut ary) => {
            match tokens {
                &Token::Index { idx: i, .. } => {
                    if tokens.has_next() {
                        resolve(ary.get_mut(i).unwrap(), tokens.next().unwrap().deref())
                    } else {
                        Ok(ary.index_mut(i))
                    }
                },
                &Token::Identifier { ident: ref ident, .. } => {
                    let kind = ErrorKind::NoIdentifierInArray(ident.clone());
                    Err(Error::from(kind))
                },
            }
        },

        _ => {
            match tokens {
                &Token::Identifier { ident: ref ident, .. } => {
                    Err(Error::from(ErrorKind::QueryingValueAsTable(ident.clone())))
                },

                &Token::Index { idx: i, .. } => {
                    Err(Error::from(ErrorKind::QueryingValueAsArray(i)))
                },
            }
        }
    }
}

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

    macro_rules! do_resolve {
        ( $toml:ident => $query:expr ) => {
            resolve(&mut $toml, &tokenize_with_seperator(&String::from($query), '.').unwrap())
        }
    }

    #[test]
    fn test_resolve_empty_toml_simple_query() {
        let mut toml = toml_from_str("").unwrap();
        let result = do_resolve!(toml => "example");

        assert!(result.is_err());
        let result = result.unwrap_err();

        let errkind = result.kind();
        assert!(is_match!(errkind, &ErrorKind::IdentifierNotFoundInDocument { .. }));
    }

    #[test]
    fn test_resolve_present_bool() {
        let mut toml = toml_from_str("example = true").unwrap();
        let result = do_resolve!(toml => "example");

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

        assert!(is_match!(result, &mut Value::Boolean(true)));
    }

    #[test]
    fn test_resolve_present_integer() {
        let mut toml = toml_from_str("example = 1").unwrap();
        let result = do_resolve!(toml => "example");

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

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

    #[test]
    fn test_resolve_present_float() {
        let mut toml = toml_from_str("example = 1.0").unwrap();
        let result = do_resolve!(toml => "example");

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

        assert!(is_match!(result, &mut Value::Float(1.0)));
    }

    #[test]
    fn test_resolve_present_string() {
        let mut toml = toml_from_str("example = 'string'").unwrap();
        let result = do_resolve!(toml => "example");

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

        assert!(is_match!(result, &mut Value::String(_)));
        match result {
            &mut Value::String(ref s) => assert_eq!("string", s),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_resolve_present_array_bools() {
        let mut toml = toml_from_str("example = [ true, false ]").unwrap();
        let result = do_resolve!(toml => "example");

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

        assert!(is_match!(result, &mut Value::Array(_)));
        match result {
            &mut Value::Array(ref ary) => {
                assert_eq!(ary[0], Value::Boolean(true));
                assert_eq!(ary[1], Value::Boolean(false));
            },
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_resolve_present_array_integers() {
        let mut toml = toml_from_str("example = [ 1, 1337 ]").unwrap();
        let result = do_resolve!(toml => "example");

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

        assert!(is_match!(result, &mut Value::Array(_)));
        match result {
            &mut Value::Array(ref ary) => {
                assert_eq!(ary[0], Value::Integer(1));
                assert_eq!(ary[1], Value::Integer(1337));
            },
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_resolve_present_array_floats() {
        let mut toml = toml_from_str("example = [ 1.0, 133.25 ]").unwrap();
        let result = do_resolve!(toml => "example");

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

        assert!(is_match!(result, &mut Value::Array(_)));
        match result {
            &mut Value::Array(ref ary) => {
                assert_eq!(ary[0], Value::Float(1.0));
                assert_eq!(ary[1], Value::Float(133.25));
            },
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_resolve_array_index_query_1() {
        let mut toml = toml_from_str("example = [ 1 ]").unwrap();
        let result = do_resolve!(toml => "example.[0]");

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

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

    #[test]
    fn test_resolve_array_index_query_2() {
        let mut toml = toml_from_str("example = [ 1, 2, 3, 4, 5 ]").unwrap();
        let result = do_resolve!(toml => "example.[4]");

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

        assert!(is_match!(result, &mut Value::Integer(5)));
    }

    #[test]
    fn test_resolve_table_element_query() {
        let mut toml = toml_from_str(r#"
        [table]
        value = 42
        "#).unwrap();
        let result = do_resolve!(toml => "table.value");

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

        assert!(is_match!(result, &mut Value::Integer(42)));
    }

    #[test]
    fn test_resolve_table_with_many_elements_element_query() {
        let mut toml = toml_from_str(r#"
        [table]
        value1 = 42
        value2 = 43
        value3 = 44
        value4 = 45
        value5 = 46
        "#).unwrap();
        let result = do_resolve!(toml => "table.value1");

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

        assert!(is_match!(result, &mut Value::Integer(42)));
    }

    #[test]
    fn test_resolve_table_array_query() {
        let mut toml = toml_from_str(r#"
        [table]
        value1 = [ 42.0, 50.0 ]
        "#).unwrap();
        let result = do_resolve!(toml => "table.value1");

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

        assert!(is_match!(result, &mut Value::Array(_)));
        match result {
            &mut Value::Array(ref ary) => {
                assert_eq!(ary[0], Value::Float(42.0));
                assert_eq!(ary[1], Value::Float(50.0));
            },
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_resolve_table_array_element_query() {
        let mut toml = toml_from_str(r#"
        [table]
        value1 = [ 42 ]
        "#).unwrap();
        let result = do_resolve!(toml => "table.value1.[0]");

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

        assert!(is_match!(result, &mut Value::Integer(42)));
    }

    #[test]
    fn test_resolve_multi_table_query() {
        let mut toml = toml_from_str(r#"
        [table0]
        value = [ 1 ]
        [table1]
        value = [ "Foo" ]
        [table2]
        value = [ 42.0 ]
        [table3]
        value = [ true ]
        "#).unwrap();
        let result = do_resolve!(toml => "table1.value.[0]");

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

        assert!(is_match!(result, &mut Value::String(_)));
        match result {
            &mut Value::String(ref s) => assert_eq!("Foo", s),
            _ => panic!("What just happened?"),
        }
    }

    static FRUIT_TABLE : &'static str = r#"
    [[fruit.blah]]
      name = "apple"

      [fruit.blah.physical]
        color = "red"
        shape = "round"

    [[fruit.blah]]
      name = "banana"

      [fruit.blah.physical]
        color = "yellow"
        shape = "bent"
    "#;

    #[test]
    fn test_resolve_array_table_query_1() {
        let mut toml = toml_from_str(FRUIT_TABLE).unwrap();
        let result = do_resolve!(toml => "fruit.blah.[0].name");

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

        assert!(is_match!(result, &mut Value::String(_)));
        match result {
            &mut Value::String(ref s) => assert_eq!("apple", s),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_resolve_array_table_query_2() {
        let mut toml = toml_from_str(FRUIT_TABLE).unwrap();
        let result = do_resolve!(toml => "fruit.blah.[0].physical");

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

        assert!(is_match!(result, &mut Value::Table(_)));
        match result {
            &mut Value::Table(ref tab) => {
                match tab.get("color") {
                    Some(&Value::String(ref s)) => assert_eq!("red", s),
                    _ => assert!(false),
                }
                match tab.get("shape") {
                    Some(&Value::String(ref s)) => assert_eq!("round", s),
                    _ => assert!(false),
                }
            },
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_resolve_query_on_result() {
        let mut toml = toml_from_str(FRUIT_TABLE).unwrap();
        let result = do_resolve!(toml => "fruit.blah.[1].physical");

        assert!(result.is_ok());
        let mut result = result.unwrap();

        let tokens = tokenize_with_seperator(&String::from("color"), '.').unwrap();
        let result = resolve(result, &tokens);

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

        assert!(is_match!(result, &mut Value::String(_)));
        match result {
            &mut Value::String(ref s) => assert_eq!("yellow", s),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_resolve_query_empty_table() {
        let mut toml = toml_from_str(r#"
        [example]
        "#).unwrap();
        let result = do_resolve!(toml => "example");

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

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

    #[test]
    fn test_resolve_query_member_of_empty_table() {
        let mut toml = toml_from_str(r#"
        [example]
        "#).unwrap();
        let result = do_resolve!(toml => "example.foo");

        assert!(result.is_err());
        let result = result.unwrap_err();

        let errkind = result.kind();
        assert!(is_match!(errkind, &ErrorKind::IdentifierNotFoundInDocument { .. }));
    }

    #[test]
    fn test_resolve_query_index_in_table() {
        let mut toml = toml_from_str(r#"
        [example]
        "#).unwrap();
        let result = do_resolve!(toml => "example.[0]");

        assert!(result.is_err());
        let result = result.unwrap_err();

        let errkind = result.kind();
        assert!(is_match!(errkind, &ErrorKind::NoIndexInTable { .. }));
    }

    #[test]
    fn test_resolve_query_identifier_in_array() {
        let mut toml = toml_from_str(r#"
        [example]
        foo = [ 1, 2, 3 ]
        "#).unwrap();
        let result = do_resolve!(toml => "example.foo.bar");

        assert!(result.is_err());
        let result = result.unwrap_err();

        let errkind = result.kind();
        assert!(is_match!(errkind, &ErrorKind::NoIdentifierInArray { .. }));
    }

    #[test]
    fn test_resolve_query_value_as_table() {
        let mut toml = toml_from_str(r#"
        [example]
        foo = 1
        "#).unwrap();
        let result = do_resolve!(toml => "example.foo.bar");

        assert!(result.is_err());
        let result = result.unwrap_err();

        let errkind = result.kind();
        assert!(is_match!(errkind, &ErrorKind::QueryingValueAsTable { .. }));
    }

    #[test]
    fn test_resolve_query_value_as_array() {
        let mut toml = toml_from_str(r#"
        [example]
        foo = 1
        "#).unwrap();
        let result = do_resolve!(toml => "example.foo.[0]");

        assert!(result.is_err());
        let result = result.unwrap_err();

        let errkind = result.kind();
        assert!(is_match!(errkind, &ErrorKind::QueryingValueAsArray { .. }));
    }

}
<commit_msg>Refactor: Simplify some statements<commit_after>/// The query resolver that operates on the AST and the TOML object

use std::ops::Deref;
use std::ops::IndexMut;

use toml::Value;
use tokenizer::Token;
use error::*;

fn resolve<'doc>(toml: &'doc mut Value, tokens: &Token) -> Result<&'doc mut Value> {
    match toml {
        &mut Value::Table(ref mut t) => {
            match tokens {
                &Token::Identifier { ident: ref ident, .. } => {
                    match t.get_mut(ident) {
                        None    => {
                            let ek = ErrorKind::IdentifierNotFoundInDocument(ident.clone());
                            Err(Error::from(ek))
                        },
                        Some(sub_document) => {
                            match tokens.next() {
                                Some(next) => resolve(sub_document, next),
                                None => Ok(sub_document),
                            }
                        },
                    }
                },

                &Token::Index { idx: i, .. } => {
                    let kind = ErrorKind::NoIndexInTable(i);
                    Err(Error::from(kind))
                },
            }
        },

        &mut Value::Array(ref mut ary) => {
            match tokens {
                &Token::Index { idx: i, .. } => {
                    match tokens.next() {
                        Some(next) => resolve(ary.get_mut(i).unwrap(), next),
                        None       => Ok(ary.index_mut(i)),
                    }
                },
                &Token::Identifier { ident: ref ident, .. } => {
                    let kind = ErrorKind::NoIdentifierInArray(ident.clone());
                    Err(Error::from(kind))
                },
            }
        },

        _ => match tokens {
            &Token::Identifier { ident: ref ident, .. } => {
                Err(Error::from(ErrorKind::QueryingValueAsTable(ident.clone())))
            },

            &Token::Index { idx: i, .. } => {
                Err(Error::from(ErrorKind::QueryingValueAsArray(i)))
            },
        }
    }
}

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

    macro_rules! do_resolve {
        ( $toml:ident => $query:expr ) => {
            resolve(&mut $toml, &tokenize_with_seperator(&String::from($query), '.').unwrap())
        }
    }

    #[test]
    fn test_resolve_empty_toml_simple_query() {
        let mut toml = toml_from_str("").unwrap();
        let result = do_resolve!(toml => "example");

        assert!(result.is_err());
        let result = result.unwrap_err();

        let errkind = result.kind();
        assert!(is_match!(errkind, &ErrorKind::IdentifierNotFoundInDocument { .. }));
    }

    #[test]
    fn test_resolve_present_bool() {
        let mut toml = toml_from_str("example = true").unwrap();
        let result = do_resolve!(toml => "example");

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

        assert!(is_match!(result, &mut Value::Boolean(true)));
    }

    #[test]
    fn test_resolve_present_integer() {
        let mut toml = toml_from_str("example = 1").unwrap();
        let result = do_resolve!(toml => "example");

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

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

    #[test]
    fn test_resolve_present_float() {
        let mut toml = toml_from_str("example = 1.0").unwrap();
        let result = do_resolve!(toml => "example");

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

        assert!(is_match!(result, &mut Value::Float(1.0)));
    }

    #[test]
    fn test_resolve_present_string() {
        let mut toml = toml_from_str("example = 'string'").unwrap();
        let result = do_resolve!(toml => "example");

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

        assert!(is_match!(result, &mut Value::String(_)));
        match result {
            &mut Value::String(ref s) => assert_eq!("string", s),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_resolve_present_array_bools() {
        let mut toml = toml_from_str("example = [ true, false ]").unwrap();
        let result = do_resolve!(toml => "example");

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

        assert!(is_match!(result, &mut Value::Array(_)));
        match result {
            &mut Value::Array(ref ary) => {
                assert_eq!(ary[0], Value::Boolean(true));
                assert_eq!(ary[1], Value::Boolean(false));
            },
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_resolve_present_array_integers() {
        let mut toml = toml_from_str("example = [ 1, 1337 ]").unwrap();
        let result = do_resolve!(toml => "example");

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

        assert!(is_match!(result, &mut Value::Array(_)));
        match result {
            &mut Value::Array(ref ary) => {
                assert_eq!(ary[0], Value::Integer(1));
                assert_eq!(ary[1], Value::Integer(1337));
            },
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_resolve_present_array_floats() {
        let mut toml = toml_from_str("example = [ 1.0, 133.25 ]").unwrap();
        let result = do_resolve!(toml => "example");

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

        assert!(is_match!(result, &mut Value::Array(_)));
        match result {
            &mut Value::Array(ref ary) => {
                assert_eq!(ary[0], Value::Float(1.0));
                assert_eq!(ary[1], Value::Float(133.25));
            },
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_resolve_array_index_query_1() {
        let mut toml = toml_from_str("example = [ 1 ]").unwrap();
        let result = do_resolve!(toml => "example.[0]");

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

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

    #[test]
    fn test_resolve_array_index_query_2() {
        let mut toml = toml_from_str("example = [ 1, 2, 3, 4, 5 ]").unwrap();
        let result = do_resolve!(toml => "example.[4]");

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

        assert!(is_match!(result, &mut Value::Integer(5)));
    }

    #[test]
    fn test_resolve_table_element_query() {
        let mut toml = toml_from_str(r#"
        [table]
        value = 42
        "#).unwrap();
        let result = do_resolve!(toml => "table.value");

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

        assert!(is_match!(result, &mut Value::Integer(42)));
    }

    #[test]
    fn test_resolve_table_with_many_elements_element_query() {
        let mut toml = toml_from_str(r#"
        [table]
        value1 = 42
        value2 = 43
        value3 = 44
        value4 = 45
        value5 = 46
        "#).unwrap();
        let result = do_resolve!(toml => "table.value1");

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

        assert!(is_match!(result, &mut Value::Integer(42)));
    }

    #[test]
    fn test_resolve_table_array_query() {
        let mut toml = toml_from_str(r#"
        [table]
        value1 = [ 42.0, 50.0 ]
        "#).unwrap();
        let result = do_resolve!(toml => "table.value1");

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

        assert!(is_match!(result, &mut Value::Array(_)));
        match result {
            &mut Value::Array(ref ary) => {
                assert_eq!(ary[0], Value::Float(42.0));
                assert_eq!(ary[1], Value::Float(50.0));
            },
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_resolve_table_array_element_query() {
        let mut toml = toml_from_str(r#"
        [table]
        value1 = [ 42 ]
        "#).unwrap();
        let result = do_resolve!(toml => "table.value1.[0]");

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

        assert!(is_match!(result, &mut Value::Integer(42)));
    }

    #[test]
    fn test_resolve_multi_table_query() {
        let mut toml = toml_from_str(r#"
        [table0]
        value = [ 1 ]
        [table1]
        value = [ "Foo" ]
        [table2]
        value = [ 42.0 ]
        [table3]
        value = [ true ]
        "#).unwrap();
        let result = do_resolve!(toml => "table1.value.[0]");

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

        assert!(is_match!(result, &mut Value::String(_)));
        match result {
            &mut Value::String(ref s) => assert_eq!("Foo", s),
            _ => panic!("What just happened?"),
        }
    }

    static FRUIT_TABLE : &'static str = r#"
    [[fruit.blah]]
      name = "apple"

      [fruit.blah.physical]
        color = "red"
        shape = "round"

    [[fruit.blah]]
      name = "banana"

      [fruit.blah.physical]
        color = "yellow"
        shape = "bent"
    "#;

    #[test]
    fn test_resolve_array_table_query_1() {
        let mut toml = toml_from_str(FRUIT_TABLE).unwrap();
        let result = do_resolve!(toml => "fruit.blah.[0].name");

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

        assert!(is_match!(result, &mut Value::String(_)));
        match result {
            &mut Value::String(ref s) => assert_eq!("apple", s),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_resolve_array_table_query_2() {
        let mut toml = toml_from_str(FRUIT_TABLE).unwrap();
        let result = do_resolve!(toml => "fruit.blah.[0].physical");

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

        assert!(is_match!(result, &mut Value::Table(_)));
        match result {
            &mut Value::Table(ref tab) => {
                match tab.get("color") {
                    Some(&Value::String(ref s)) => assert_eq!("red", s),
                    _ => assert!(false),
                }
                match tab.get("shape") {
                    Some(&Value::String(ref s)) => assert_eq!("round", s),
                    _ => assert!(false),
                }
            },
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_resolve_query_on_result() {
        let mut toml = toml_from_str(FRUIT_TABLE).unwrap();
        let result = do_resolve!(toml => "fruit.blah.[1].physical");

        assert!(result.is_ok());
        let mut result = result.unwrap();

        let tokens = tokenize_with_seperator(&String::from("color"), '.').unwrap();
        let result = resolve(result, &tokens);

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

        assert!(is_match!(result, &mut Value::String(_)));
        match result {
            &mut Value::String(ref s) => assert_eq!("yellow", s),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_resolve_query_empty_table() {
        let mut toml = toml_from_str(r#"
        [example]
        "#).unwrap();
        let result = do_resolve!(toml => "example");

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

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

    #[test]
    fn test_resolve_query_member_of_empty_table() {
        let mut toml = toml_from_str(r#"
        [example]
        "#).unwrap();
        let result = do_resolve!(toml => "example.foo");

        assert!(result.is_err());
        let result = result.unwrap_err();

        let errkind = result.kind();
        assert!(is_match!(errkind, &ErrorKind::IdentifierNotFoundInDocument { .. }));
    }

    #[test]
    fn test_resolve_query_index_in_table() {
        let mut toml = toml_from_str(r#"
        [example]
        "#).unwrap();
        let result = do_resolve!(toml => "example.[0]");

        assert!(result.is_err());
        let result = result.unwrap_err();

        let errkind = result.kind();
        assert!(is_match!(errkind, &ErrorKind::NoIndexInTable { .. }));
    }

    #[test]
    fn test_resolve_query_identifier_in_array() {
        let mut toml = toml_from_str(r#"
        [example]
        foo = [ 1, 2, 3 ]
        "#).unwrap();
        let result = do_resolve!(toml => "example.foo.bar");

        assert!(result.is_err());
        let result = result.unwrap_err();

        let errkind = result.kind();
        assert!(is_match!(errkind, &ErrorKind::NoIdentifierInArray { .. }));
    }

    #[test]
    fn test_resolve_query_value_as_table() {
        let mut toml = toml_from_str(r#"
        [example]
        foo = 1
        "#).unwrap();
        let result = do_resolve!(toml => "example.foo.bar");

        assert!(result.is_err());
        let result = result.unwrap_err();

        let errkind = result.kind();
        assert!(is_match!(errkind, &ErrorKind::QueryingValueAsTable { .. }));
    }

    #[test]
    fn test_resolve_query_value_as_array() {
        let mut toml = toml_from_str(r#"
        [example]
        foo = 1
        "#).unwrap();
        let result = do_resolve!(toml => "example.foo.[0]");

        assert!(result.is_err());
        let result = result.unwrap_err();

        let errkind = result.kind();
        assert!(is_match!(errkind, &ErrorKind::QueryingValueAsArray { .. }));
    }

}
<|endoftext|>


<commit_before>extern crate parking_lot;
extern crate owning_ref;

use parking_lot::{RwLock, RwLockWriteGuard, RwLockReadGuard};
use owning_ref::{OwningHandle, OwningRef};
use std::sync::atomic::{self, AtomicUsize};
use std::hash::{self, Hash, Hasher};
use std::{mem, ops};

const ORDERING: atomic::Ordering = atomic::Ordering::SeqCst;
const LENGTH_MULTIPLIER: usize = 4;
const MAX_LOAD_FACTOR_NUM: usize = 100 - 15;
const MAX_LOAD_FACTOR_DENOM: usize = 100;

fn hash<K: Hash>(key: K) -> usize {
    let mut h = hash::SipHasher::new();
    key.hash(&mut h);
    h.finish() as usize
}

enum Bucket<K, V> {
    Contains(K, V),
    Removed,
    Empty,
}

impl<K, V> Bucket<K, V> {
    fn remove(&mut self) -> Bucket<K, V> {
        mem::replace(self, Bucket::Removed)
    }

    fn value(self) -> Option<V> {
        if let Bucket::Contains(_, val) = self {
            Some(val)
        } else { None }
    }
}

struct Table<K, V> {
    buckets: Vec<RwLock<Bucket<K, V>>>,
}

impl<K: PartialEq + Hash, V> Table<K, V> {
    fn scan<F>(&self, key: &K, matches: F) -> RwLockReadGuard<Bucket<K, V>>
        where F: Fn(&Bucket<K, V>) -> bool {
        let hash = hash(key);
        let len = self.buckets.len();

        for i in 0.. {
            let lock = self.buckets[(hash + i) % len].read();

            if matches(&lock) {
                return lock;
            }
        }

        unreachable!();
    }

    fn scan_mut<F>(&self, key: &K, matches: F) -> RwLockWriteGuard<Bucket<K, V>>
        where F: Fn(&Bucket<K, V>) -> bool {
        let hash = hash(key);
        let len = self.buckets.len();

        for i in 0.. {
            let lock = self.buckets[(hash + i) % len].write();

            if matches(&lock) {
                return lock;
            }
        }

        unreachable!();
    }

    fn scan_mut_no_lock<F>(&mut self, key: &K, matches: F) -> &mut Bucket<K, V>
        where F: Fn(&Bucket<K, V>) -> bool {
        let hash = hash(key);
        let len = self.buckets.len();

        for i in 0.. {
            let bucket = self.buckets[(hash + i) % len].get_mut();

            if matches(&bucket) {
                return bucket;
            }
        }

        unreachable!();
    }

    fn lookup(&self, key: &K) -> RwLockReadGuard<Bucket<K, V>> {
        self.scan(key, |x| match *x {
            Bucket::Contains(ref candidate_key, _) if key == candidate_key => true,
            Bucket::Empty => true,
            _ => false,
        })
    }

    fn lookup_mut(&self, key: &K) -> RwLockWriteGuard<Bucket<K, V>> {
        self.scan_mut(key, |x| match *x {
            Bucket::Contains(ref candidate_key, _) if key == candidate_key => true,
            Bucket::Empty => true,
            _ => false,
        })
    }

    fn find_free(&self, key: &K) -> RwLockWriteGuard<Bucket<K, V>> {
        self.scan_mut(key, |x| match *x {
            // Halt if and only if the bucket is free.
            Bucket::Removed | Bucket::Empty => true,
            _ => false,
        })
    }

    fn fill(&mut self, table: Vec<RwLock<Bucket<K, V>>>) {
        for mut i in table {
            if let Bucket::Contains(key, val) = i.get_mut().remove() {
                let mut bucket = self.scan_mut_no_lock(&key, |x| match *x {
                    Bucket::Removed | Bucket::Empty => true,
                    _ => false,
                });

                *bucket = Bucket::Contains(key, val);
            }
        }
    }
}

pub struct ReadGuard<'a, K: 'a, V: 'a> {
    inner: OwningRef<OwningHandle<RwLockReadGuard<'a, Table<K, V>>, RwLockReadGuard<'a, Bucket<K, V>>>, V>,
}

impl<'a, K, V> ops::Deref for ReadGuard<'a, K, V> {
    type Target = V;

    fn deref(&self) -> &V {
        &self.inner
    }
}

pub struct WriteGuard<'a, K: 'a, V: 'a> {
    inner: OwningHandle<OwningHandle<RwLockReadGuard<'a, Table<K, V>>, RwLockWriteGuard<'a, Bucket<K, V>>>, &'a mut V>,
}

impl<'a, K, V> ops::Deref for WriteGuard<'a, K, V> {
    type Target = V;

    fn deref(&self) -> &V {
        &self.inner
    }
}

impl<'a, K, V> ops::DerefMut for WriteGuard<'a, K, V> {
    fn deref_mut(&mut self) -> &mut V {
        &mut self.inner
    }
}

pub struct CHashMap<K, V> {
    total: AtomicUsize,
    table: RwLock<Table<K, V>>,
}

impl<K: PartialEq + Hash, V> CHashMap<K, V> {
    pub fn get(&self, key: &K) -> Option<ReadGuard<K, V>> {
        if let Ok(inner) = OwningRef::new(OwningHandle::new(self.table.read(), |x| unsafe { &*x }.lookup(key)))
            .try_map(|x| if let Bucket::Contains(_, ref val) = *x {
            Ok(val)
        } else {
            Err(())
        }) {
            Some(ReadGuard {
                inner: inner,
            })
        } else { None }
    }

    pub fn get_mut(&self, key: &K) -> Option<WriteGuard<K, V>> {
        if let Ok(inner) = OwningHandle::try_new(OwningHandle::new(self.table.read(), |x| unsafe { &*x }.lookup_mut(key)), |x| if let &mut Bucket::Contains(_, ref mut val) = unsafe { &mut *(x as *mut Bucket<K, V>) } {
            Ok(val)
        } else {
            Err(())
        }) {
            Some(WriteGuard {
                inner: inner,
            })
        } else { None }
    }

    pub fn insert(&self, key: K, val: V) {
        let lock = self.expand();
        let mut bucket = lock.find_free(&key);

        *bucket = Bucket::Contains(key, val);
    }

    pub fn replace(&self, key: K, val: V) -> Option<V> {
        let lock = self.expand();
        let mut bucket = lock.lookup_mut(&key);

        mem::replace(&mut *bucket, Bucket::Contains(key, val)).value()
    }

    pub fn remove(&self, key: &K) -> Option<V> {
        let lock = self.table.read();
        self.total.fetch_sub(1, ORDERING);

        let mut bucket = lock.lookup_mut(&key);
        bucket.remove().value()
    }

    pub fn reserve(&self, len: usize) {
        if self.total.load(ORDERING) < len {
            let mut lock = self.table.write();
            let vec = mem::replace(&mut lock.buckets, Vec::with_capacity(len * LENGTH_MULTIPLIER));
            lock.fill(vec);
        }
    }

    pub fn shrink_to_fit(&self) {
        let mut lock = self.table.write();
        let vec = mem::replace(&mut lock.buckets, Vec::with_capacity(self.total.load(ORDERING) * LENGTH_MULTIPLIER));
        lock.fill(vec);
    }

    fn expand(&self) -> RwLockReadGuard<Table<K, V>> {
        let lock = self.table.read();
        let total = self.total.fetch_add(1, ORDERING);

        // Extend if necessary. We multiply by some constant to adjust our load factor.
        if total * MAX_LOAD_FACTOR_DENOM >= lock.buckets.len() * MAX_LOAD_FACTOR_NUM {
            drop(lock);
            self.reserve(total + 1);
            self.table.read()
        } else {
            lock
        }
    }
}
<commit_msg>Add initializers to `CHashMap`.<commit_after>extern crate parking_lot;
extern crate owning_ref;

use parking_lot::{RwLock, RwLockWriteGuard, RwLockReadGuard};
use owning_ref::{OwningHandle, OwningRef};
use std::sync::atomic::{self, AtomicUsize};
use std::hash::{self, Hash, Hasher};
use std::{mem, ops};

const ORDERING: atomic::Ordering = atomic::Ordering::SeqCst;
const LENGTH_MULTIPLIER: usize = 4;
const MAX_LOAD_FACTOR_NUM: usize = 100 - 15;
const MAX_LOAD_FACTOR_DENOM: usize = 100;
const DEFAULT_INITIAL_SIZE: usize = 32;

fn hash<K: Hash>(key: K) -> usize {
    let mut h = hash::SipHasher::new();
    key.hash(&mut h);
    h.finish() as usize
}

enum Bucket<K, V> {
    Contains(K, V),
    Removed,
    Empty,
}

impl<K, V> Bucket<K, V> {
    fn remove(&mut self) -> Bucket<K, V> {
        mem::replace(self, Bucket::Removed)
    }

    fn value(self) -> Option<V> {
        if let Bucket::Contains(_, val) = self {
            Some(val)
        } else { None }
    }
}

struct Table<K, V> {
    buckets: Vec<RwLock<Bucket<K, V>>>,
}

impl<K: PartialEq + Hash, V> Table<K, V> {
    fn with_capacity(cap: usize) -> Table<K, V> {
        // TODO: For some obscure reason `RwLock` doesn't implement `Clone`.
        let mut vec = Vec::with_capacity(cap);
        for _ in 0..cap {
            vec.push(RwLock::new(Bucket::Empty));
        }

        Table {
            buckets: vec,
        }
    }

    fn scan<F>(&self, key: &K, matches: F) -> RwLockReadGuard<Bucket<K, V>>
        where F: Fn(&Bucket<K, V>) -> bool {
        let hash = hash(key);
        let len = self.buckets.len();

        for i in 0.. {
            let lock = self.buckets[(hash + i) % len].read();

            if matches(&lock) {
                return lock;
            }
        }

        unreachable!();
    }

    fn scan_mut<F>(&self, key: &K, matches: F) -> RwLockWriteGuard<Bucket<K, V>>
        where F: Fn(&Bucket<K, V>) -> bool {
        let hash = hash(key);
        let len = self.buckets.len();

        for i in 0.. {
            let lock = self.buckets[(hash + i) % len].write();

            if matches(&lock) {
                return lock;
            }
        }

        unreachable!();
    }

    fn scan_mut_no_lock<F>(&mut self, key: &K, matches: F) -> &mut Bucket<K, V>
        where F: Fn(&Bucket<K, V>) -> bool {
        let hash = hash(key);
        let len = self.buckets.len();

        for i in 0.. {
            let bucket = self.buckets[(hash + i) % len].get_mut();

            if matches(&bucket) {
                return bucket;
            }
        }

        unreachable!();
    }

    fn lookup(&self, key: &K) -> RwLockReadGuard<Bucket<K, V>> {
        self.scan(key, |x| match *x {
            Bucket::Contains(ref candidate_key, _) if key == candidate_key => true,
            Bucket::Empty => true,
            _ => false,
        })
    }

    fn lookup_mut(&self, key: &K) -> RwLockWriteGuard<Bucket<K, V>> {
        self.scan_mut(key, |x| match *x {
            Bucket::Contains(ref candidate_key, _) if key == candidate_key => true,
            Bucket::Empty => true,
            _ => false,
        })
    }

    fn find_free(&self, key: &K) -> RwLockWriteGuard<Bucket<K, V>> {
        self.scan_mut(key, |x| match *x {
            // Halt if and only if the bucket is free.
            Bucket::Removed | Bucket::Empty => true,
            _ => false,
        })
    }

    fn fill(&mut self, table: Table<K, V>) {
        for mut i in table.buckets {
            if let Bucket::Contains(key, val) = i.get_mut().remove() {
                let mut bucket = self.scan_mut_no_lock(&key, |x| match *x {
                    Bucket::Removed | Bucket::Empty => true,
                    _ => false,
                });

                *bucket = Bucket::Contains(key, val);
            }
        }
    }
}

pub struct ReadGuard<'a, K: 'a, V: 'a> {
    inner: OwningRef<OwningHandle<RwLockReadGuard<'a, Table<K, V>>, RwLockReadGuard<'a, Bucket<K, V>>>, V>,
}

impl<'a, K, V> ops::Deref for ReadGuard<'a, K, V> {
    type Target = V;

    fn deref(&self) -> &V {
        &self.inner
    }
}

pub struct WriteGuard<'a, K: 'a, V: 'a> {
    inner: OwningHandle<OwningHandle<RwLockReadGuard<'a, Table<K, V>>, RwLockWriteGuard<'a, Bucket<K, V>>>, &'a mut V>,
}

impl<'a, K, V> ops::Deref for WriteGuard<'a, K, V> {
    type Target = V;

    fn deref(&self) -> &V {
        &self.inner
    }
}

impl<'a, K, V> ops::DerefMut for WriteGuard<'a, K, V> {
    fn deref_mut(&mut self) -> &mut V {
        &mut self.inner
    }
}

pub struct CHashMap<K, V> {
    total: AtomicUsize,
    table: RwLock<Table<K, V>>,
}

impl<K, V> CHashMap<K, V> {
    pub fn with_capacity(cap: usize) -> CHashMap<K, V> {
        CHashMap {
            total: AtomicUsize::new(0),
            table: RwLock::new(Table::with_capacity(cap)),
        }
    }

    pub fn new() -> CHashMap<K, V> {
        CHashMap::with_capacity(DEFAULT_INITIAL_SIZE)
    }
}

impl<K: PartialEq + Hash, V> CHashMap<K, V> {
    pub fn get(&self, key: &K) -> Option<ReadGuard<K, V>> {
        if let Ok(inner) = OwningRef::new(OwningHandle::new(self.table.read(), |x| unsafe { &*x }.lookup(key)))
            .try_map(|x| if let Bucket::Contains(_, ref val) = *x {
            Ok(val)
        } else {
            Err(())
        }) {
            Some(ReadGuard {
                inner: inner,
            })
        } else { None }
    }

    pub fn get_mut(&self, key: &K) -> Option<WriteGuard<K, V>> {
        if let Ok(inner) = OwningHandle::try_new(OwningHandle::new(self.table.read(), |x| unsafe { &*x }.lookup_mut(key)), |x| if let &mut Bucket::Contains(_, ref mut val) = unsafe { &mut *(x as *mut Bucket<K, V>) } {
            Ok(val)
        } else {
            Err(())
        }) {
            Some(WriteGuard {
                inner: inner,
            })
        } else { None }
    }

    pub fn insert(&self, key: K, val: V) {
        let lock = self.expand();
        let mut bucket = lock.find_free(&key);

        *bucket = Bucket::Contains(key, val);
    }

    pub fn replace(&self, key: K, val: V) -> Option<V> {
        let lock = self.expand();
        let mut bucket = lock.lookup_mut(&key);

        mem::replace(&mut *bucket, Bucket::Contains(key, val)).value()
    }

    pub fn remove(&self, key: &K) -> Option<V> {
        let lock = self.table.read();

        let mut bucket = lock.lookup_mut(&key);
        let ret = bucket.remove().value();

        if ret.is_some() {
            self.total.fetch_sub(1, ORDERING);
        }

        ret
    }

    pub fn reserve(&self, additional: usize) {
        let len = self.total.load(ORDERING) + additional;
        let mut lock = self.table.write();
        let table = mem::replace(&mut *lock, Table::with_capacity(len * LENGTH_MULTIPLIER));
        lock.fill(table);
    }

    pub fn shrink_to_fit(&self) {
        let mut lock = self.table.write();
        let table = mem::replace(&mut *lock, Table::with_capacity(self.total.load(ORDERING) * LENGTH_MULTIPLIER));
        lock.fill(table);
    }

    fn expand(&self) -> RwLockReadGuard<Table<K, V>> {
        let lock = self.table.read();
        let total = self.total.fetch_add(1, ORDERING) + 1;

        // Extend if necessary. We multiply by some constant to adjust our load factor.
        if total * MAX_LOAD_FACTOR_DENOM >= lock.buckets.len() * MAX_LOAD_FACTOR_NUM {
            drop(lock);

            {
                let mut lock = self.table.write();
                let table = mem::replace(&mut *lock, Table::with_capacity(total * LENGTH_MULTIPLIER));
                lock.fill(table);
            }

            self.table.read()
        } else {
            lock
        }
    }
}

impl<K, V> Default for CHashMap<K, V> {
    fn default() -> CHashMap<K, V> {
        CHashMap::new()
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 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.

#![allow(bad_style)]

extern crate "rust-netmap" as netmap;
extern crate libc;

use libc::{c_void, size_t, c_int, c_ulong, c_short};
use self::netmap::netmap_user::{nm_open, nm_inject, nm_close, nm_nextpkt, nm_desc, nm_pkthdr,
                                NETMAP_FD};

use std::ffi::CString;
use std::io::{IoResult, IoError};
use std::mem;
use std::ptr;
use std::raw;
use std::sync::Arc;

use datalink::DataLinkChannelType;
use packet::Packet;
use packet::ethernet::{EthernetHeader, MutableEthernetHeader};
use util::{NetworkInterface};

#[cfg(target_os = "linux")]
#[repr(C)]
struct pollfd {
    fd: c_int,
    events: c_short,
    revents: c_short
}

#[cfg(target_os = "linux")]
const POLLIN: c_short = 0x0001;
#[cfg(target_os = "linux")]
const POLLOUT: c_short = 0x0004;

type nfds_t = c_ulong;

extern {
    fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: c_int) -> c_int;
}

struct NmDesc {
    desc: *mut nm_desc,
}

impl NmDesc {
    fn new(iface: &NetworkInterface) -> IoResult<NmDesc> {
        let ifname = CString::from_slice(("netmap:".to_string() + iface.name.as_slice()).as_bytes());
        let desc = unsafe {
            nm_open(ifname.as_ptr(), ptr::null(), 0, ptr::null())
        };

        if desc.is_null() {
            Err(IoError::last_error())
        } else {
            Ok(NmDesc {
                desc: desc
            })
        }
    }
}

impl Drop for NmDesc {
    fn drop(&mut self) {
        unsafe {
            nm_close(self.desc);
        }
    }
}

pub struct DataLinkSenderImpl {
    desc: Arc<NmDesc>
}

impl DataLinkSenderImpl {
    // FIXME This is incredibly inefficient
    pub fn build_and_send<F>(&mut self, num_packets: usize, packet_size: usize,
                          func: &mut F) -> Option<IoResult<()>>
        where F : FnMut(MutableEthernetHeader)
    {
        for _ in range(0, num_packets) {
            let mut vec: Vec<u8> = Vec::with_capacity(packet_size);
            {
                let meh = MutableEthernetHeader::new(vec.as_mut_slice());
                func(meh);
            }

            if let None = self.send_to(EthernetHeader::new(vec.as_slice()), None) {
                // FIXME This is wrong
                return None;
            }
        }

        Some(Ok(()))
    }

    pub fn send_to(&mut self, packet: EthernetHeader, _dst: Option<NetworkInterface>)
        -> Option<IoResult<()>> {
        let mut fds = pollfd {
            fd: unsafe { NETMAP_FD(self.desc.desc) },
            events: POLLOUT,
            revents: 0,
        };
        unsafe { poll(&mut fds, 1, -1) };
        if unsafe {

               nm_inject(self.desc.desc,
                         packet.packet().as_ptr() as *const c_void,
                         packet.packet().len() as size_t)
           } > 0 {
            Some(Ok(()))
        } else {
            // FIXME This is wrong
            None
        }
    }
}

pub struct DataLinkReceiverImpl {
    desc: Arc<NmDesc>,
}

impl DataLinkReceiverImpl {
    // FIXME Layer 3
    pub fn iter<'a>(&'a mut self) -> DataLinkChannelIteratorImpl<'a> {
        DataLinkChannelIteratorImpl {
            pc: self,
        }
    }
}

pub fn datalink_channel(network_interface: &NetworkInterface,
                        _write_buffer_size: usize,
                        _read_buffer_size: usize,
                        _channel_type: DataLinkChannelType)
    -> IoResult<(DataLinkSenderImpl, DataLinkReceiverImpl)> {
    // FIXME probably want one for each of send/recv
    let desc = NmDesc::new(network_interface);
    match desc {
        Ok(desc) => {
            let arc = Arc::new(desc);

            Ok((DataLinkSenderImpl { desc: arc.clone() },
                DataLinkReceiverImpl { desc: arc }))
        },
        Err(e) => Err(e)
    }
}

pub struct DataLinkChannelIteratorImpl<'a> {
    pc: &'a mut DataLinkReceiverImpl,
}

impl<'a> DataLinkChannelIteratorImpl<'a> {
    pub fn next<'c>(&'c mut self) -> IoResult<EthernetHeader<'c>> {
        let mut fds = pollfd {
            fd: unsafe { NETMAP_FD(self.pc.desc.desc) },
            events: POLLIN,
            revents: 0,
        };
        // FIXME Don't do this with each call
        // FIXME Check error code
        // FIXME epoll/kqueue
        unsafe { poll(&mut fds, 1, -1) };
        let mut h: nm_pkthdr = unsafe { mem::zeroed() };
        let buf = unsafe { nm_nextpkt(self.pc.desc.desc, &mut h) };
        if buf.is_null() {
            // FIXME Doesn't mean there's an error
            return Err(IoError::last_error());
        }
        Ok(EthernetHeader::new( unsafe {
            mem::transmute(raw::Slice { data: buf, len: h.len as usize })
        }))
    }
}

<commit_msg>More efficient implementations for send and receive with netmap.<commit_after>// Copyright (c) 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.

#![allow(bad_style)]

extern crate "rust-netmap" as netmap;
extern crate libc;

use libc::{c_int, c_uint, c_ulong, c_short};
use self::netmap::netmap_user::{nm_open, nm_close, nm_nextpkt, nm_desc, nm_pkthdr,
                                nm_ring_next, NETMAP_TXRING, NETMAP_FD, NETMAP_BUF};
use self::netmap::netmap::{nm_ring_empty, netmap_slot};

use std::ffi::CString;
use std::path::Path;
use std::io::fs::File;
use std::io::{IoResult, IoError};
use std::mem;
use std::num;
use std::ptr;
use std::raw;
use std::sync::Arc;

use datalink::DataLinkChannelType;
use packet::Packet;
use packet::ethernet::{EthernetHeader, MutableEthernetHeader};
use util::{NetworkInterface};

#[cfg(target_os = "linux")]
#[repr(C)]
struct pollfd {
    fd: c_int,
    events: c_short,
    revents: c_short
}

#[cfg(target_os = "linux")]
const POLLIN: c_short = 0x0001;
#[cfg(target_os = "linux")]
const POLLOUT: c_short = 0x0004;

type nfds_t = c_ulong;

extern {
    fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: c_int) -> c_int;
}

struct NmDesc {
    desc: *mut nm_desc,
    buf_size: c_uint,
}

impl NmDesc {
    fn new(iface: &NetworkInterface) -> IoResult<NmDesc> {
        let ifname = CString::from_slice(("netmap:".to_string() + iface.name.as_slice()).as_bytes());
        let desc = unsafe {
            nm_open(ifname.as_ptr(), ptr::null(), 0, ptr::null())
        };

        if desc.is_null() {
            Err(IoError::last_error())
        } else {
            let mut f = try!(File::open(&Path::new("/sys/module/netmap/parameters/buf_size")));
            let num_str = try!(f.read_to_string());
            let buf_size = num_str.trim_right().parse().unwrap();

            Ok(NmDesc {
                desc: desc,
                buf_size: buf_size
            })
        }
    }
}

impl Drop for NmDesc {
    fn drop(&mut self) {
        unsafe {
            nm_close(self.desc);
        }
    }
}

pub struct DataLinkSenderImpl {
    desc: Arc<NmDesc>
}

impl DataLinkSenderImpl {
    pub fn build_and_send<F>(&mut self, num_packets: usize, packet_size: usize,
                          func: &mut F) -> Option<IoResult<()>>
        where F : FnMut(MutableEthernetHeader)
    {
        assert!(num::cast::<usize, u16>(packet_size).unwrap() as c_uint <= self.desc.buf_size);
        let desc = self.desc.desc;
        let mut fds = pollfd {
            fd: unsafe { NETMAP_FD(desc) },
            events: POLLOUT,
            revents: 0,
        };
        let mut packet_idx = 0us;
        while packet_idx < num_packets {
            unsafe {
                if poll(&mut fds, 1, -1) < 0 {
                    return Some(Err(IoError::last_error()));
                }
                let ring = NETMAP_TXRING((*desc).nifp, 0);
                while !nm_ring_empty(ring) && packet_idx < num_packets {
                    let i = (*ring).cur;
                    let slot_ptr: *mut netmap_slot = mem::transmute(&mut (*ring).slot);
                    let buf = NETMAP_BUF(ring, (*slot_ptr.offset(i as isize)).buf_idx as isize);
                    let slice = raw::Slice { data: buf, len: packet_size };
                    let meh = MutableEthernetHeader::new(mem::transmute(slice));
                    (*slot_ptr.offset(i as isize)).len = packet_size as u16;
                    func(meh);
                    let next = nm_ring_next(ring, i);
                    (*ring).head = next;
                    (*ring).cur =  next;
                    packet_idx += 1;
                }
            }
        }

        Some(Ok(()))
    }

    pub fn send_to(&mut self, packet: EthernetHeader, _dst: Option<NetworkInterface>)
        -> Option<IoResult<()>> {
        use packet::MutablePacket;
        self.build_and_send(1, packet.packet().len(), &mut |&mut:mut eh: MutableEthernetHeader| {
            eh.clone_from(packet);
        })
    }
}

pub struct DataLinkReceiverImpl {
    desc: Arc<NmDesc>,
}

impl DataLinkReceiverImpl {
    // FIXME Layer 3
    pub fn iter<'a>(&'a mut self) -> DataLinkChannelIteratorImpl<'a> {
        DataLinkChannelIteratorImpl {
            pc: self,
        }
    }
}

pub fn datalink_channel(network_interface: &NetworkInterface,
                        _write_buffer_size: usize,
                        _read_buffer_size: usize,
                        _channel_type: DataLinkChannelType)
    -> IoResult<(DataLinkSenderImpl, DataLinkReceiverImpl)> {
    // FIXME probably want one for each of send/recv
    let desc = NmDesc::new(network_interface);
    match desc {
        Ok(desc) => {
            let arc = Arc::new(desc);

            Ok((DataLinkSenderImpl { desc: arc.clone() },
                DataLinkReceiverImpl { desc: arc }))
        },
        Err(e) => Err(e)
    }
}

pub struct DataLinkChannelIteratorImpl<'a> {
    pc: &'a mut DataLinkReceiverImpl,
}

impl<'a> DataLinkChannelIteratorImpl<'a> {
    pub fn next<'c>(&'c mut self) -> IoResult<EthernetHeader<'c>> {
        let desc = self.pc.desc.desc;
        let mut h: nm_pkthdr = unsafe { mem::uninitialized() };
        let mut buf = unsafe { nm_nextpkt(desc, &mut h) };
        if buf.is_null() {
            let mut fds = pollfd {
                fd: unsafe { NETMAP_FD(desc) },
                events: POLLIN,
                revents: 0,
            };
            if unsafe { poll(&mut fds, 1, -1) } < 0 {
                return Err(IoError::last_error());
            }
            buf = unsafe { nm_nextpkt(desc, &mut h) };
        }
        Ok(EthernetHeader::new( unsafe {
            mem::transmute(raw::Slice { data: buf, len: h.len as usize })
        }))
    }
}

<|endoftext|>


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

extern crate gl;
extern crate glfw;

use gl::types::*;
use glfw::{Context, OpenGlProfileHint, WindowHint, WindowMode};
use std::mem;
use std::ptr;
use std::str;
use std::ffi::CString;

// Vertex data
static VERTEX_DATA: [GLfloat; 6] = [
     0.0,  0.5,
     0.5, -0.5,
    -0.5, -0.5
];

// Shader sources
static VS_SRC: &'static str =
   "#version 150\n\
    in vec2 position;\n\
    void main() {\n\
       gl_Position = vec4(position, 0.0, 1.0);\n\
    }";

static FS_SRC: &'static str =
   "#version 150\n\
    out vec4 out_color;\n\
    void main() {\n\
       out_color = vec4(1.0, 1.0, 1.0, 1.0);\n\
    }";

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader;
    unsafe {
        shader = gl::CreateShader(ty);
        // Attempt to compile the shader
        let c_str = CString::from_slice(src.as_bytes());
        gl::ShaderSource(shader, 1, &c_str.as_ptr(), ptr::null());
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::with_capacity(len as usize);
            buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
            panic!("{}", str::from_utf8(buf.as_slice()).ok().expect("ShaderInfoLog not valid utf8"));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint { unsafe {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    gl::LinkProgram(program);
    // Get the link status
    let mut status = gl::FALSE as GLint;
    gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
        let mut len: GLint = 0;
        gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
        let mut buf = Vec::with_capacity(len as usize);
        buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
        gl::GetProgramInfoLog(program, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
        panic!("{}", str::from_utf8(buf.as_slice()).ok().expect("ProgramInfoLog not valid utf8"));
    }
    program
} }

fn main() {
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    // Choose a GL profile that is compatible with OS X 10.7+
    glfw.window_hint(WindowHint::ContextVersion(3, 2));
    glfw.window_hint(WindowHint::OpenglForwardCompat(true));
    glfw.window_hint(WindowHint::OpenglProfile(OpenGlProfileHint::Core));

    let (mut window, _) = glfw.create_window(800, 600, "OpenGL", WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    // It is essential to make the context current before calling `gl::load_with`.
    window.make_current();

    // Load the OpenGL function pointers
    gl::load_with(|s| window.get_proc_address(s));

    // Create GLSL shaders
    let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER);
    let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER);
    let program = link_program(vs, fs);

    let mut vao = 0;
    let mut vbo = 0;

    unsafe {
        // Create Vertex Array Object
        gl::GenVertexArrays(1, &mut vao);
        gl::BindVertexArray(vao);

        // Create a Vertex Buffer Object and copy the vertex data to it
        gl::GenBuffers(1, &mut vbo);
        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(gl::ARRAY_BUFFER,
                       (VERTEX_DATA.len() * mem::size_of::<GLfloat>()) as GLsizeiptr,
                       mem::transmute(&VERTEX_DATA[0]),
                       gl::STATIC_DRAW);

        // Use shader program
        gl::UseProgram(program);
        gl::BindFragDataLocation(program, 0,
                                 CString::from_slice(b"out_color").as_ptr());

        // Specify the layout of the vertex data
        let pos_attr = gl::GetAttribLocation(program,
                                             CString::from_slice(b"position").as_ptr());
        gl::EnableVertexAttribArray(pos_attr as GLuint);
        gl::VertexAttribPointer(pos_attr as GLuint, 2, gl::FLOAT,
                                gl::FALSE as GLboolean, 0, ptr::null());
    }

    while !window.should_close() {
        // Poll events
        glfw.poll_events();

        unsafe {
            // Clear the screen to black
            gl::ClearColor(0.3, 0.3, 0.3, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // Draw a triangle from the 3 vertices
            gl::DrawArrays(gl::TRIANGLES, 0, 3);
        }

        // Swap buffers
        window.swap_buffers();
    }

    unsafe {
    // Cleanup
        gl::DeleteProgram(program);
        gl::DeleteShader(fs);
        gl::DeleteShader(vs);
        gl::DeleteBuffers(1, &vbo);
        gl::DeleteVertexArrays(1, &vao);
    }
}
<commit_msg>Update static_triangle example<commit_after>// Copyright 2013 The gl-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate gl;
extern crate glfw;

use gl::types::*;
use glfw::{Context, OpenGlProfileHint, WindowHint, WindowMode};
use std::mem;
use std::ptr;
use std::str;
use std::ffi::CString;

// Vertex data
static VERTEX_DATA: [GLfloat; 6] = [
     0.0,  0.5,
     0.5, -0.5,
    -0.5, -0.5
];

// Shader sources
static VS_SRC: &'static str =
   "#version 150\n\
    in vec2 position;\n\
    void main() {\n\
       gl_Position = vec4(position, 0.0, 1.0);\n\
    }";

static FS_SRC: &'static str =
   "#version 150\n\
    out vec4 out_color;\n\
    void main() {\n\
       out_color = vec4(1.0, 1.0, 1.0, 1.0);\n\
    }";

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader;
    unsafe {
        shader = gl::CreateShader(ty);
        // Attempt to compile the shader
        let c_str = CString::new(src.as_bytes()).unwrap();
        gl::ShaderSource(shader, 1, &c_str.as_ptr(), ptr::null());
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::with_capacity(len as usize);
            buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
            panic!("{}", str::from_utf8(&buf).ok().expect("ShaderInfoLog not valid utf8"));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint { unsafe {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    gl::LinkProgram(program);
    // Get the link status
    let mut status = gl::FALSE as GLint;
    gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
        let mut len: GLint = 0;
        gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
        let mut buf = Vec::with_capacity(len as usize);
        buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
        gl::GetProgramInfoLog(program, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
        panic!("{}", str::from_utf8(&buf).ok().expect("ProgramInfoLog not valid utf8"));
    }
    program
} }

fn main() {
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    // Choose a GL profile that is compatible with OS X 10.7+
    glfw.window_hint(WindowHint::ContextVersion(3, 2));
    glfw.window_hint(WindowHint::OpenGlForwardCompat(true));
    glfw.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core));

    let (mut window, _) = glfw.create_window(800, 600, "OpenGL", WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    // It is essential to make the context current before calling `gl::load_with`.
    window.make_current();

    // Load the OpenGL function pointers
    gl::load_with(|s| window.get_proc_address(s));

    // Create GLSL shaders
    let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER);
    let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER);
    let program = link_program(vs, fs);

    let mut vao = 0;
    let mut vbo = 0;

    unsafe {
        // Create Vertex Array Object
        gl::GenVertexArrays(1, &mut vao);
        gl::BindVertexArray(vao);

        // Create a Vertex Buffer Object and copy the vertex data to it
        gl::GenBuffers(1, &mut vbo);
        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(gl::ARRAY_BUFFER,
                       (VERTEX_DATA.len() * mem::size_of::<GLfloat>()) as GLsizeiptr,
                       mem::transmute(&VERTEX_DATA[0]),
                       gl::STATIC_DRAW);

        // Use shader program
        gl::UseProgram(program);
        gl::BindFragDataLocation(program, 0,
                                 CString::new("out_color").unwrap().as_ptr());

        // Specify the layout of the vertex data
        let pos_attr = gl::GetAttribLocation(program,
                                             CString::new("position").unwrap().as_ptr());
        gl::EnableVertexAttribArray(pos_attr as GLuint);
        gl::VertexAttribPointer(pos_attr as GLuint, 2, gl::FLOAT,
                                gl::FALSE as GLboolean, 0, ptr::null());
    }

    while !window.should_close() {
        // Poll events
        glfw.poll_events();

        unsafe {
            // Clear the screen to black
            gl::ClearColor(0.3, 0.3, 0.3, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // Draw a triangle from the 3 vertices
            gl::DrawArrays(gl::TRIANGLES, 0, 3);
        }

        // Swap buffers
        window.swap_buffers();
    }

    unsafe {
    // Cleanup
        gl::DeleteProgram(program);
        gl::DeleteShader(fs);
        gl::DeleteShader(vs);
        gl::DeleteBuffers(1, &vbo);
        gl::DeleteVertexArrays(1, &vao);
    }
}
<|endoftext|>


<commit_before>use nix::unistd::getpid;
use rosxmlrpc::{Response, ResponseError, Server};
use std::net::SocketAddr;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use futures::sync::mpsc::Sender;
use super::error::{self, ErrorKind, Result};
use tcpros::{Publisher, Subscriber, Service};
use xml_rpc::{self, Value};

pub struct SlaveHandler {
    pub subscriptions: Arc<Mutex<HashMap<String, Subscriber>>>,
    pub publications: Arc<Mutex<HashMap<String, Publisher>>>,
    pub services: Arc<Mutex<HashMap<String, Service>>>,
    server: Server,
}

impl SlaveHandler {
    pub fn new(
        master_uri: &str,
        hostname: &str,
        name: &str,
        shutdown_signal: Sender<()>,
    ) -> SlaveHandler {
        use futures::Sink;

        let mut server = Server::default();

        server.register_value("getBusStats", "Bus stats", |_args| {
            // TODO: implement actual stats displaying
            Err(ResponseError::Server("Method not implemented".into()))
        });

        server.register_value("getBusInfo", "Bus info", |_args| {
            // TODO: implement actual info displaying
            Err(ResponseError::Server("Method not implemented".into()))
        });

        let master_uri_string = String::from(master_uri);

        server.register_value("getMasterUri", "Master URI", move |_args| {
            Ok(Value::String(master_uri_string.clone()))
        });

        server.register_value("shutdown", "Shutdown", move |args| {
            let mut args = args.into_iter();
            let _caller_id = args.next().ok_or(ResponseError::Client(
                "Missing argument 'caller_id'".into(),
            ))?;
            let message = match args.next() {
                Some(Value::String(message)) => message,
                _ => return Err(ResponseError::Client("Missing argument 'message'".into())),
            };
            info!("Server is shutting down because: {}", message);
            match shutdown_signal.clone().wait().send(()) {
                Ok(()) => Ok(Value::Int(0)),
                Err(err) => {
                    error!("Shutdown error: {:?}", err);
                    Err(ResponseError::Server("Failed to shut down".into()))
                }
            }
        });

        server.register_value("getPid", "PID", |_args| Ok(Value::Int(getpid())));

        let subscriptions = Arc::new(Mutex::new(HashMap::<String, Subscriber>::new()));
        let subs = subscriptions.clone();

        server.register_value("getSubscriptions", "List of subscriptions", move |_args| {
            Ok(Value::Array(
                subs.lock()
                    .expect(FAILED_TO_LOCK)
                    .values()
                    .map(|ref v| {
                        Value::Array(vec![
                            Value::String(v.topic.clone()),
                            Value::String(v.msg_type.clone()),
                        ])
                    })
                    .collect(),
            ))
        });

        let publications = Arc::new(Mutex::new(HashMap::<String, Publisher>::new()));
        let pubs = publications.clone();

        server.register_value("getPublications", "List of publications", move |_args| {
            Ok(Value::Array(
                pubs.lock()
                    .expect(FAILED_TO_LOCK)
                    .values()
                    .map(|ref v| {
                        Value::Array(vec![
                            Value::String(v.topic.clone()),
                            Value::String(v.msg_type.clone()),
                        ])
                    })
                    .collect(),
            ))
        });

        server.register_value("paramUpdate", "Parameter updated", |_args| {
            // We don't do anything with parameter updates
            Ok(Value::Int(0))
        });

        let name_string = String::from(name);
        let subs = subscriptions.clone();

        server.register_value("publisherUpdate", "Publishers updated", move |args| {
            let mut args = args.into_iter();
            let _caller_id = args.next().ok_or(ResponseError::Client(
                "Missing argument 'caller_id'".into(),
            ))?;
            let topic = match args.next() {
                Some(Value::String(topic)) => topic,
                _ => return Err(ResponseError::Client("Missing argument 'topic'".into())),
            };
            let publishers = match args.next() {
                Some(Value::Array(publishers)) => publishers,
                _ => {
                    return Err(ResponseError::Client(
                        "Missing argument 'publishers'".into(),
                    ))
                }
            };
            let publishers = publishers
                .into_iter()
                .map(|v| match v {
                    Value::String(x) => Ok(x),
                    _ => Err(ResponseError::Client(
                        "Publishers need to be strings".into(),
                    )),
                })
                .collect::<Response<Vec<String>>>()?;

            add_publishers_to_subscription(
                &mut subs.lock().expect(FAILED_TO_LOCK),
                &name_string,
                &topic,
                publishers.into_iter(),
            ).map_err(|v| {
                ResponseError::Server(format!("Failed to handle publishers: {}", v))
            })?;
            Ok(Value::Int(0))
        });

        let hostname_string = String::from(hostname);
        let pubs = publications.clone();

        server.register_value("requestTopic", "Chosen protocol", move |args| {
            let mut args = args.into_iter();
            let _caller_id = args.next().ok_or(ResponseError::Client(
                "Missing argument 'caller_id'".into(),
            ))?;
            let topic = match args.next() {
                Some(Value::String(topic)) => topic,
                _ => return Err(ResponseError::Client("Missing argument 'topic'".into())),
            };
            let protocols = match args.next() {
                Some(Value::Array(protocols)) => protocols,
                Some(_) => {
                    return Err(ResponseError::Client(
                        "Protocols need to be provided as [ [String, XmlRpcLegalValue] ]"
                            .into(),
                    ))
                }
                None => return Err(ResponseError::Client("Missing argument 'protocols'".into())),
            };
            let (ip, port) = match pubs.lock().expect(FAILED_TO_LOCK).get(&topic) {
                Some(publisher) => (hostname_string.clone(), publisher.port as i32),
                None => {
                    return Err(ResponseError::Client(
                        "Requested topic not published by node".into(),
                    ));
                }
            };
            let mut has_tcpros = false;
            for protocol in protocols {
                if let Value::Array(protocol) = protocol {
                    if let Some(&Value::String(ref name)) = protocol.get(0) {
                        has_tcpros |= name == "TCPROS";
                    }
                }
            }
            if has_tcpros {
                Ok(Value::Array(vec![
                    Value::String("TCPROS".into()),
                    Value::String(ip),
                    Value::Int(port),
                ]))
            } else {
                Err(ResponseError::Server(
                    "No matching protocols available".into(),
                ))
            }
        });

        SlaveHandler {
            subscriptions: subscriptions,
            publications: publications,
            services: Arc::new(Mutex::new(HashMap::new())),
            server: server,
        }
    }

    pub fn bind(self, addr: &SocketAddr) -> xml_rpc::error::Result<xml_rpc::server::BoundServer> {
        self.server.bind(addr)
    }
}

pub fn add_publishers_to_subscription<T>(
    subscriptions: &mut HashMap<String, Subscriber>,
    name: &str,
    topic: &str,
    publishers: T,
) -> Result<()>
where
    T: Iterator<Item = String>,
{
    if let Some(mut subscription) = subscriptions.get_mut(topic) {
        for publisher in publishers {
            if let Err(err) = connect_to_publisher(&mut subscription, &name, &publisher, &topic) {
                let info = err.iter()
                    .map(|v| format!("{}", v))
                    .collect::<Vec<_>>()
                    .join("\nCaused by:");
                error!("Failed to connect to publisher '{}': {}", publisher, info);
                return Err(err);
            }
        }
    }
    Ok(())
}

fn connect_to_publisher(
    subscriber: &mut Subscriber,
    caller_id: &str,
    publisher: &str,
    topic: &str,
) -> Result<()> {
    let (protocol, hostname, port) = request_topic(publisher, caller_id, topic)?;
    if protocol != "TCPROS" {
        bail!(
            "Publisher responded with a non-TCPROS protocol: {}",
            protocol
        )
    }
    subscriber
        .connect_to((hostname.as_str(), port as u16))
        .map_err(|err| ErrorKind::Io(err).into())
}

fn request_topic(
    publisher_uri: &str,
    caller_id: &str,
    topic: &str,
) -> error::rosxmlrpc::Result<(String, String, i32)> {
    let (_code, _message, protocols): (i32, String, (String, String, i32)) = xml_rpc::Client::new()
        .unwrap()
        .call(&publisher_uri.parse().unwrap(), "requestTopic", &(
            caller_id,
            topic,
            [["TCPROS"]],
        ))
        .unwrap()
        .unwrap();
    Ok(protocols)
}

#[allow(dead_code)]
pub struct BusStats {
    pub publish: Vec<PublishStats>,
    pub subscribe: Vec<SubscribeStats>,
    pub service: ServiceStats,
}

#[allow(dead_code)]
pub struct PublishStats {
    pub name: String,
    pub data_sent: String,
    pub connection_data: PublishConnectionData,
}

#[allow(dead_code)]
pub struct PublishConnectionData {
    pub connection_id: String,
    pub bytes_sent: i32,
    pub number_sent: i32,
    pub connected: bool,
}

#[allow(dead_code)]
pub struct SubscribeStats {
    pub name: String,
    pub connection_data: SubscribeConnectionData,
}

#[allow(dead_code)]
pub struct SubscribeConnectionData {
    pub connection_id: String,
    pub bytes_received: i32,
    pub drop_estimate: i32,
    pub connected: bool,
}

#[allow(dead_code)]
pub struct ServiceStats {
    pub number_of_requests: i32,
    pub bytes_received: i32,
    pub bytes_sent: i32,
}

#[allow(dead_code)]
pub struct BusInfo {
    pub connection_id: String,
    pub destination_id: String,
    pub direction: String,
    pub transport: String,
    pub topic: String,
    pub connected: bool,
}

static FAILED_TO_LOCK: &'static str = "Failed to acquire lock";
<commit_msg>Handle when parameters are sent as one array<commit_after>use nix::unistd::getpid;
use rosxmlrpc::{Response, ResponseError, Server};
use std::net::SocketAddr;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use futures::sync::mpsc::Sender;
use super::error::{self, ErrorKind, Result};
use tcpros::{Publisher, Subscriber, Service};
use xml_rpc::{self, Value, Params};

pub struct SlaveHandler {
    pub subscriptions: Arc<Mutex<HashMap<String, Subscriber>>>,
    pub publications: Arc<Mutex<HashMap<String, Publisher>>>,
    pub services: Arc<Mutex<HashMap<String, Service>>>,
    server: Server,
}

fn unwrap_array_case(params: Params) -> Params {
    if let Some(&Value::Array(ref items)) = params.get(0) {
        return items.clone();
    }
    params
}

impl SlaveHandler {
    pub fn new(
        master_uri: &str,
        hostname: &str,
        name: &str,
        shutdown_signal: Sender<()>,
    ) -> SlaveHandler {
        use futures::Sink;

        let mut server = Server::default();

        server.register_value("getBusStats", "Bus stats", |_args| {
            // TODO: implement actual stats displaying
            Err(ResponseError::Server("Method not implemented".into()))
        });

        server.register_value("getBusInfo", "Bus info", |_args| {
            // TODO: implement actual info displaying
            Err(ResponseError::Server("Method not implemented".into()))
        });

        let master_uri_string = String::from(master_uri);

        server.register_value("getMasterUri", "Master URI", move |_args| {
            Ok(Value::String(master_uri_string.clone()))
        });

        server.register_value("shutdown", "Shutdown", move |args| {
            let mut args = unwrap_array_case(args).into_iter();
            let _caller_id = args.next().ok_or(ResponseError::Client(
                "Missing argument 'caller_id'".into(),
            ))?;
            let message = match args.next() {
                Some(Value::String(message)) => message,
                _ => return Err(ResponseError::Client("Missing argument 'message'".into())),
            };
            info!("Server is shutting down because: {}", message);
            match shutdown_signal.clone().wait().send(()) {
                Ok(()) => Ok(Value::Int(0)),
                Err(err) => {
                    error!("Shutdown error: {:?}", err);
                    Err(ResponseError::Server("Failed to shut down".into()))
                }
            }
        });

        server.register_value("getPid", "PID", |_args| Ok(Value::Int(getpid())));

        let subscriptions = Arc::new(Mutex::new(HashMap::<String, Subscriber>::new()));
        let subs = subscriptions.clone();

        server.register_value("getSubscriptions", "List of subscriptions", move |_args| {
            Ok(Value::Array(
                subs.lock()
                    .expect(FAILED_TO_LOCK)
                    .values()
                    .map(|ref v| {
                        Value::Array(vec![
                            Value::String(v.topic.clone()),
                            Value::String(v.msg_type.clone()),
                        ])
                    })
                    .collect(),
            ))
        });

        let publications = Arc::new(Mutex::new(HashMap::<String, Publisher>::new()));
        let pubs = publications.clone();

        server.register_value("getPublications", "List of publications", move |_args| {
            Ok(Value::Array(
                pubs.lock()
                    .expect(FAILED_TO_LOCK)
                    .values()
                    .map(|ref v| {
                        Value::Array(vec![
                            Value::String(v.topic.clone()),
                            Value::String(v.msg_type.clone()),
                        ])
                    })
                    .collect(),
            ))
        });

        server.register_value("paramUpdate", "Parameter updated", |_args| {
            // We don't do anything with parameter updates
            Ok(Value::Int(0))
        });

        let name_string = String::from(name);
        let subs = subscriptions.clone();

        server.register_value("publisherUpdate", "Publishers updated", move |args| {
            let mut args = unwrap_array_case(args).into_iter();
            let _caller_id = args.next().ok_or(ResponseError::Client(
                "Missing argument 'caller_id'".into(),
            ))?;
            let topic = match args.next() {
                Some(Value::String(topic)) => topic,
                _ => return Err(ResponseError::Client("Missing argument 'topic'".into())),
            };
            let publishers = match args.next() {
                Some(Value::Array(publishers)) => publishers,
                _ => {
                    return Err(ResponseError::Client(
                        "Missing argument 'publishers'".into(),
                    ))
                }
            };
            let publishers = publishers
                .into_iter()
                .map(|v| match v {
                    Value::String(x) => Ok(x),
                    _ => Err(ResponseError::Client(
                        "Publishers need to be strings".into(),
                    )),
                })
                .collect::<Response<Vec<String>>>()?;

            add_publishers_to_subscription(
                &mut subs.lock().expect(FAILED_TO_LOCK),
                &name_string,
                &topic,
                publishers.into_iter(),
            ).map_err(|v| {
                ResponseError::Server(format!("Failed to handle publishers: {}", v))
            })?;
            Ok(Value::Int(0))
        });

        let hostname_string = String::from(hostname);
        let pubs = publications.clone();

        server.register_value("requestTopic", "Chosen protocol", move |args| {
            let mut args = unwrap_array_case(args).into_iter();
            let _caller_id = args.next().ok_or(ResponseError::Client(
                "Missing argument 'caller_id'".into(),
            ))?;
            let topic = match args.next() {
                Some(Value::String(topic)) => topic,
                _ => return Err(ResponseError::Client("Missing argument 'topic'".into())),
            };
            let protocols = match args.next() {
                Some(Value::Array(protocols)) => protocols,
                Some(_) => {
                    return Err(ResponseError::Client(
                        "Protocols need to be provided as [ [String, XmlRpcLegalValue] ]"
                            .into(),
                    ))
                }
                None => return Err(ResponseError::Client("Missing argument 'protocols'".into())),
            };
            let (ip, port) = match pubs.lock().expect(FAILED_TO_LOCK).get(&topic) {
                Some(publisher) => (hostname_string.clone(), publisher.port as i32),
                None => {
                    return Err(ResponseError::Client(
                        "Requested topic not published by node".into(),
                    ));
                }
            };
            let mut has_tcpros = false;
            for protocol in protocols {
                if let Value::Array(protocol) = protocol {
                    if let Some(&Value::String(ref name)) = protocol.get(0) {
                        has_tcpros |= name == "TCPROS";
                    }
                }
            }
            if has_tcpros {
                Ok(Value::Array(vec![
                    Value::String("TCPROS".into()),
                    Value::String(ip),
                    Value::Int(port),
                ]))
            } else {
                Err(ResponseError::Server(
                    "No matching protocols available".into(),
                ))
            }
        });

        SlaveHandler {
            subscriptions: subscriptions,
            publications: publications,
            services: Arc::new(Mutex::new(HashMap::new())),
            server: server,
        }
    }

    pub fn bind(self, addr: &SocketAddr) -> xml_rpc::error::Result<xml_rpc::server::BoundServer> {
        self.server.bind(addr)
    }
}

pub fn add_publishers_to_subscription<T>(
    subscriptions: &mut HashMap<String, Subscriber>,
    name: &str,
    topic: &str,
    publishers: T,
) -> Result<()>
where
    T: Iterator<Item = String>,
{
    if let Some(mut subscription) = subscriptions.get_mut(topic) {
        for publisher in publishers {
            if let Err(err) = connect_to_publisher(&mut subscription, &name, &publisher, &topic) {
                let info = err.iter()
                    .map(|v| format!("{}", v))
                    .collect::<Vec<_>>()
                    .join("\nCaused by:");
                error!("Failed to connect to publisher '{}': {}", publisher, info);
                return Err(err);
            }
        }
    }
    Ok(())
}

fn connect_to_publisher(
    subscriber: &mut Subscriber,
    caller_id: &str,
    publisher: &str,
    topic: &str,
) -> Result<()> {
    let (protocol, hostname, port) = request_topic(publisher, caller_id, topic)?;
    if protocol != "TCPROS" {
        bail!(
            "Publisher responded with a non-TCPROS protocol: {}",
            protocol
        )
    }
    subscriber
        .connect_to((hostname.as_str(), port as u16))
        .map_err(|err| ErrorKind::Io(err).into())
}

fn request_topic(
    publisher_uri: &str,
    caller_id: &str,
    topic: &str,
) -> error::rosxmlrpc::Result<(String, String, i32)> {
    let (_code, _message, protocols): (i32, String, (String, String, i32)) = xml_rpc::Client::new()
        .unwrap()
        .call(&publisher_uri.parse().unwrap(), "requestTopic", &(
            caller_id,
            topic,
            [["TCPROS"]],
        ))
        .unwrap()
        .unwrap();
    Ok(protocols)
}

#[allow(dead_code)]
pub struct BusStats {
    pub publish: Vec<PublishStats>,
    pub subscribe: Vec<SubscribeStats>,
    pub service: ServiceStats,
}

#[allow(dead_code)]
pub struct PublishStats {
    pub name: String,
    pub data_sent: String,
    pub connection_data: PublishConnectionData,
}

#[allow(dead_code)]
pub struct PublishConnectionData {
    pub connection_id: String,
    pub bytes_sent: i32,
    pub number_sent: i32,
    pub connected: bool,
}

#[allow(dead_code)]
pub struct SubscribeStats {
    pub name: String,
    pub connection_data: SubscribeConnectionData,
}

#[allow(dead_code)]
pub struct SubscribeConnectionData {
    pub connection_id: String,
    pub bytes_received: i32,
    pub drop_estimate: i32,
    pub connected: bool,
}

#[allow(dead_code)]
pub struct ServiceStats {
    pub number_of_requests: i32,
    pub bytes_received: i32,
    pub bytes_sent: i32,
}

#[allow(dead_code)]
pub struct BusInfo {
    pub connection_id: String,
    pub destination_id: String,
    pub direction: String,
    pub transport: String,
    pub topic: String,
    pub connected: bool,
}

static FAILED_TO_LOCK: &'static str = "Failed to acquire lock";
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std;
use gl;
use gl::types::{
  GLfloat,
  GLint,
  GLuint,
  GLchar,
  GLenum,
};
use cgmath::matrix::{
  Matrix,
  Mat4,
  Mat3,
  ToMat4,
};
use cgmath::vector::{
  Vec3,
  Vec2,
};
use cgmath::angle;
use stb_image::image;
use misc::{
  c_str,
  deg_to_rad,
};
use color::Color3;

pub fn compile_shader(src: &str, shader_type: GLenum) -> GLuint {
  let shader = gl::CreateShader(shader_type);
  unsafe {
    gl::ShaderSource(shader, 1, &c_str(src), std::ptr::null());
    gl::CompileShader(shader);
    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
    if status != (gl::TRUE as GLint) {
      let mut len = 0;
      gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetShaderInfoLog(shader, len, std::ptr::mut_null(),
        buf.as_mut_ptr() as *mut GLchar
      );
      fail!("compile_shader(): " + std::str::raw::from_utf8(buf));
    }
  }
  shader
}

pub fn link_program(vertex_shader: GLuint, fragment_shader: GLuint) -> GLuint {
  let program = gl::CreateProgram();
  gl::AttachShader(program, vertex_shader);
  gl::AttachShader(program, fragment_shader);
  gl::LinkProgram(program);
  unsafe {
    let mut status = gl::FALSE as GLint;
    gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);
    if status != (gl::TRUE as GLint) {
      let mut len = 0;
      gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetProgramInfoLog(program, len, std::ptr::mut_null(),
        buf.as_mut_ptr() as *mut GLchar
      );
      fail!("link_program(): " + std::str::raw::from_utf8(buf));
    }
  }
  program
}

pub fn compile_program(
  vertex_shader_src: &str,
  frag_shader_src: &str,
) -> GLuint {
  let vertex_shader = compile_shader(
    vertex_shader_src, gl::VERTEX_SHADER);
  let fragment_shader = compile_shader(
    frag_shader_src, gl::FRAGMENT_SHADER);
  let program = link_program(vertex_shader, fragment_shader);
  // mark shaders for deletion after program deletion
  gl::DeleteShader(fragment_shader);
  gl::DeleteShader(vertex_shader);
  program
}

pub fn get_attr(program_id: GLuint, name: &str) -> GLuint {
  unsafe {
    gl::GetAttribLocation(program_id, c_str(name)) as GLuint
  }
}

pub fn get_uniform(program: GLuint, name: &str) -> GLint {
  unsafe {
    gl::GetUniformLocation(program, c_str(name))
  }
}

pub fn draw_mesh(faces_count: int) {
  let starting_index = 0;
  let vertices_count = faces_count as i32 * 3;
  gl::DrawArrays(gl::TRIANGLES, starting_index, vertices_count);
}

pub fn uniform_mat4f(mat_id: GLint, mat: &Mat4<GLfloat>) {
  unsafe {
    gl::UniformMatrix4fv(mat_id, 1, gl::FALSE, mat.cr(0, 0));
  }
}

pub fn tr(m: Mat4<f32>, v: Vec3<f32>) -> Mat4<f32> {
  let mut t = Mat4::<f32>::identity();
  *t.mut_cr(3, 0) = v.x;
  *t.mut_cr(3, 1) = v.y;
  *t.mut_cr(3, 2) = v.z;
  m.mul_m(&t)
}

pub fn rot_x(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let rad = angle::rad(deg_to_rad(angle));
  let r = Mat3::from_angle_x(rad).to_mat4();
  m.mul_m(&r)
}

pub fn rot_z(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let rad = angle::rad(deg_to_rad(angle));
  let r = Mat3::from_angle_z(rad).to_mat4();
  m.mul_m(&r)
}

pub fn fill_current_coord_vbo(data: &[Vec3<GLfloat>]) {
  let glfloat_size = std::mem::size_of::<GLfloat>();
  let buffer_size = (data.len() * 3 * glfloat_size) as gl::types::GLsizeiptr;
  unsafe {
    gl::BufferData(
      gl::ARRAY_BUFFER,
      buffer_size,
      std::cast::transmute(&data[0]),
      gl::STATIC_DRAW,
    );
  }
}

pub fn gen_buffer() -> GLuint {
  let mut n = 0 as GLuint;
  unsafe {
    gl::GenBuffers(1, &mut n);
  }
  n
}

pub fn delete_buffer(buffer: GLuint) {
  unsafe {
    gl::DeleteBuffers(1, &buffer);
  }
}

pub fn fill_current_color_vbo(data: &[Color3]) {
  let color3_size = std::mem::size_of::<Color3>();
  let buffer_size = (data.len() * color3_size) as gl::types::GLsizeiptr;
  unsafe {
    gl::BufferData(
      gl::ARRAY_BUFFER,
      buffer_size,
      std::cast::transmute(&data[0]),
      gl::STATIC_DRAW,
    );
  }
}

pub fn fill_current_vt_vbo(data: &[Vec2<GLfloat>]) {
  let glfloat_size = std::mem::size_of::<GLfloat>();
  let buffer_size = (data.len() * 2 * glfloat_size) as gl::types::GLsizeiptr;
  unsafe {
    gl::BufferData(
      gl::ARRAY_BUFFER,
      buffer_size,
      std::cast::transmute(&data[0]),
      gl::STATIC_DRAW,
    );
  }
}

pub fn vertex_attrib_pointer(attr: GLuint, components_count: i32) {
  let normalized = gl::FALSE;
  let stride = 0;
  unsafe {
    gl::VertexAttribPointer(
      attr,
      components_count,
      gl::FLOAT,
      normalized,
      stride,
      std::ptr::null(),
    );
  }
}

fn load_image(path: ~str) -> image::Image<u8> {
  let load_result = image::load(path);
  match load_result {
    image::ImageU8(image) => {
      image
    },
    image::Error(message) => {
      fail!("{}", message);
    },
    _ => {
      fail!("unkn");
    }
  }
}

pub fn load_texture(path: ~str) -> GLuint {
  let image = load_image(path);
  let mut id = 0;
  unsafe {
    gl::GenTextures(1, &mut id)
  };
  gl::ActiveTexture(gl::TEXTURE0);
  gl::BindTexture(gl::TEXTURE_2D, id);
  unsafe {
    if image.depth == 4 {
      gl::TexImage2D(
        gl::TEXTURE_2D,
        0,
        gl::RGBA as GLint,
        image.width as gl::types::GLsizei,
        image.height as gl::types::GLsizei,
        0,
        gl::RGBA,
        gl::UNSIGNED_BYTE,
        std::cast::transmute(&image.data[0]),
      );
    } else if image.depth == 3 {
      gl::TexImage2D(
        gl::TEXTURE_2D,
        0,
        gl::RGB as GLint,
        image.width as gl::types::GLsizei,
        image.height as gl::types::GLsizei,
        0,
        gl::RGB,
        gl::UNSIGNED_BYTE,
        std::cast::transmute(&image.data[0]),
      );
    } else {
      fail!("depth");
    }
  }
  gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint);
  gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint);
  gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint);
  gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint);
  id
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<commit_msg>gl_helpers.rs: Simplified load_texture()<commit_after>// See LICENSE file for copyright and license details.

use std;
use gl;
use gl::types::{
  GLfloat,
  GLint,
  GLuint,
  GLchar,
  GLenum,
};
use cgmath::matrix::{
  Matrix,
  Mat4,
  Mat3,
  ToMat4,
};
use cgmath::vector::{
  Vec3,
  Vec2,
};
use cgmath::angle;
use stb_image::image;
use misc::{
  c_str,
  deg_to_rad,
};
use color::Color3;

pub fn compile_shader(src: &str, shader_type: GLenum) -> GLuint {
  let shader = gl::CreateShader(shader_type);
  unsafe {
    gl::ShaderSource(shader, 1, &c_str(src), std::ptr::null());
    gl::CompileShader(shader);
    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
    if status != (gl::TRUE as GLint) {
      let mut len = 0;
      gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetShaderInfoLog(shader, len, std::ptr::mut_null(),
        buf.as_mut_ptr() as *mut GLchar
      );
      fail!("compile_shader(): " + std::str::raw::from_utf8(buf));
    }
  }
  shader
}

pub fn link_program(vertex_shader: GLuint, fragment_shader: GLuint) -> GLuint {
  let program = gl::CreateProgram();
  gl::AttachShader(program, vertex_shader);
  gl::AttachShader(program, fragment_shader);
  gl::LinkProgram(program);
  unsafe {
    let mut status = gl::FALSE as GLint;
    gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);
    if status != (gl::TRUE as GLint) {
      let mut len = 0;
      gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetProgramInfoLog(program, len, std::ptr::mut_null(),
        buf.as_mut_ptr() as *mut GLchar
      );
      fail!("link_program(): " + std::str::raw::from_utf8(buf));
    }
  }
  program
}

pub fn compile_program(
  vertex_shader_src: &str,
  frag_shader_src: &str,
) -> GLuint {
  let vertex_shader = compile_shader(
    vertex_shader_src, gl::VERTEX_SHADER);
  let fragment_shader = compile_shader(
    frag_shader_src, gl::FRAGMENT_SHADER);
  let program = link_program(vertex_shader, fragment_shader);
  // mark shaders for deletion after program deletion
  gl::DeleteShader(fragment_shader);
  gl::DeleteShader(vertex_shader);
  program
}

pub fn get_attr(program_id: GLuint, name: &str) -> GLuint {
  unsafe {
    gl::GetAttribLocation(program_id, c_str(name)) as GLuint
  }
}

pub fn get_uniform(program: GLuint, name: &str) -> GLint {
  unsafe {
    gl::GetUniformLocation(program, c_str(name))
  }
}

pub fn draw_mesh(faces_count: int) {
  let starting_index = 0;
  let vertices_count = faces_count as i32 * 3;
  gl::DrawArrays(gl::TRIANGLES, starting_index, vertices_count);
}

pub fn uniform_mat4f(mat_id: GLint, mat: &Mat4<GLfloat>) {
  unsafe {
    gl::UniformMatrix4fv(mat_id, 1, gl::FALSE, mat.cr(0, 0));
  }
}

pub fn tr(m: Mat4<f32>, v: Vec3<f32>) -> Mat4<f32> {
  let mut t = Mat4::<f32>::identity();
  *t.mut_cr(3, 0) = v.x;
  *t.mut_cr(3, 1) = v.y;
  *t.mut_cr(3, 2) = v.z;
  m.mul_m(&t)
}

pub fn rot_x(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let rad = angle::rad(deg_to_rad(angle));
  let r = Mat3::from_angle_x(rad).to_mat4();
  m.mul_m(&r)
}

pub fn rot_z(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let rad = angle::rad(deg_to_rad(angle));
  let r = Mat3::from_angle_z(rad).to_mat4();
  m.mul_m(&r)
}

pub fn fill_current_coord_vbo(data: &[Vec3<GLfloat>]) {
  let glfloat_size = std::mem::size_of::<GLfloat>();
  let buffer_size = (data.len() * 3 * glfloat_size) as gl::types::GLsizeiptr;
  unsafe {
    gl::BufferData(
      gl::ARRAY_BUFFER,
      buffer_size,
      std::cast::transmute(&data[0]),
      gl::STATIC_DRAW,
    );
  }
}

pub fn gen_buffer() -> GLuint {
  let mut n = 0 as GLuint;
  unsafe {
    gl::GenBuffers(1, &mut n);
  }
  n
}

pub fn delete_buffer(buffer: GLuint) {
  unsafe {
    gl::DeleteBuffers(1, &buffer);
  }
}

pub fn fill_current_color_vbo(data: &[Color3]) {
  let color3_size = std::mem::size_of::<Color3>();
  let buffer_size = (data.len() * color3_size) as gl::types::GLsizeiptr;
  unsafe {
    gl::BufferData(
      gl::ARRAY_BUFFER,
      buffer_size,
      std::cast::transmute(&data[0]),
      gl::STATIC_DRAW,
    );
  }
}

pub fn fill_current_vt_vbo(data: &[Vec2<GLfloat>]) {
  let glfloat_size = std::mem::size_of::<GLfloat>();
  let buffer_size = (data.len() * 2 * glfloat_size) as gl::types::GLsizeiptr;
  unsafe {
    gl::BufferData(
      gl::ARRAY_BUFFER,
      buffer_size,
      std::cast::transmute(&data[0]),
      gl::STATIC_DRAW,
    );
  }
}

pub fn vertex_attrib_pointer(attr: GLuint, components_count: i32) {
  let normalized = gl::FALSE;
  let stride = 0;
  unsafe {
    gl::VertexAttribPointer(
      attr,
      components_count,
      gl::FLOAT,
      normalized,
      stride,
      std::ptr::null(),
    );
  }
}

fn load_image(path: ~str) -> image::Image<u8> {
  let load_result = image::load(path);
  match load_result {
    image::ImageU8(image) => {
      image
    },
    image::Error(message) => {
      fail!("{}", message);
    },
    _ => {
      fail!("unkn");
    }
  }
}

pub fn load_texture(path: ~str) -> GLuint {
  let image = load_image(path);
  let mut id = 0;
  unsafe {
    gl::GenTextures(1, &mut id)
  };
  gl::ActiveTexture(gl::TEXTURE0);
  gl::BindTexture(gl::TEXTURE_2D, id);
  let format = match image.depth {
    4 => gl::RGBA,
    3 => gl::RGB,
    _ => fail!("wrong depth"),
  };
  unsafe {
    let level = 0;
    let border = 0;
    gl::TexImage2D(
      gl::TEXTURE_2D,
      level,
      format as GLint,
      image.width as gl::types::GLsizei,
      image.height as gl::types::GLsizei,
      border,
      format,
      gl::UNSIGNED_BYTE,
      std::cast::transmute(&image.data[0]),
    );
  }
  gl::TexParameteri(gl::TEXTURE_2D,
    gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint);
  gl::TexParameteri(gl::TEXTURE_2D,
    gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint);
  gl::TexParameteri(gl::TEXTURE_2D,
    gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint);
  gl::TexParameteri(gl::TEXTURE_2D,
    gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint);
  id
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<|endoftext|>