<commit_before>use library::Nullable;
use regex::*;
use std::vec::Vec;
use toml::Value;

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Ident {
    Name(String),
    Pattern(Regex),
}

impl Ident {
    pub fn parse(toml: &Value, object_name: &str, is_parameter: bool) -> Option<Ident> {
        match toml.lookup("pattern").and_then(|v| v.as_str()) {
            Some(s) => Regex::new(s)
                .map(|r| Ident::Pattern(r))
                .map_err(|e| {
                    if is_parameter {
                        error!("Bad pattern '{}' in functions parameter for '{}': {}", s, object_name, e);
                    } else {
                        error!("Bad pattern '{}' in function for '{}': {}", s, object_name, e);
                    }
                    e
                })
                .ok(),
            None => toml.lookup("name")
                .and_then(|val| val.as_str())
                .map(|s| Ident::Name(s.into())),
        }
    }

    fn is_match(&self, name: &str) -> bool {
        use self::Ident::*;
        match *self {
            Name(ref n) => name == n,
            Pattern(ref regex) => regex.is_match(name),
        }
    }
}

#[derive(Clone, Debug)]
pub struct Parameter {
    pub ident: Ident,
    //true - parameter don't changed in ffi function,
    //false(default) - parameter can be changed in ffi function
    pub constant: bool,
    pub nullable: Option<Nullable>,
}

impl Parameter {
    pub fn parse(toml: &Value, object_name: &str) -> Option<Parameter> {
        let ident = match Ident::parse(toml, object_name, true) {
            Some(ident) => ident,
            None => {
                error!("No 'name' or 'pattern' given for parameter for object {}", object_name);
                return None
            }
        };
        let constant = toml.lookup("const")
            .and_then(|val| val.as_bool())
            .unwrap_or(false);
        let nullable = toml.lookup("nullable")
            .and_then(|val| val.as_bool())
            .map(|b| Nullable(b));

        Some(Parameter{
            ident: ident,
            constant: constant,
            nullable: nullable,
        })
    }
}

#[derive(Clone, Debug)]
pub struct Parameters(Vec<Parameter>);

impl Parameters {
    pub fn parse(toml: Option<&Value>, object_name: &str) -> Parameters {
        let mut v = Vec::new();
        if let Some(pars) = toml.and_then(|val| val.as_slice()) {
            for par in pars {
                if let Some(par) = Parameter::parse(par, object_name) {
                    v.push(par);
                }
            }
        }

        Parameters(v)
    }

    pub fn matched(&self, parameter_name: &str) -> Vec<&Parameter> {
        self.0.iter().filter(|p| p.ident.is_match(parameter_name)).collect()
    }

    #[cfg(test)]
    fn vec(&self) -> &Vec<Parameter> {
        &self.0
    }
}

#[derive(Clone, Debug)]
pub struct Return {
    pub nullable: Option<Nullable>,
}

impl Return {
    pub fn parse(toml: Option<&Value>) -> Return {
        if let Some(v) = toml {
            let nullable = v.lookup("nullable")
                .and_then(|v| v.as_bool())
                .map(|b| Nullable(b));
            Return {
                nullable: nullable,
            }
        } else {
            Return {
                nullable: None,
            }
        }

    }
}

#[derive(Clone, Debug)]
pub struct Function {
    pub ident: Ident,
    //true - ignore this function,
    //false(default) - process this function
    pub ignore: bool,
    pub parameters: Parameters,
    pub ret: Return,
}

impl Function {
    pub fn parse(toml: &Value, object_name: &str) -> Option<Function> {
        let ident = match Ident::parse(toml, object_name, false) {
            Some(ident) => ident,
            None => {
                error!("No 'name' or 'pattern' given for function for object {}", object_name);
                return None
            }
        };
        let ignore = toml.lookup("ignore")
            .and_then(|val| val.as_bool())
            .unwrap_or(false);
        let parameters = Parameters::parse(toml.lookup("parameter"), object_name);
        let ret = Return::parse(toml.lookup("return"));

        Some(Function{
            ident: ident,
            ignore: ignore,
            parameters: parameters,
            ret: ret,
        })
    }

    pub fn matched_parameters<'a>(functions: &[&'a Function], parameter_name: &str) -> Vec<&'a Parameter> {
        let mut v = Vec::new();
        for f in functions {
            let pars = f.parameters.matched(parameter_name);
            //TODO: change to push_all
            for par in pars {
                v.push(par);
            }
        }
        v
    }
}

#[derive(Clone, Debug)]
pub struct Functions(Vec<Function>);

impl Functions {
    pub fn new() -> Functions {
        Functions(Vec::new())
    }

    pub fn parse(toml: Option<&Value>, object_name: &str) -> Functions {
        let mut v = Vec::new();
        if let Some(fns) = toml.and_then(|val| val.as_slice()) {
            for f in fns {
                if let Some(f) = Function::parse(f, object_name) {
                    v.push(f);
                }
            }
        }

        Functions(v)
    }

    pub fn matched(&self, function_name: &str) -> Vec<&Function> {
        self.0.iter().filter(|f| f.ident.is_match(function_name)).collect()
    }

    #[cfg(test)]
    fn vec(&self) -> &Vec<Function> {
        &self.0
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use toml;

    fn functions_toml(input: &str) -> toml::Value {
        let mut parser = toml::Parser::new(&input);
        let value = parser.parse();
        assert!(value.is_some());
        value.unwrap().remove("f").unwrap()
    }

    fn toml(input: &str) -> toml::Value {
        let mut parser = toml::Parser::new(&input);
        let value = parser.parse();
        assert!(value.is_some());
        toml::Value::Table(value.unwrap())
    }

    #[test]
    fn function_parse_ignore() {
        let toml = toml(r#"
name = "func1"
ignore = true
"#);
        let f = Function::parse(&toml, "a").unwrap();
        assert_eq!(f.ident, Ident::Name("func1".into()));
        assert_eq!(f.ignore, true);
    }

    #[test]
    fn function_parse_return_nullable_default1() {
        let toml = toml(r#"
name = "func1"
"#);
        let f = Function::parse(&toml, "a").unwrap();
        assert_eq!(f.ret.nullable, true);
    }
    #[test]
    fn function_parse_return_nullable_default2() {
        let toml = toml(r#"
name = "func1"
[return]
"#);
        let f = Function::parse(&toml, "a").unwrap();
        assert_eq!(f.ret.nullable, true);
    }

    #[test]
    fn function_parse_parameters() {
        let toml = toml(r#"
name = "func1"
[[parameter]]
name = "par1"
[[parameter]]
name = "par2"
const = false
[[parameter]]
name = "par3"
const = true
[[parameter]]
pattern = "par4"
const = true
"#);
        let f = Function::parse(&toml, "a").unwrap();
        let pars = f.parameters.vec();
        assert_eq!(pars.len(), 4);
        assert_eq!(pars[0].ident, Ident::Name("par1".into()));
        assert_eq!(pars[0].constant, false);
        assert_eq!(pars[1].ident, Ident::Name("par2".into()));
        assert_eq!(pars[1].constant, false);
        assert_eq!(pars[2].ident, Ident::Name("par3".into()));
        assert_eq!(pars[2].constant, true);
        if let Ident::Pattern(_) = pars[3].ident {
        } else {
            assert!(false, "Pattern don't parsed");
        }
        assert_eq!(pars[3].constant, true);
    }

    #[test]
    fn function_parse_return_nullable_false() {
        let toml = toml(r#"
name = "func1"
[return]
nullable = false
"#);
        let f = Function::parse(&toml, "a").unwrap();
        assert_eq!(f.ret.nullable, false);
    }

    #[test]
    fn functions_parse_empty_for_none() {
        let fns = Functions::parse(None, "a");
        assert!(fns.vec().is_empty());
    }

    #[test]
    fn functions_parse_ident() {
        let toml = functions_toml(r#"
[[f]]
name = "func1"
[[f]]
not_name = "func1.5"
[[f]]
name = "func2"
[[f]]
pattern = 'func3\w+'
[[f]]
pattern = 'bad_func4[\w+'
"#);
        let fns = Functions::parse(Some(&toml), "a");
        assert_eq!(fns.vec().len(), 3);
        assert_eq!(fns.vec()[0].ident, Ident::Name("func1".into()));
        assert_eq!(fns.vec()[1].ident, Ident::Name("func2".into()));
        if let Ident::Pattern(_) = fns.vec()[2].ident {
        } else {
            assert!(false, "Pattern don't parsed");
        }
    }

    #[test]
    fn functions_parse_matches() {
        let toml = functions_toml(r#"
[[f]]
name = "func1"
[[f]]
name = "f1.5"
[[f]]
name = "func2"
[[f]]
pattern = 'func\d+'
"#);
        let fns = Functions::parse(Some(&toml), "a");
        assert_eq!(fns.vec().len(), 4);

        assert_eq!(fns.matched("func1").len(), 2);
        assert_eq!(fns.matched("func2").len(), 2);
        assert_eq!(fns.matched("func3").len(), 1);
        assert_eq!(fns.matched("f1.5").len(), 1);
        assert_eq!(fns.matched("none").len(), 0);
    }

    #[test]
    fn functions_parse_matched_parameters() {
        let toml = functions_toml(r#"
[[f]]
name = "func"
[[f.parameter]]
name="par1"
[[f.parameter]]
name="par2"
[[f.parameter]]
pattern='par\d+'
[[f]]
name = "func"
[[f.parameter]]
name="par2"
[[f.parameter]]
name="par3"
[[f.parameter]]
pattern='par\d+'
"#);
        let fns = Functions::parse(Some(&toml), "a");
        assert_eq!(fns.vec().len(), 2);
        let m = fns.matched("func");
        assert_eq!(m.len(), 2);

        assert_eq!(Function::matched_parameters(&m, "param").len(), 0);
        assert_eq!(Function::matched_parameters(&m, "par1").len(), 3);
        assert_eq!(Function::matched_parameters(&m, "par2").len(), 4);
        assert_eq!(Function::matched_parameters(&m, "par3").len(), 3);
        assert_eq!(Function::matched_parameters(&m, "par4").len(), 2);
    }
}
<commit_msg>Update config tests for nullability settings<commit_after>use library::Nullable;
use regex::*;
use std::vec::Vec;
use toml::Value;

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Ident {
    Name(String),
    Pattern(Regex),
}

impl Ident {
    pub fn parse(toml: &Value, object_name: &str, is_parameter: bool) -> Option<Ident> {
        match toml.lookup("pattern").and_then(|v| v.as_str()) {
            Some(s) => Regex::new(s)
                .map(|r| Ident::Pattern(r))
                .map_err(|e| {
                    if is_parameter {
                        error!("Bad pattern '{}' in functions parameter for '{}': {}", s, object_name, e);
                    } else {
                        error!("Bad pattern '{}' in function for '{}': {}", s, object_name, e);
                    }
                    e
                })
                .ok(),
            None => toml.lookup("name")
                .and_then(|val| val.as_str())
                .map(|s| Ident::Name(s.into())),
        }
    }

    fn is_match(&self, name: &str) -> bool {
        use self::Ident::*;
        match *self {
            Name(ref n) => name == n,
            Pattern(ref regex) => regex.is_match(name),
        }
    }
}

#[derive(Clone, Debug)]
pub struct Parameter {
    pub ident: Ident,
    //true - parameter don't changed in ffi function,
    //false(default) - parameter can be changed in ffi function
    pub constant: bool,
    pub nullable: Option<Nullable>,
}

impl Parameter {
    pub fn parse(toml: &Value, object_name: &str) -> Option<Parameter> {
        let ident = match Ident::parse(toml, object_name, true) {
            Some(ident) => ident,
            None => {
                error!("No 'name' or 'pattern' given for parameter for object {}", object_name);
                return None
            }
        };
        let constant = toml.lookup("const")
            .and_then(|val| val.as_bool())
            .unwrap_or(false);
        let nullable = toml.lookup("nullable")
            .and_then(|val| val.as_bool())
            .map(|b| Nullable(b));

        Some(Parameter{
            ident: ident,
            constant: constant,
            nullable: nullable,
        })
    }
}

#[derive(Clone, Debug)]
pub struct Parameters(Vec<Parameter>);

impl Parameters {
    pub fn parse(toml: Option<&Value>, object_name: &str) -> Parameters {
        let mut v = Vec::new();
        if let Some(pars) = toml.and_then(|val| val.as_slice()) {
            for par in pars {
                if let Some(par) = Parameter::parse(par, object_name) {
                    v.push(par);
                }
            }
        }

        Parameters(v)
    }

    pub fn matched(&self, parameter_name: &str) -> Vec<&Parameter> {
        self.0.iter().filter(|p| p.ident.is_match(parameter_name)).collect()
    }

    #[cfg(test)]
    fn vec(&self) -> &Vec<Parameter> {
        &self.0
    }
}

#[derive(Clone, Debug)]
pub struct Return {
    pub nullable: Option<Nullable>,
}

impl Return {
    pub fn parse(toml: Option<&Value>) -> Return {
        if let Some(v) = toml {
            let nullable = v.lookup("nullable")
                .and_then(|v| v.as_bool())
                .map(|b| Nullable(b));
            Return {
                nullable: nullable,
            }
        } else {
            Return {
                nullable: None,
            }
        }

    }
}

#[derive(Clone, Debug)]
pub struct Function {
    pub ident: Ident,
    //true - ignore this function,
    //false(default) - process this function
    pub ignore: bool,
    pub parameters: Parameters,
    pub ret: Return,
}

impl Function {
    pub fn parse(toml: &Value, object_name: &str) -> Option<Function> {
        let ident = match Ident::parse(toml, object_name, false) {
            Some(ident) => ident,
            None => {
                error!("No 'name' or 'pattern' given for function for object {}", object_name);
                return None
            }
        };
        let ignore = toml.lookup("ignore")
            .and_then(|val| val.as_bool())
            .unwrap_or(false);
        let parameters = Parameters::parse(toml.lookup("parameter"), object_name);
        let ret = Return::parse(toml.lookup("return"));

        Some(Function{
            ident: ident,
            ignore: ignore,
            parameters: parameters,
            ret: ret,
        })
    }

    pub fn matched_parameters<'a>(functions: &[&'a Function], parameter_name: &str) -> Vec<&'a Parameter> {
        let mut v = Vec::new();
        for f in functions {
            let pars = f.parameters.matched(parameter_name);
            //TODO: change to push_all
            for par in pars {
                v.push(par);
            }
        }
        v
    }
}

#[derive(Clone, Debug)]
pub struct Functions(Vec<Function>);

impl Functions {
    pub fn new() -> Functions {
        Functions(Vec::new())
    }

    pub fn parse(toml: Option<&Value>, object_name: &str) -> Functions {
        let mut v = Vec::new();
        if let Some(fns) = toml.and_then(|val| val.as_slice()) {
            for f in fns {
                if let Some(f) = Function::parse(f, object_name) {
                    v.push(f);
                }
            }
        }

        Functions(v)
    }

    pub fn matched(&self, function_name: &str) -> Vec<&Function> {
        self.0.iter().filter(|f| f.ident.is_match(function_name)).collect()
    }

    #[cfg(test)]
    fn vec(&self) -> &Vec<Function> {
        &self.0
    }
}

#[cfg(test)]
mod tests {
    use library::Nullable;
    use super::*;
    use toml;

    fn functions_toml(input: &str) -> toml::Value {
        let mut parser = toml::Parser::new(&input);
        let value = parser.parse();
        assert!(value.is_some());
        value.unwrap().remove("f").unwrap()
    }

    fn toml(input: &str) -> toml::Value {
        let mut parser = toml::Parser::new(&input);
        let value = parser.parse();
        assert!(value.is_some());
        toml::Value::Table(value.unwrap())
    }

    #[test]
    fn function_parse_ignore() {
        let toml = toml(r#"
name = "func1"
ignore = true
"#);
        let f = Function::parse(&toml, "a").unwrap();
        assert_eq!(f.ident, Ident::Name("func1".into()));
        assert_eq!(f.ignore, true);
    }

    #[test]
    fn function_parse_return_nullable_default1() {
        let toml = toml(r#"
name = "func1"
"#);
        let f = Function::parse(&toml, "a").unwrap();
        assert_eq!(f.ret.nullable, None);
    }
    #[test]
    fn function_parse_return_nullable_default2() {
        let toml = toml(r#"
name = "func1"
[return]
"#);
        let f = Function::parse(&toml, "a").unwrap();
        assert_eq!(f.ret.nullable, None);
    }

    #[test]
    fn function_parse_parameters() {
        let toml = toml(r#"
name = "func1"
[[parameter]]
name = "par1"
[[parameter]]
name = "par2"
const = false
nullable = false
[[parameter]]
name = "par3"
const = true
nullable = true
[[parameter]]
pattern = "par4"
const = true
"#);
        let f = Function::parse(&toml, "a").unwrap();
        let pars = f.parameters.vec();
        assert_eq!(pars.len(), 4);
        assert_eq!(pars[0].ident, Ident::Name("par1".into()));
        assert_eq!(pars[0].constant, false);
        assert_eq!(pars[0].nullable, None);
        assert_eq!(pars[1].ident, Ident::Name("par2".into()));
        assert_eq!(pars[1].constant, false);
        assert_eq!(pars[1].nullable, Some(Nullable(false)));
        assert_eq!(pars[2].ident, Ident::Name("par3".into()));
        assert_eq!(pars[2].constant, true);
        assert_eq!(pars[2].nullable, Some(Nullable(true)));
        if let Ident::Pattern(_) = pars[3].ident {
        } else {
            assert!(false, "Pattern don't parsed");
        }
        assert_eq!(pars[3].constant, true);
        assert_eq!(pars[3].nullable, None);
    }

    #[test]
    fn function_parse_return_nullable_false() {
        let toml = toml(r#"
name = "func1"
[return]
nullable = false
"#);
        let f = Function::parse(&toml, "a").unwrap();
        assert_eq!(f.ret.nullable, Some(Nullable(false)));
    }

    #[test]
    fn function_parse_return_nullable_true() {
        let toml = toml(r#"
name = "func1"
[return]
nullable = true
"#);
        let f = Function::parse(&toml, "a").unwrap();
        assert_eq!(f.ret.nullable, Some(Nullable(true)));
    }

    #[test]
    fn functions_parse_empty_for_none() {
        let fns = Functions::parse(None, "a");
        assert!(fns.vec().is_empty());
    }

    #[test]
    fn functions_parse_ident() {
        let toml = functions_toml(r#"
[[f]]
name = "func1"
[[f]]
not_name = "func1.5"
[[f]]
name = "func2"
[[f]]
pattern = 'func3\w+'
[[f]]
pattern = 'bad_func4[\w+'
"#);
        let fns = Functions::parse(Some(&toml), "a");
        assert_eq!(fns.vec().len(), 3);
        assert_eq!(fns.vec()[0].ident, Ident::Name("func1".into()));
        assert_eq!(fns.vec()[1].ident, Ident::Name("func2".into()));
        if let Ident::Pattern(_) = fns.vec()[2].ident {
        } else {
            assert!(false, "Pattern don't parsed");
        }
    }

    #[test]
    fn functions_parse_matches() {
        let toml = functions_toml(r#"
[[f]]
name = "func1"
[[f]]
name = "f1.5"
[[f]]
name = "func2"
[[f]]
pattern = 'func\d+'
"#);
        let fns = Functions::parse(Some(&toml), "a");
        assert_eq!(fns.vec().len(), 4);

        assert_eq!(fns.matched("func1").len(), 2);
        assert_eq!(fns.matched("func2").len(), 2);
        assert_eq!(fns.matched("func3").len(), 1);
        assert_eq!(fns.matched("f1.5").len(), 1);
        assert_eq!(fns.matched("none").len(), 0);
    }

    #[test]
    fn functions_parse_matched_parameters() {
        let toml = functions_toml(r#"
[[f]]
name = "func"
[[f.parameter]]
name="par1"
[[f.parameter]]
name="par2"
[[f.parameter]]
pattern='par\d+'
[[f]]
name = "func"
[[f.parameter]]
name="par2"
[[f.parameter]]
name="par3"
[[f.parameter]]
pattern='par\d+'
"#);
        let fns = Functions::parse(Some(&toml), "a");
        assert_eq!(fns.vec().len(), 2);
        let m = fns.matched("func");
        assert_eq!(m.len(), 2);

        assert_eq!(Function::matched_parameters(&m, "param").len(), 0);
        assert_eq!(Function::matched_parameters(&m, "par1").len(), 3);
        assert_eq!(Function::matched_parameters(&m, "par2").len(), 4);
        assert_eq!(Function::matched_parameters(&m, "par3").len(), 3);
        assert_eq!(Function::matched_parameters(&m, "par4").len(), 2);
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt;
use std::mem;

use yaml_rust as yaml;

use crate::map::Map;
use crate::value::{Value, ValueKind};

pub fn parse(
    uri: Option<&String>,
    text: &str,
) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>> {
    // Parse a YAML object from file
    let mut docs = yaml::YamlLoader::load_from_str(text)?;
    let root = match docs.len() {
        0 => yaml::Yaml::Hash(yaml::yaml::Hash::new()),
        1 => mem::replace(&mut docs[0], yaml::Yaml::Null),
        n => {
            return Err(Box::new(MultipleDocumentsError(n)));
        }
    };

    // TODO: Have a proper error fire if the root of a file is ever not a Table
    let value = from_yaml_value(uri, &root);
    match value.kind {
        ValueKind::Table(map) => Ok(map),

        _ => Ok(Map::new()),
    }
}

fn from_yaml_value(uri: Option<&String>, value: &yaml::Yaml) -> Value {
    match *value {
        yaml::Yaml::String(ref value) => Value::new(uri, ValueKind::String(value.clone())),
        yaml::Yaml::Real(ref value) => {
            // TODO: Figure out in what cases this can panic?
            Value::new(uri, ValueKind::Float(value.parse::<f64>().unwrap()))
        }
        yaml::Yaml::Integer(value) => Value::new(uri, ValueKind::Integer(value)),
        yaml::Yaml::Boolean(value) => Value::new(uri, ValueKind::Boolean(value)),
        yaml::Yaml::Hash(ref table) => {
            let mut m = Map::new();
            for (key, value) in table {
                if let Some(k) = key.as_str() {
                    m.insert(k.to_owned(), from_yaml_value(uri, value));
                }
                // TODO: should we do anything for non-string keys?
            }
            Value::new(uri, ValueKind::Table(m))
        }
        yaml::Yaml::Array(ref array) => {
            let mut l = Vec::new();

            for value in array {
                l.push(from_yaml_value(uri, value));
            }

            Value::new(uri, ValueKind::Array(l))
        }

        // 1. Yaml NULL
        // 2. BadValue – It shouldn't be possible to hit BadValue as this only happens when
        //               using the index trait badly or on a type error but we send back nil.
        // 3. Alias – No idea what to do with this and there is a note in the lib that its
        //            not fully supported yet anyway
        _ => Value::new(uri, ValueKind::Nil),
    }
}

#[derive(Debug, Copy, Clone)]
struct MultipleDocumentsError(usize);

impl fmt::Display for MultipleDocumentsError {
    fn fmt(&self, format: &mut fmt::Formatter) -> fmt::Result {
        write!(format, "Got {} YAML documents, expected 1", self.0)
    }
}

impl Error for MultipleDocumentsError {
    fn description(&self) -> &str {
        "More than one YAML document provided"
    }
}
<commit_msg>Fix panic: Unwrap()ing a f64::parse() should not happen<commit_after>use std::error::Error;
use std::fmt;
use std::mem;

use yaml_rust as yaml;

use crate::map::Map;
use crate::value::{Value, ValueKind};

pub fn parse(
    uri: Option<&String>,
    text: &str,
) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>> {
    // Parse a YAML object from file
    let mut docs = yaml::YamlLoader::load_from_str(text)?;
    let root = match docs.len() {
        0 => yaml::Yaml::Hash(yaml::yaml::Hash::new()),
        1 => mem::replace(&mut docs[0], yaml::Yaml::Null),
        n => {
            return Err(Box::new(MultipleDocumentsError(n)));
        }
    };

    // TODO: Have a proper error fire if the root of a file is ever not a Table
    let value = from_yaml_value(uri, &root)?;
    match value.kind {
        ValueKind::Table(map) => Ok(map),

        _ => Ok(Map::new()),
    }
}

fn from_yaml_value(
    uri: Option<&String>,
    value: &yaml::Yaml,
) -> Result<Value, Box<dyn Error + Send + Sync>> {
    match *value {
        yaml::Yaml::String(ref value) => Ok(Value::new(uri, ValueKind::String(value.clone()))),
        yaml::Yaml::Real(ref value) => {
            // TODO: Figure out in what cases this can panic?
            value
                .parse::<f64>()
                .map_err(|_| {
                    Box::new(FloatParsingError(value.to_string())) as Box<(dyn Error + Send + Sync)>
                })
                .map(ValueKind::Float)
                .map(|f| Value::new(uri, f))
        }
        yaml::Yaml::Integer(value) => Ok(Value::new(uri, ValueKind::Integer(value))),
        yaml::Yaml::Boolean(value) => Ok(Value::new(uri, ValueKind::Boolean(value))),
        yaml::Yaml::Hash(ref table) => {
            let mut m = Map::new();
            for (key, value) in table {
                if let Some(k) = key.as_str() {
                    m.insert(k.to_owned(), from_yaml_value(uri, value)?);
                }
                // TODO: should we do anything for non-string keys?
            }
            Ok(Value::new(uri, ValueKind::Table(m)))
        }
        yaml::Yaml::Array(ref array) => {
            let mut l = Vec::new();

            for value in array {
                l.push(from_yaml_value(uri, value)?);
            }

            Ok(Value::new(uri, ValueKind::Array(l)))
        }

        // 1. Yaml NULL
        // 2. BadValue – It shouldn't be possible to hit BadValue as this only happens when
        //               using the index trait badly or on a type error but we send back nil.
        // 3. Alias – No idea what to do with this and there is a note in the lib that its
        //            not fully supported yet anyway
        _ => Ok(Value::new(uri, ValueKind::Nil)),
    }
}

#[derive(Debug, Copy, Clone)]
struct MultipleDocumentsError(usize);

impl fmt::Display for MultipleDocumentsError {
    fn fmt(&self, format: &mut fmt::Formatter) -> fmt::Result {
        write!(format, "Got {} YAML documents, expected 1", self.0)
    }
}

impl Error for MultipleDocumentsError {
    fn description(&self) -> &str {
        "More than one YAML document provided"
    }
}

#[derive(Debug, Clone)]
struct FloatParsingError(String);

impl fmt::Display for FloatParsingError {
    fn fmt(&self, format: &mut fmt::Formatter) -> fmt::Result {
        write!(format, "Parsing {} as floating point number failed", self.0)
    }
}

impl Error for FloatParsingError {
    fn description(&self) -> &str {
        "Floating point number parsing failed"
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Revolution Solid & Contributors.
// author(s): sysnett
// rust-monster is licensed under a MIT License.

use super::ga_core::GASolution;

use std::cmp::Ordering;
use std::iter::FromIterator;

// Better name than 'Basis'?
#[derive(Clone, Copy)]
pub enum GAPopulationSortBasis
{
    Raw,
    Scaled,
}

// The 'Copy' trait requires the 'Clone' trait.
// 'Copy' removes the 'move' semantics from an assignment or a function return of value.
#[derive(Clone, Copy)]
pub enum GAPopulationSortOrder
{
    LowIsBest,
    HighIsBest,
}

/// Genetic Algorithm Population
// TODO: RUST DOCS!
pub struct GAPopulation<T: GASolution>
{
    population: Vec<T>,

    sort_order: GAPopulationSortOrder,

    // 'population' ordered by Raw score.
    population_order_raw: Vec<usize>,
    // Is 'population_order_raw' sorted?
    is_raw_sorted: bool,

    // 'population' ordered by Scaled score.
    population_order_scaled: Vec<usize>,
    // Is 'population_scaled' sorted?
    is_scaled_sorted: bool,

    // We keep 2 lists of indexes to the population vector.
    // One sorted by Raw Score and one by Scaled Score (Fitness).
}
impl<T: GASolution> GAPopulation<T>
{
    // TODO: New should use some parameters, maybe a Config
    pub fn new(p: Vec<T>, order: GAPopulationSortOrder) -> GAPopulation<T>
    {
        let gap = GAPopulation
                  {
                      population: p,
                      sort_order: order,
                      population_order_raw: vec![],
                      is_raw_sorted: false,
                      population_order_scaled: vec![],
                      is_scaled_sorted: false
                  };

        gap
    }

    pub fn population(&mut self) -> &mut Vec<T>
    {
        return &mut self.population
    }

    pub fn evaluate(&mut self)
    {
        for ref mut ind in &mut self.population
        {
            ind.evaluate();
        }
    }

    pub fn size(&self) -> usize
    {
        self.population.len()
    }

    pub fn order(&self) -> GAPopulationSortOrder
    {
        // This is not a 'move', but a copy (GAPopulationSortOrder implements the
        // 'Copy' trait). A move from a borrowed reference (such as 'self') would
        // not be permitted.
        self.sort_order
    }

    //TODO: this is a temporary implementation
    pub fn select(&self) -> &T
    {
        self.individual(0, GAPopulationSortBasis::Scaled)
    }

    //TODO: This is a temporary implementation
    pub fn best(&self) -> &T
    {
        // TODO: Call GAPopulation.scale().

        self.individual(0, GAPopulationSortBasis::Scaled)
    }

    //TODO: This is a temporary implementation
    pub fn worst(&self) -> &T
    {
        self.individual(self.size()-1, GAPopulationSortBasis::Scaled)
    }

    pub fn best_by_raw_score(&self) -> &T
    {
        self.individual(0, GAPopulationSortBasis::Raw)
    }

    pub fn worst_by_raw_score(&self) -> &T
    {
        self.individual(self.size()-1, GAPopulationSortBasis::Scaled)
    }

    pub fn best_by_scaled_score(&self) -> &T
    {
        self.individual(0, GAPopulationSortBasis::Raw)
    }

    pub fn worst_by_scaled_score(&self) -> &T
    {
        self.individual(self.size()-1, GAPopulationSortBasis::Scaled)
    }

    pub fn individual(&self, i : usize, sort_basis : GAPopulationSortBasis) -> &T
    {
        // TODO: Check that i makes sense
        match sort_basis
        {
            GAPopulationSortBasis::Raw
            => { &self.population[self.population_order_raw[i]] },
            GAPopulationSortBasis::Scaled
            => { &self.population[self.population_order_scaled[i]] },
        }
    }

    pub fn sort(&mut self)
    {
        self.sort_int(false, GAPopulationSortBasis::Scaled);
        self.sort_int(false, GAPopulationSortBasis::Raw);
    }

    //TODO: I hate this name
    pub fn sort_int(&mut self, force_sort: bool, sort_basis: GAPopulationSortBasis)
    {
        let mut ordered : Vec<usize> = Vec::from_iter(0..self.size());
        match sort_basis
        {
            GAPopulationSortBasis::Raw
            =>  if (!self.is_raw_sorted) || force_sort
                {
                    match self.sort_order
                    {
                        GAPopulationSortOrder::LowIsBest =>
                        {
                            ordered.sort_by(|s1: &usize, s2: &usize|
                                            self.population[*s1].score()
                                                .partial_cmp(&self.population[*s2].score()).unwrap_or(Ordering::Equal));

                        },
                        GAPopulationSortOrder::HighIsBest =>
                        {
                            ordered.sort_by(|s1: &usize, s2: &usize|
                                            self.population[*s2].score()
                                                .partial_cmp(&self.population[*s1].score()).unwrap_or(Ordering::Equal));

                        },
                    };
                    self.population_order_raw = ordered;
                    self.is_raw_sorted = true;
                },

            GAPopulationSortBasis::Scaled
            =>  if (!self.is_scaled_sorted) || force_sort
                {
                    match self.sort_order
                    {
                        GAPopulationSortOrder::LowIsBest =>
                        {
                            ordered.sort_by(|s1: &usize, s2: &usize|
                                            self.population[*s1].fitness()
                                                .partial_cmp(&self.population[*s2].fitness()).unwrap_or(Ordering::Equal));
                        },

                        GAPopulationSortOrder::HighIsBest =>
                        {
                            ordered.sort_by(|s1: &usize, s2: &usize|
                                            self.population[*s2].fitness()
                                                .partial_cmp(&self.population[*s1].fitness()).unwrap_or(Ordering::Equal));
                        }
                    };
                    self.population_order_scaled = ordered;
                    self.is_scaled_sorted = true;
                },
        };
    }
}

struct GAPopulationRawIterator<'a, T: 'a + GASolution>
{
    population: &'a GAPopulation<T>,
    next_index: usize
}

impl<'a, T: 'a + GASolution> Iterator for GAPopulationRawIterator<'a, T>
{
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item>
    {
        if self.next_index == self.population.size()
        {
            None
        }
        else
        {
            self.next_index = self.next_index + 1;
            Some(self.population.individual(self.next_index - 1, GAPopulationSortBasis::Raw))
        }
    }
}

struct GAPopulationFitnessIterator<'a, T: 'a + GASolution>
{
    population: &'a GAPopulation<T>,
    next_index: usize
}

impl<'a, T: 'a + GASolution> Iterator for GAPopulationFitnessIterator<'a, T>
{
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item>
    {
        if self.next_index == self.population.size()
        {
            None
        }
        else
        {
            self.next_index = self.next_index + 1;
            Some(self.population.individual(self.next_index - 1, GAPopulationSortBasis::Scaled))
        }
    }

}

#[cfg(test)]
mod test
{
    use super::*;
    use super::super::ga_test::*;
    use super::super::ga_core::*;

    #[test]
    fn test_sort_population()
    {
        ga_test_setup("ga_population::test_sort_population");
        let f = GA_TEST_FITNESS_VAL;
        let f_m = GA_TEST_FITNESS_VAL - 1.0;
        let i_f = 1.0 / f;
        let i_f_m = 1.0 / f_m;

        let mut population = GAPopulation::new(vec![GATestSolution::new(f), GATestSolution::new(f_m)], GAPopulationSortOrder::HighIsBest);
        population.sort();

        //TestSolution's Fitness is the inverse of the Score (F = 1/S)
        assert_eq!(population.individual(0, GAPopulationSortBasis::Raw).score(), f);
        assert_eq!(population.individual(1, GAPopulationSortBasis::Raw).score(), f_m);
        assert_eq!(population.individual(0, GAPopulationSortBasis::Scaled).fitness(), i_f_m);
        assert_eq!(population.individual(1, GAPopulationSortBasis::Scaled).fitness(), i_f);
    }

}
<commit_msg>Add GAPopulationRawIterator and GAPopulationFitnessIterator.<commit_after>// Copyright 2016 Revolution Solid & Contributors.
// author(s): sysnett
// rust-monster is licensed under a MIT License.

use super::ga_core::GASolution;

use std::cmp::Ordering;
use std::iter::FromIterator;

// Better name than 'Basis'?
#[derive(Clone, Copy)]
pub enum GAPopulationSortBasis
{
    Raw,
    Scaled,
}

// The 'Copy' trait requires the 'Clone' trait.
// 'Copy' removes the 'move' semantics from an assignment or a function return of value.
#[derive(Clone, Copy)]
pub enum GAPopulationSortOrder
{
    LowIsBest,
    HighIsBest,
}

/// Genetic Algorithm Population
// TODO: RUST DOCS!
pub struct GAPopulation<T: GASolution>
{
    population: Vec<T>,

    sort_order: GAPopulationSortOrder,

    // 'population' ordered by Raw score.
    population_order_raw: Vec<usize>,
    // Is 'population_order_raw' sorted?
    is_raw_sorted: bool,

    // 'population' ordered by Scaled score.
    population_order_scaled: Vec<usize>,
    // Is 'population_scaled' sorted?
    is_scaled_sorted: bool,

    // We keep 2 lists of indexes to the population vector.
    // One sorted by Raw Score and one by Scaled Score (Fitness).
}
impl<T: GASolution> GAPopulation<T>
{
    // TODO: New should use some parameters, maybe a Config
    pub fn new(p: Vec<T>, order: GAPopulationSortOrder) -> GAPopulation<T>
    {
        let gap = GAPopulation
                  {
                      population: p,
                      sort_order: order,
                      population_order_raw: vec![],
                      is_raw_sorted: false,
                      population_order_scaled: vec![],
                      is_scaled_sorted: false
                  };

        gap
    }

    pub fn population(&mut self) -> &mut Vec<T>
    {
        return &mut self.population
    }

    pub fn evaluate(&mut self)
    {
        for ref mut ind in &mut self.population
        {
            ind.evaluate();
        }
    }

    pub fn size(&self) -> usize
    {
        self.population.len()
    }

    pub fn order(&self) -> GAPopulationSortOrder
    {
        // This is not a 'move', but a copy (GAPopulationSortOrder implements the
        // 'Copy' trait). A move from a borrowed reference (such as 'self') would
        // not be permitted.
        self.sort_order
    }

    //TODO: this is a temporary implementation
    pub fn select(&self) -> &T
    {
        self.individual(0, GAPopulationSortBasis::Scaled)
    }

    //TODO: This is a temporary implementation
    pub fn best(&self) -> &T
    {
        // TODO: Call GAPopulation.scale().

        self.individual(0, GAPopulationSortBasis::Scaled)
    }

    //TODO: This is a temporary implementation
    pub fn worst(&self) -> &T
    {
        self.individual(self.size()-1, GAPopulationSortBasis::Scaled)
    }

    pub fn best_by_raw_score(&self) -> &T
    {
        self.individual(0, GAPopulationSortBasis::Raw)
    }

    pub fn worst_by_raw_score(&self) -> &T
    {
        self.individual(self.size()-1, GAPopulationSortBasis::Scaled)
    }

    pub fn best_by_scaled_score(&self) -> &T
    {
        self.individual(0, GAPopulationSortBasis::Raw)
    }

    pub fn worst_by_scaled_score(&self) -> &T
    {
        self.individual(self.size()-1, GAPopulationSortBasis::Scaled)
    }

    pub fn individual(&self, i : usize, sort_basis : GAPopulationSortBasis) -> &T
    {
        // TODO: Check that i makes sense
        match sort_basis
        {
            GAPopulationSortBasis::Raw
            => { &self.population[self.population_order_raw[i]] },
            GAPopulationSortBasis::Scaled
            => { &self.population[self.population_order_scaled[i]] },
        }
    }

    pub fn sort(&mut self)
    {
        self.sort_int(false, GAPopulationSortBasis::Scaled);
        self.sort_int(false, GAPopulationSortBasis::Raw);
    }

    //TODO: I hate this name
    pub fn sort_int(&mut self, force_sort: bool, sort_basis: GAPopulationSortBasis)
    {
        let mut ordered : Vec<usize> = Vec::from_iter(0..self.size());
        match sort_basis
        {
            GAPopulationSortBasis::Raw
            =>  if (!self.is_raw_sorted) || force_sort
                {
                    match self.sort_order
                    {
                        GAPopulationSortOrder::LowIsBest =>
                        {
                            ordered.sort_by(|s1: &usize, s2: &usize|
                                            self.population[*s1].score()
                                                .partial_cmp(&self.population[*s2].score()).unwrap_or(Ordering::Equal));

                        },
                        GAPopulationSortOrder::HighIsBest =>
                        {
                            ordered.sort_by(|s1: &usize, s2: &usize|
                                            self.population[*s2].score()
                                                .partial_cmp(&self.population[*s1].score()).unwrap_or(Ordering::Equal));

                        },
                    };
                    self.population_order_raw = ordered;
                    self.is_raw_sorted = true;
                },

            GAPopulationSortBasis::Scaled
            =>  if (!self.is_scaled_sorted) || force_sort
                {
                    match self.sort_order
                    {
                        GAPopulationSortOrder::LowIsBest =>
                        {
                            ordered.sort_by(|s1: &usize, s2: &usize|
                                            self.population[*s1].fitness()
                                                .partial_cmp(&self.population[*s2].fitness()).unwrap_or(Ordering::Equal));
                        },

                        GAPopulationSortOrder::HighIsBest =>
                        {
                            ordered.sort_by(|s1: &usize, s2: &usize|
                                            self.population[*s2].fitness()
                                                .partial_cmp(&self.population[*s1].fitness()).unwrap_or(Ordering::Equal));
                        }
                    };
                    self.population_order_scaled = ordered;
                    self.is_scaled_sorted = true;
                },
        };
    }

    pub fn raw_score_iterator() -> GAPopulationRawIterator<T>
    {

    }

    pub fn fitness_score_iterator() -> GAPopulationFitnessIterator<T>
    {

    }
}

struct GAPopulationRawIterator<'a, T: 'a + GASolution>
{
    population: &'a GAPopulation<T>,
    next_index: usize
}

impl<'a, T: 'a + GASolution> Iterator for GAPopulationRawIterator<'a, T>
{
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item>
    {
        if self.next_index == self.population.size()
        {
            None
        }
        else
        {
            self.next_index = self.next_index + 1;
            Some(self.population.individual(self.next_index - 1, GAPopulationSortBasis::Raw))
        }
    }
}

struct GAPopulationFitnessIterator<'a, T: 'a + GASolution>
{
    population: &'a GAPopulation<T>,
    next_index: usize
}

impl<'a, T: 'a + GASolution> Iterator for GAPopulationFitnessIterator<'a, T>
{
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item>
    {
        if self.next_index == self.population.size()
        {
            None
        }
        else
        {
            self.next_index = self.next_index + 1;
            Some(self.population.individual(self.next_index - 1, GAPopulationSortBasis::Scaled))
        }
    }

}

#[cfg(test)]
mod test
{
    use super::*;
    use super::super::ga_test::*;
    use super::super::ga_core::*;

    #[test]
    fn test_sort_population()
    {
        ga_test_setup("ga_population::test_sort_population");
        let f = GA_TEST_FITNESS_VAL;
        let f_m = GA_TEST_FITNESS_VAL - 1.0;
        let i_f = 1.0 / f;
        let i_f_m = 1.0 / f_m;

        let mut population = GAPopulation::new(vec![GATestSolution::new(f), GATestSolution::new(f_m)], GAPopulationSortOrder::HighIsBest);
        population.sort();

        //TestSolution's Fitness is the inverse of the Score (F = 1/S)
        assert_eq!(population.individual(0, GAPopulationSortBasis::Raw).score(), f);
        assert_eq!(population.individual(1, GAPopulationSortBasis::Raw).score(), f_m);
        assert_eq!(population.individual(0, GAPopulationSortBasis::Scaled).fitness(), i_f_m);
        assert_eq!(population.individual(1, GAPopulationSortBasis::Scaled).fitness(), i_f);
    }

}
<|endoftext|>


<commit_before>// Helianto -- static website generator
// Copyright © 2015-2016 Mickaël RAYBAUD-ROIG
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::rc::Rc;
use std::collections::HashMap;
use std::path::PathBuf;
use super::super::{Result, Document, DocumentMetadata, DocumentContent};

pub struct IndexGenerator;

impl super::Generator for IndexGenerator {
    fn new() -> IndexGenerator { IndexGenerator }

    fn generate(&self, docs: &[Rc<DocumentMetadata>]) -> Result<Vec<Rc<Document>>> {
        let mut indexes: HashMap<String, Vec<Rc<DocumentMetadata>>> = HashMap::new();

        for doc in docs.iter() {
            let dir: String = PathBuf::from(&doc.url)
                .parent()
                .and_then(|p| p.to_str())
                .unwrap_or("")
                .into();

            println!("Adding page {} to the index {}...", doc.url, dir);
            let documents = indexes.entry(dir).or_insert_with(Vec::new);
            documents.push(doc.clone());
        }

        Ok(indexes.into_iter()
                  .map(|(url, mut docs)| {

                      let meta = DocumentMetadata {
                          url: format!("{}/index.html", url),
                          title: format!("Index of {}", url),
                          ..DocumentMetadata::default()
                      };

                      docs.sort_by(|b, a| a.created.cmp(&b.created));
                      let content = DocumentContent::Index(docs);

                      Rc::new(Document::new(meta, content))
                  })
                  .collect())
    }
}
<commit_msg>Documents in subdirectories are added to indexes<commit_after>// Helianto -- static website generator
// Copyright © 2015-2016 Mickaël RAYBAUD-ROIG
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::rc::Rc;
use std::collections::HashMap;
use std::path::PathBuf;
use super::super::{Result, Document, DocumentMetadata, DocumentContent};

pub struct IndexGenerator;

impl super::Generator for IndexGenerator {
    fn new() -> IndexGenerator { IndexGenerator }

    fn generate(&self, docs: &[Rc<DocumentMetadata>]) -> Result<Vec<Rc<Document>>> {
        let mut indexes: HashMap<String, Vec<Rc<DocumentMetadata>>> = HashMap::new();

        for doc in docs.iter() {
            let mut path: PathBuf = PathBuf::from(&doc.url);

            while let Some(parent) = path.clone().parent() {

                let index_url = match parent.to_str() {
                    Some(string) => string.into(),
                    None => continue,
                };

                let documents = indexes.entry(index_url).or_insert_with(Vec::new);
                documents.push(doc.clone());

                path = parent.into();
            }
        }

        Ok(indexes.into_iter()
                  .map(|(url, mut docs)| {

                      let meta = DocumentMetadata {
                          url: format!("{}/index.html", url),
                          title: format!("Index of {}", url),
                          ..DocumentMetadata::default()
                      };

                      docs.sort_by(|b, a| a.created.cmp(&b.created));
                      let content = DocumentContent::Index(docs);

                      Rc::new(Document::new(meta, content))
                  })
                  .collect())
    }
}
<|endoftext|>


<commit_before>use test::*;
use mock::*;
use test::generated::*;

use protocol::Type;

#[test]
fn test_simple_struct() {
    let instance = Simple { key: Some(String::from("Hello World!")) };
    let mut protocol = encode(&instance);

    assert_eq!(protocol.log(), &[
        Struct(Begin(String::from("Simple"))),
        Field(Begin((String::from("key"), Type::String, 16))),
        Prim(PString(String::from("Hello World!"))),
        Field(End),
        field_end(),
        Struct(End)
    ]);

    let second = decode::<Simple>(&mut protocol);
    assert_eq!(instance.key, second.key);
}

#[test]
fn test_empty_struct() {
    let mut protocol = encode(&Empty);

    assert_eq!(protocol.log(), &[
        Struct(Begin(String::from("Empty"))),
        field_end(),
        Struct(End)
    ]);

    decode::<Empty>(&mut protocol);
}

#[test]
fn test_recursive_struct() {
    let instance = Recursive {
        recurse: Some(vec![
            Recursive { recurse: Some(vec![]) },
            Recursive { recurse: Some(vec![
                Recursive { recurse: Some(vec![]) }
            ]) }
        ])
    };

    let mut protocol = encode(&instance);

    let type_name = String::from("Recursive");
    let field_name = String::from("recurse");

    assert_eq!(protocol.log(), &[
        Struct(Begin(type_name.clone())),
            Field(Begin((field_name.clone(), Type::List, 0))),
                List(Begin((Type::Struct, 2))),
                    Struct(Begin(type_name.clone())),
                        Field(Begin((field_name.clone(), Type::List, 0))),
                            List(Begin((Type::Struct, 0))),
                            List(End),
                        Field(End),
                        field_end(),
                    Struct(End),

                    Struct(Begin(type_name.clone())),
                        Field(Begin((field_name.clone(), Type::List, 0))),
                            List(Begin((Type::Struct, 1))),
                                Struct(Begin(type_name.clone())),
                                    Field(Begin((field_name.clone(), Type::List, 0))),
                                        List(Begin((Type::Struct, 0))),
                                        List(End),
                                    Field(End),
                                    field_end(),
                                Struct(End),
                            List(End),
                        Field(End),
                        field_end(),
                    Struct(End),
                List(End),
            Field(End),
            field_end(),
        Struct(End)
    ]);

    assert_recursive_equal(instance, decode(&mut protocol));

    fn assert_recursive_equal(first: Recursive, second: Recursive) {
        if first.recurse.as_ref().unwrap().len() != second.recurse.as_ref().unwrap().len() {
             panic!("different recurse lengths")
        }

        for (one, two) in first.recurse.unwrap().into_iter().zip(second.recurse.unwrap().into_iter()) {
            assert_recursive_equal(one, two);
        }
    }
}

#[test]
fn test_nested_list_in_struct() {
    let instance = Nested {
        nested: Some(vec![vec![vec![Simple { key: Some(String::from("Hello World!")) }]]])
    };
    let mut protocol = encode(&instance);

    assert_eq!(protocol.log(), &[
        Struct(Begin(String::from("Nested"))),
            Field(Begin((String::from("nested"), Type::List, 32))),
                List(Begin((Type::List, 1))),
                    List(Begin((Type::List, 1))),
                        List(Begin((Type::Struct, 1))),
                            Struct(Begin(String::from("Simple"))),
                                Field(Begin((String::from("key"), Type::String, 16))),
                                    Prim(PString(String::from("Hello World!"))),
                                Field(End),
                                field_end(),
                            Struct(End),
                        List(End),
                    List(End),
                List(End),
            Field(End),
            field_end(),
        Struct(End)
    ]);

    let second = decode::<Nested>(&mut protocol);
    assert_eq!(instance.nested.unwrap()[0][0][0].key, second.nested.unwrap()[0][0][0].key);
}

#[test]
fn test_struct_with_many_fields() {
    let instance = Many {
        one: Some(17),
        two: Some(String::from("Some String")),
        three: Some(vec![Simple { key: Some(String::from("A String")) }])
    };
    let mut protocol = encode(&instance);

    assert_eq!(protocol.log(), &[
        Struct(Begin(String::from("Many"))),
            Field(Begin((String::from("one"), Type::I32, 3))),
                Prim(I32(17)),
            Field(End),
            Field(Begin((String::from("two"), Type::String, 4))),
                Prim(PString(String::from("Some String"))),
            Field(End),
            Field(Begin((String::from("three"), Type::List, 9))),
                List(Begin((Type::Struct, 1))),
                    Struct(Begin(String::from("Simple"))),
                        Field(Begin((String::from("key"), Type::String, 16))),
                            Prim(PString(String::from("A String"))),
                        Field(End),
                        field_end(),
                    Struct(End),
                List(End),
            Field(End),
            field_end(),
        Struct(End)
    ]);

    let second = decode::<Many>(&mut protocol);
    assert_eq!(instance.one, second.one);
    assert_eq!(instance.two, second.two);
    assert_eq!(instance.three.unwrap()[0].key, second.three.unwrap()[0].key);
}

// #[test]
// fn test_struct_with_optional_field_as_some() {
//     let instance = Optional { this: Some(7489) };
//     let mut protocol = encode(&instance);
//
//     assert_eq!(protocol.log(), &[
//         Struct(Begin(String::from("Optional"))),
//         Field(Begin((String::from("this"), Type::I64, 2))),
//         Prim(I64(7489)),
//         Field(End),
//         field_end(),
//         Struct(End)
//     ]);
//
//     let second = decode::<Optional>(&mut protocol);
//     assert_eq!(instance.this, second.this);
// }
//
// #[test]
// fn test_struct_with_optional_field_as_none() {
//     let instance = Optional { this: None };
//     let mut protocol = encode(&instance);
//
//     assert_eq!(protocol.log(), &[
//         Struct(Begin(String::from("Optional"))),
//         field_end(),
//         Struct(End)
//     ]);
//
//     let second = decode::<Optional>(&mut protocol);
//     assert_eq!(instance.this, second.this);
// }

<commit_msg>Fix tests for optional field change<commit_after>use test::*;
use mock::*;
use test::generated::*;

use protocol::Type;

#[test]
fn test_simple_struct() {
    let instance = Simple { key: String::from("Hello World!") };
    let mut protocol = encode(&instance);

    assert_eq!(protocol.log(), &[
        Struct(Begin(String::from("Simple"))),
        Field(Begin((String::from("key"), Type::String, 16))),
        Prim(PString(String::from("Hello World!"))),
        Field(End),
        field_end(),
        Struct(End)
    ]);

    let second = decode::<Simple>(&mut protocol);
    assert_eq!(instance.key, second.key);
}

#[test]
fn test_empty_struct() {
    let mut protocol = encode(&Empty);

    assert_eq!(protocol.log(), &[
        Struct(Begin(String::from("Empty"))),
        field_end(),
        Struct(End)
    ]);

    decode::<Empty>(&mut protocol);
}

#[test]
fn test_recursive_struct() {
    let instance = Recursive {
        recurse: vec![
            Recursive { recurse: vec![] },
            Recursive { recurse: vec![
                Recursive { recurse: vec![] }
            ] }
        ]
    };

    let mut protocol = encode(&instance);

    let type_name = String::from("Recursive");
    let field_name = String::from("recurse");

    assert_eq!(protocol.log(), &[
        Struct(Begin(type_name.clone())),
            Field(Begin((field_name.clone(), Type::List, 0))),
                List(Begin((Type::Struct, 2))),
                    Struct(Begin(type_name.clone())),
                        Field(Begin((field_name.clone(), Type::List, 0))),
                            List(Begin((Type::Struct, 0))),
                            List(End),
                        Field(End),
                        field_end(),
                    Struct(End),

                    Struct(Begin(type_name.clone())),
                        Field(Begin((field_name.clone(), Type::List, 0))),
                            List(Begin((Type::Struct, 1))),
                                Struct(Begin(type_name.clone())),
                                    Field(Begin((field_name.clone(), Type::List, 0))),
                                        List(Begin((Type::Struct, 0))),
                                        List(End),
                                    Field(End),
                                    field_end(),
                                Struct(End),
                            List(End),
                        Field(End),
                        field_end(),
                    Struct(End),
                List(End),
            Field(End),
            field_end(),
        Struct(End)
    ]);

    assert_recursive_equal(instance, decode(&mut protocol));

    fn assert_recursive_equal(first: Recursive, second: Recursive) {
        if first.recurse.len() != second.recurse.len() {
             panic!("different recurse lengths")
        }

        for (one, two) in first.recurse.into_iter().zip(second.recurse.into_iter()) {
            assert_recursive_equal(one, two);
        }
    }
}

#[test]
fn test_nested_list_in_struct() {
    let instance = Nested {
        nested: vec![vec![vec![Simple { key: String::from("Hello World!") }]]]
    };
    let mut protocol = encode(&instance);

    assert_eq!(protocol.log(), &[
        Struct(Begin(String::from("Nested"))),
            Field(Begin((String::from("nested"), Type::List, 32))),
                List(Begin((Type::List, 1))),
                    List(Begin((Type::List, 1))),
                        List(Begin((Type::Struct, 1))),
                            Struct(Begin(String::from("Simple"))),
                                Field(Begin((String::from("key"), Type::String, 16))),
                                    Prim(PString(String::from("Hello World!"))),
                                Field(End),
                                field_end(),
                            Struct(End),
                        List(End),
                    List(End),
                List(End),
            Field(End),
            field_end(),
        Struct(End)
    ]);

    let second = decode::<Nested>(&mut protocol);
    assert_eq!(instance.nested[0][0][0].key, second.nested[0][0][0].key);
}

#[test]
fn test_struct_with_many_fields() {
    let instance = Many {
        one: 17,
        two: String::from("Some String"),
        three: vec![Simple { key: String::from("A String") }]
    };
    let mut protocol = encode(&instance);

    assert_eq!(protocol.log(), &[
        Struct(Begin(String::from("Many"))),
            Field(Begin((String::from("one"), Type::I32, 3))),
                Prim(I32(17)),
            Field(End),
            Field(Begin((String::from("two"), Type::String, 4))),
                Prim(PString(String::from("Some String"))),
            Field(End),
            Field(Begin((String::from("three"), Type::List, 9))),
                List(Begin((Type::Struct, 1))),
                    Struct(Begin(String::from("Simple"))),
                        Field(Begin((String::from("key"), Type::String, 16))),
                            Prim(PString(String::from("A String"))),
                        Field(End),
                        field_end(),
                    Struct(End),
                List(End),
            Field(End),
            field_end(),
        Struct(End)
    ]);

    let second = decode::<Many>(&mut protocol);
    assert_eq!(instance.one, second.one);
    assert_eq!(instance.two, second.two);
    assert_eq!(instance.three[0].key, second.three[0].key);
}

// #[test]
// fn test_struct_with_optional_field_as_some() {
//     let instance = Optional { this: Some(7489) };
//     let mut protocol = encode(&instance);
//
//     assert_eq!(protocol.log(), &[
//         Struct(Begin(String::from("Optional"))),
//         Field(Begin((String::from("this"), Type::I64, 2))),
//         Prim(I64(7489)),
//         Field(End),
//         field_end(),
//         Struct(End)
//     ]);
//
//     let second = decode::<Optional>(&mut protocol);
//     assert_eq!(instance.this, second.this);
// }
//
// #[test]
// fn test_struct_with_optional_field_as_none() {
//     let instance = Optional { this: None };
//     let mut protocol = encode(&instance);
//
//     assert_eq!(protocol.log(), &[
//         Struct(Begin(String::from("Optional"))),
//         field_end(),
//         Struct(End)
//     ]);
//
//     let second = decode::<Optional>(&mut protocol);
//     assert_eq!(instance.this, second.this);
// }

<|endoftext|>


<commit_before>use registry::{Enum, Registry, Cmd, Ns};
use std::old_io::IoResult;

mod ty;
pub mod global_gen;
pub mod static_gen;
pub mod struct_gen;
pub mod static_struct_gen;

/// Trait for a bindings generator.
pub trait Generator {
    /// Builds the GL bindings.
    fn write<W>(&self, registry: &Registry, ns: Ns, dest: &mut W) -> IoResult<()> where W: Writer;
}

/// This function generates a `const name: type = value;` item.
fn gen_enum_item<W>(enm: &Enum, types_prefix: &str, dest: &mut W) -> IoResult<()> where W: Writer {
    // computing the name of the enum
    // if the original starts with a digit, adding an underscore prefix.
    let ident = if (enm.ident.as_slice().char_at(0)).is_numeric() {
        format!("_{}", enm.ident)
    } else {
        enm.ident.clone()
    };

    // if the enum has the value of the form `((Type)Value)`, then `val_regexed` contains `(Type, Value)`
    let val_regexed = {
        if enm.value.starts_with("((") && enm.value.ends_with(")") {
            let separator = enm.value.as_slice().chars().skip(2).position(|c| c == ')').unwrap();
            Some((enm.value.slice(2, separator + 2), enm.value.slice_from(separator + 3).as_slice().trim_matches(')')))
        } else {
            None
        }
    };

    // computing the type of the enum
    let ty = {
        // some enums have a value of the form `((Type)Value)` ; if this is the case, we need to
        //  replace the type of the enum (which is GLenum by default) by the type in the expression
        if let Some((ty, _)) = val_regexed {
            // if the value is like `((Type)Value)`, then the type is `types::Type`
            format!("{}{}", types_prefix, ty)

        } else if enm.value.as_slice().starts_with("\"") {
            // some values are of the form "Value" ; if this is the case, we use `&'static str`
            //  instead of `GLenum`
            "&'static str".to_string()

        } else {
            // some values are `TRUE` or `FALSE`, in which case we use `GLboolean` instead of
            //  `GLenum`
            match ident.as_slice() {
                "TRUE" | "FALSE" => format!("{}GLboolean", types_prefix),
                _ => match enm.ty {
                    Some(ref s) if s.as_slice() == "ull" => format!("{}GLuint64", types_prefix),
                    _ => format!("{}GLenum", types_prefix)
                }
            }
        }
    };

    // computing the value of the enum
    let value = {
        // similar to the type, some values are `((Type)Value)`
        // replacing "((Type)Value)" by "Value as types::Type"
        if let Some((ty, val)) = val_regexed {
            format!("{} as {}{}", val, types_prefix, ty)
        } else {
            enm.value.clone()
        }
    };

    writeln!(dest, "
        #[stable]
        #[allow(dead_code)]
        #[allow(non_upper_case_globals)]
        pub const {}: {} = {};
    ", ident, ty, value)
}

/// Generates all the type aliases for a namespace.
///
/// Aliases are either `pub type = ...` or `#[repr(C)] pub struct ... { ... }` and contain all the
///  things that we can't obtain from the XML files.
pub fn gen_type_aliases<W>(namespace: &Ns, dest: &mut W) -> IoResult<()> where W: Writer {
    match *namespace {
        Ns::Gl | Ns::Gles1 | Ns::Gles2 => {
            try!(ty::build_gl_aliases(dest));
        }

        Ns::Glx => {
            try!(ty::build_gl_aliases(dest));
            try!(ty::build_x_aliases(dest));
            try!(ty::build_glx_aliases(dest));
        }

        Ns::Wgl => {
            try!(ty::build_gl_aliases(dest));
            try!(ty::build_win_aliases(dest));
            try!(ty::build_wgl_aliases(dest));
        }

        Ns::Egl => {
            try!(ty::build_gl_aliases(dest));
            try!(ty::build_egl_aliases(dest));
        }
    }

    Ok(())
}

/// Generates the list of Rust `Arg`s that a `Cmd` requires.
pub fn gen_parameters(cmd: &Cmd, with_idents: bool, with_types: bool) -> Vec<String> {
    cmd.params.iter()
        .map(|binding| {
            // variable name of the binding
            let ident = match binding.ident.as_slice() {
                "in" => "in_",
                "ref" => "ref_",
                "type" => "type_",
                ident => ident,
            };

            // rust type of the binding
            let ty = ty::to_rust_ty(binding.ty.as_slice());

            // returning
            if with_idents && with_types {
                format!("{}: {}", ident, ty)
            } else if with_types {
                format!("{}", ty)
            } else if with_idents {
                format!("{}", ident)
            } else {
                panic!()
            }
        })
        .collect()
}

/// Generates the Rust return type of a `Cmd`.
pub fn gen_return_type(cmd: &Cmd) -> String {
    // turn the return type into a Rust type
    let ty = ty::to_rust_ty(cmd.proto.ty.as_slice());

    // ... but there is one more step: if the Rust type is `c_void`, we replace it with `()`
    if ty == "__gl_imports::libc::c_void" {
        return "()".to_string();
    }

    ty.to_string()
}

/// Generates the native symbol name of a `Cmd`.
///
/// Example results: `"glClear"`, `"wglCreateContext"`, etc.
pub fn gen_symbol_name(ns: &Ns, cmd: &str) -> String {
    (match *ns {
        Ns::Gl | Ns::Gles1 | Ns::Gles2 => "gl",
        Ns::Glx => "glX",
        Ns::Wgl => "wgl",
        Ns::Egl => "egl",
    }).to_string() + cmd
}
<commit_msg>Fix some excess spacing in generated file.<commit_after>use registry::{Enum, Registry, Cmd, Ns};
use std::old_io::IoResult;

mod ty;
pub mod global_gen;
pub mod static_gen;
pub mod struct_gen;
pub mod static_struct_gen;

/// Trait for a bindings generator.
pub trait Generator {
    /// Builds the GL bindings.
    fn write<W>(&self, registry: &Registry, ns: Ns, dest: &mut W) -> IoResult<()> where W: Writer;
}

/// This function generates a `const name: type = value;` item.
fn gen_enum_item<W>(enm: &Enum, types_prefix: &str, dest: &mut W) -> IoResult<()> where W: Writer {
    // computing the name of the enum
    // if the original starts with a digit, adding an underscore prefix.
    let ident = if (enm.ident.as_slice().char_at(0)).is_numeric() {
        format!("_{}", enm.ident)
    } else {
        enm.ident.clone()
    };

    // if the enum has the value of the form `((Type)Value)`, then `val_regexed` contains `(Type, Value)`
    let val_regexed = {
        if enm.value.starts_with("((") && enm.value.ends_with(")") {
            let separator = enm.value.as_slice().chars().skip(2).position(|c| c == ')').unwrap();
            Some((enm.value.slice(2, separator + 2), enm.value.slice_from(separator + 3).as_slice().trim_matches(')')))
        } else {
            None
        }
    };

    // computing the type of the enum
    let ty = {
        // some enums have a value of the form `((Type)Value)` ; if this is the case, we need to
        //  replace the type of the enum (which is GLenum by default) by the type in the expression
        if let Some((ty, _)) = val_regexed {
            // if the value is like `((Type)Value)`, then the type is `types::Type`
            format!("{}{}", types_prefix, ty)

        } else if enm.value.as_slice().starts_with("\"") {
            // some values are of the form "Value" ; if this is the case, we use `&'static str`
            //  instead of `GLenum`
            "&'static str".to_string()

        } else {
            // some values are `TRUE` or `FALSE`, in which case we use `GLboolean` instead of
            //  `GLenum`
            match ident.as_slice() {
                "TRUE" | "FALSE" => format!("{}GLboolean", types_prefix),
                _ => match enm.ty {
                    Some(ref s) if s.as_slice() == "ull" => format!("{}GLuint64", types_prefix),
                    _ => format!("{}GLenum", types_prefix)
                }
            }
        }
    };

    // computing the value of the enum
    let value = {
        // similar to the type, some values are `((Type)Value)`
        // replacing "((Type)Value)" by "Value as types::Type"
        if let Some((ty, val)) = val_regexed {
            format!("{} as {}{}", val, types_prefix, ty)
        } else {
            enm.value.clone()
        }
    };

    writeln!(dest, "\
        #[stable]
        #[allow(dead_code)]
        #[allow(non_upper_case_globals)]
        pub const {}: {} = {}; \
    ", ident, ty, value)
}

/// Generates all the type aliases for a namespace.
///
/// Aliases are either `pub type = ...` or `#[repr(C)] pub struct ... { ... }` and contain all the
///  things that we can't obtain from the XML files.
pub fn gen_type_aliases<W>(namespace: &Ns, dest: &mut W) -> IoResult<()> where W: Writer {
    match *namespace {
        Ns::Gl | Ns::Gles1 | Ns::Gles2 => {
            try!(ty::build_gl_aliases(dest));
        }

        Ns::Glx => {
            try!(ty::build_gl_aliases(dest));
            try!(ty::build_x_aliases(dest));
            try!(ty::build_glx_aliases(dest));
        }

        Ns::Wgl => {
            try!(ty::build_gl_aliases(dest));
            try!(ty::build_win_aliases(dest));
            try!(ty::build_wgl_aliases(dest));
        }

        Ns::Egl => {
            try!(ty::build_gl_aliases(dest));
            try!(ty::build_egl_aliases(dest));
        }
    }

    Ok(())
}

/// Generates the list of Rust `Arg`s that a `Cmd` requires.
pub fn gen_parameters(cmd: &Cmd, with_idents: bool, with_types: bool) -> Vec<String> {
    cmd.params.iter()
        .map(|binding| {
            // variable name of the binding
            let ident = match binding.ident.as_slice() {
                "in" => "in_",
                "ref" => "ref_",
                "type" => "type_",
                ident => ident,
            };

            // rust type of the binding
            let ty = ty::to_rust_ty(binding.ty.as_slice());

            // returning
            if with_idents && with_types {
                format!("{}: {}", ident, ty)
            } else if with_types {
                format!("{}", ty)
            } else if with_idents {
                format!("{}", ident)
            } else {
                panic!()
            }
        })
        .collect()
}

/// Generates the Rust return type of a `Cmd`.
pub fn gen_return_type(cmd: &Cmd) -> String {
    // turn the return type into a Rust type
    let ty = ty::to_rust_ty(cmd.proto.ty.as_slice());

    // ... but there is one more step: if the Rust type is `c_void`, we replace it with `()`
    if ty == "__gl_imports::libc::c_void" {
        return "()".to_string();
    }

    ty.to_string()
}

/// Generates the native symbol name of a `Cmd`.
///
/// Example results: `"glClear"`, `"wglCreateContext"`, etc.
pub fn gen_symbol_name(ns: &Ns, cmd: &str) -> String {
    (match *ns {
        Ns::Gl | Ns::Gles1 | Ns::Gles2 => "gl",
        Ns::Glx => "glX",
        Ns::Wgl => "wgl",
        Ns::Egl => "egl",
    }).to_string() + cmd
}
<|endoftext|>


<commit_before>//! OS-specific functionality.

#![stable(feature = "os", since = "1.0.0")]
#![allow(missing_docs, nonstandard_style, missing_debug_implementations)]

pub mod raw;

// The code below could be written clearer using `cfg_if!`. However, the items below are
// publicly exported by `std` and external tools can have trouble analysing them because of the use
// of a macro that is not vendored by Rust and included in the toolchain.
// See https://github.com/rust-analyzer/rust-analyzer/issues/6038.

#[cfg(all(
    doc,
    not(any(
        all(target_arch = "wasm32", not(target_os = "wasi")),
        all(target_vendor = "fortanix", target_env = "sgx")
    ))
))]
#[path = "."]
mod doc {
    // When documenting std we want to show the `unix`, `windows`, `linux` and `wasi`
    // modules as these are the "main modules" that are used across platforms,
    // so these modules are enabled when `cfg(doc)` is set.
    // This should help show platform-specific functionality in a hopefully cross-platform
    // way in the documentation.

    pub mod unix;

    pub mod linux;

    pub mod wasi;

    pub mod windows;
}
#[cfg(all(
    doc,
    any(
        all(target_arch = "wasm32", not(target_os = "wasi")),
        all(target_vendor = "fortanix", target_env = "sgx")
    )
))]
mod doc {
    // On certain platforms right now the "main modules" modules that are
    // documented don't compile (missing things in `libc` which is empty),
    // so just omit them with an empty module.

    #[unstable(issue = "none", feature = "std_internals")]
    pub mod unix {}

    #[unstable(issue = "none", feature = "std_internals")]
    pub mod linux {}

    #[unstable(issue = "none", feature = "std_internals")]
    pub mod wasi {}

    #[unstable(issue = "none", feature = "std_internals")]
    pub mod windows {}
}
#[cfg(doc)]
#[stable(feature = "os", since = "1.0.0")]
pub use doc::*;

#[cfg(not(doc))]
#[path = "."]
mod imp {
    // If we're not documenting std then we only expose modules appropriate for the
    // current platform.

    #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
    pub mod fortanix_sgx;

    #[cfg(target_os = "hermit")]
    #[path = "hermit/mod.rs"]
    pub mod unix;

    #[cfg(target_os = "android")]
    pub mod android;
    #[cfg(target_os = "dragonfly")]
    pub mod dragonfly;
    #[cfg(target_os = "emscripten")]
    pub mod emscripten;
    #[cfg(target_os = "espidf")]
    pub mod espidf;
    #[cfg(target_os = "freebsd")]
    pub mod freebsd;
    #[cfg(target_os = "fuchsia")]
    pub mod fuchsia;
    #[cfg(target_os = "haiku")]
    pub mod haiku;
    #[cfg(target_os = "illumos")]
    pub mod illumos;
    #[cfg(target_os = "ios")]
    pub mod ios;
    #[cfg(target_os = "l4re")]
    pub mod linux;
    #[cfg(target_os = "linux")]
    pub mod linux;
    #[cfg(target_os = "macos")]
    pub mod macos;
    #[cfg(target_os = "netbsd")]
    pub mod netbsd;
    #[cfg(target_os = "openbsd")]
    pub mod openbsd;
    #[cfg(target_os = "redox")]
    pub mod redox;
    #[cfg(target_os = "solaris")]
    pub mod solaris;
    #[cfg(unix)]
    pub mod unix;

    #[cfg(target_os = "vxworks")]
    pub mod vxworks;

    #[cfg(target_os = "wasi")]
    pub mod wasi;

    #[cfg(windows)]
    pub mod windows;
}
#[cfg(not(doc))]
#[stable(feature = "os", since = "1.0.0")]
pub use imp::*;

#[cfg(any(unix, target_os = "wasi", doc))]
mod fd;
<commit_msg>Simplify std::os module reexports to fix rustdoc linking issues<commit_after>//! OS-specific functionality.

#![stable(feature = "os", since = "1.0.0")]
#![allow(missing_docs, nonstandard_style, missing_debug_implementations)]

pub mod raw;

// The code below could be written clearer using `cfg_if!`. However, the items below are
// publicly exported by `std` and external tools can have trouble analysing them because of the use
// of a macro that is not vendored by Rust and included in the toolchain.
// See https://github.com/rust-analyzer/rust-analyzer/issues/6038.

// On certain platforms right now the "main modules" modules that are
// documented don't compile (missing things in `libc` which is empty),
// so just omit them with an empty module and add the "unstable" attribute.

#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
pub mod fortanix_sgx;

// Unix, linux, wasi and windows are handled a bit differently.
cfg_if::cfg_if! {
    if #[cfg(all(
            doc,
            any(
                all(target_arch = "wasm32", not(target_os = "wasi")),
                all(target_vendor = "fortanix", target_env = "sgx")
            )
        ))]
    {
        #[unstable(issue = "none", feature = "std_internals")]
        pub mod unix {}
        #[unstable(issue = "none", feature = "std_internals")]
        pub mod linux {}
        #[unstable(issue = "none", feature = "std_internals")]
        pub mod wasi {}
        #[unstable(issue = "none", feature = "std_internals")]
        pub mod windows {}
    } else {
        #[cfg(target_os = "hermit")]
        #[path = "hermit/mod.rs"]
        pub mod unix;

        #[cfg(any(unix, doc))]
        pub mod unix;

        #[cfg(any(target_os = "linux", target_os = "l4re", doc))]
        pub mod linux;

        #[cfg(any(target_os = "wasi", doc))]
        pub mod wasi;

        #[cfg(any(windows, doc))]
        pub mod windows;
    }
}

// Others.
#[cfg(target_os = "android")]
pub mod android;
#[cfg(target_os = "dragonfly")]
pub mod dragonfly;
#[cfg(target_os = "emscripten")]
pub mod emscripten;
#[cfg(target_os = "espidf")]
pub mod espidf;
#[cfg(target_os = "freebsd")]
pub mod freebsd;
#[cfg(target_os = "fuchsia")]
pub mod fuchsia;
#[cfg(target_os = "haiku")]
pub mod haiku;
#[cfg(target_os = "illumos")]
pub mod illumos;
#[cfg(target_os = "ios")]
pub mod ios;
#[cfg(target_os = "macos")]
pub mod macos;
#[cfg(target_os = "netbsd")]
pub mod netbsd;
#[cfg(target_os = "openbsd")]
pub mod openbsd;
#[cfg(target_os = "redox")]
pub mod redox;
#[cfg(target_os = "solaris")]
pub mod solaris;

#[cfg(target_os = "vxworks")]
pub mod vxworks;

#[cfg(any(unix, target_os = "wasi", doc))]
mod fd;
<|endoftext|>


<commit_before>use index::btree::external::ExtNode;
use index::btree::internal::InNode;
use index::btree::node::is_node_locked;
use index::btree::node::read_node;
use index::btree::node::read_unchecked;
use index::btree::node::write_node;
use index::btree::node::write_non_empty;
use index::btree::node::write_targeted;
use index::btree::node::EmptyNode;
use index::btree::node::Node;
use index::btree::node::NodeData;
use index::btree::node::NodeWriteGuard;
use index::btree::search::mut_search;
use index::btree::search::MutSearchResult;
use index::btree::LevelTree;
use index::btree::NodeCellRef;
use index::btree::{external, BPlusTree};
use index::lsmtree::tree::LEVEL_PAGE_DIFF_MULTIPLIER;
use index::EntryKey;
use index::Slice;
use itertools::Itertools;
use smallvec::SmallVec;
use std::collections::{BTreeSet, HashSet};
use std::fmt::Debug;
use std::mem;
use std::sync::atomic::Ordering::Relaxed;

enum Selection<KS, PS>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    Selected(Vec<NodeWriteGuard<KS, PS>>),
    Innode(NodeCellRef),
}

fn select<KS, PS>(node: &NodeCellRef) -> Vec<NodeWriteGuard<KS, PS>>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let search = mut_search::<KS, PS>(node, &smallvec!());
    match search {
        MutSearchResult::External => {
            let mut collected = vec![write_node(node)];
            while collected.len() < LEVEL_PAGE_DIFF_MULTIPLIER {
                let right = write_node(
                    collected
                        .last_mut()
                        .unwrap()
                        .right_ref_mut_no_empty()
                        .unwrap(),
                );
                if right.is_none() {
                    break;
                } else {
                    collected.push(right);
                }
            }
            return collected;
        }
        MutSearchResult::Internal(node) => select::<KS, PS>(&node),
    }
}

fn prune_selected<'a, KS, PS>(node: &NodeCellRef, bound: &EntryKey)
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let first_search = mut_search::<KS, PS>(node, &smallvec!());
    match first_search {
        MutSearchResult::Internal(sub_node_ref) => {
            let sub_node = read_unchecked::<KS, PS>(&sub_node_ref);
            if !sub_node.is_empty_node() && !sub_node.is_ext() {
                prune_selected::<KS, PS>(&sub_node_ref, bound);
            }
        }
        MutSearchResult::External => unreachable!(),
    };
    let mut node_ref = node.clone();
    loop {
        let mut page = write_node::<KS, PS>(&node_ref);
        let page_len = page.len();
        if !page.is_empty_node() {
            let mut ptr_indices: HashSet<_> = page.innode().ptrs.as_slice_immute()[..page_len + 1]
                .iter()
                .enumerate()
                .filter_map(|(i, sub_level)| {
                    if read_unchecked::<KS, PS>(sub_level).is_empty_node() {
                        Some(i)
                    } else {
                        None
                    }
                })
                .collect();
            let page_right_bound = page.right_bound().clone();
            if ptr_indices.len() == page.len() + 1 {
                // all sub nodes are empty
                // will set current node empty either
                let next_page_ref = page.innode().right.clone();
                *page = NodeData::Empty(box EmptyNode {
                    left: None,
                    right: next_page_ref,
                });
            } else {
                let mut innode = page.innode_mut();
                let mut new_keys = KS::init();
                let mut new_ptrs = PS::init();
                {
                    let ptrs: Vec<&mut _> = innode.ptrs.as_slice()[..page_len + 1]
                        .iter_mut()
                        .enumerate()
                        .filter(|(i, _)| !ptr_indices.contains(&i))
                        .map(|(_, p)| p)
                        .collect();

                    let keys: Vec<&mut _> = innode.keys.as_slice()[..page_len]
                        .iter_mut()
                        .enumerate()
                        .filter(|(i, _)| !ptr_indices.contains(&i))
                        .map(|(_, k)| k)
                        .collect();
                    debug!("Prune filtered page have keys {:?}", &keys);
                    debug_assert_eq!(ptrs.len(), keys.len() + 1);
                    innode.len = keys.len();
                    let new_keys = new_keys.as_slice();
                    let new_ptrs = new_ptrs.as_slice();
                    for (i, key) in keys.into_iter().enumerate() {
                        debug_assert!(key > &mut smallvec!(0));
                        mem::swap(&mut new_keys[i], key);
                    }
                    for (i, ptr) in ptrs.into_iter().enumerate() {
                        debug_assert!(!ptr.is_default());
                        mem::swap(&mut new_ptrs[i], ptr);
                    }
                }
                innode.keys = new_keys;
                innode.ptrs = new_ptrs;
            }
            if &page_right_bound >= bound {
                break;
            }
        }
        node_ref = page.right_ref().unwrap().clone();
    }
}

pub fn level_merge<KS, PS>(src_tree: &BPlusTree<KS, PS>, dest_tree: &LevelTree) -> usize
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let mut left_most_leaf_guards = select::<KS, PS>(&src_tree.get_root());
    let merge_page_len = left_most_leaf_guards.len();
    let mut num_keys_removed = 0;
    let left_most_id = left_most_leaf_guards.first().unwrap().ext_id();
    let prune_bound = left_most_leaf_guards.last().unwrap().right_bound().clone();

    debug!("Merge selected {} pages", left_most_leaf_guards.len());
    debug_assert_eq!(
        left_most_id,
        src_tree.head_page_id,
        "{}",
        left_most_leaf_guards.first().unwrap().type_name()
    );

    // merge to dest_tree
    {
        let mut deleted_keys = src_tree.deleted.write();
        let mut merged_deleted_keys = vec![];
        let keys: Vec<EntryKey> = left_most_leaf_guards
            .iter()
            .filter(|&g| !g.is_empty_node())
            .map(|g| &g.keys()[..g.len()])
            .flatten()
            .filter(|&k| {
                if deleted_keys.contains(k) {
                    merged_deleted_keys.push(k.clone());
                    false
                } else {
                    true
                }
            })
            .cloned()
            .collect_vec();
        num_keys_removed = keys.len();
        debug!("Merge selected keys are {:?}", &keys);
        dest_tree.merge_with_keys(box keys);
        for rk in &merged_deleted_keys {
            deleted_keys.remove(rk);
        }
    }

    // adjust leaf left, right references
    {
        let right_right_most = left_most_leaf_guards
            .last()
            .unwrap()
            .right_ref()
            .unwrap()
            .clone();

        let left_left_most = left_most_leaf_guards
            .first()
            .unwrap()
            .left_ref()
            .unwrap()
            .clone();

        debug_assert!(read_unchecked::<KS, PS>(&left_left_most).is_none());

        for mut g in &mut left_most_leaf_guards {
            external::make_deleted(&g.ext_id());
            **g = NodeData::Empty(box EmptyNode {
                left: Some(left_left_most.clone()),
                right: right_right_most.clone(),
            });
        }

        let mut new_first_node = write_node::<KS, PS>(&right_right_most);
        let mut new_first_node_ext = new_first_node.extnode_mut();
        new_first_node_ext.id = left_most_id;
        new_first_node_ext.prev = left_left_most;

        debug_assert_eq!(new_first_node_ext.id, src_tree.head_page_id);

        ExtNode::<KS, PS>::make_changed(&right_right_most, src_tree);
    }

    // cleanup upper level references
    prune_selected::<KS, PS>(&src_tree.get_root(), &prune_bound);

    src_tree.len.fetch_sub(num_keys_removed, Relaxed);

    merge_page_len
}
<commit_msg>reset head page<commit_after>use index::btree::external::ExtNode;
use index::btree::internal::InNode;
use index::btree::node::is_node_locked;
use index::btree::node::read_node;
use index::btree::node::read_unchecked;
use index::btree::node::write_node;
use index::btree::node::write_non_empty;
use index::btree::node::write_targeted;
use index::btree::node::EmptyNode;
use index::btree::node::Node;
use index::btree::node::NodeData;
use index::btree::node::NodeWriteGuard;
use index::btree::search::mut_search;
use index::btree::search::MutSearchResult;
use index::btree::LevelTree;
use index::btree::NodeCellRef;
use index::btree::{external, BPlusTree};
use index::lsmtree::tree::LEVEL_PAGE_DIFF_MULTIPLIER;
use index::EntryKey;
use index::Slice;
use itertools::Itertools;
use smallvec::SmallVec;
use std::collections::{BTreeSet, HashSet};
use std::fmt::Debug;
use std::mem;
use std::sync::atomic::Ordering::Relaxed;

enum Selection<KS, PS>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    Selected(Vec<NodeWriteGuard<KS, PS>>),
    Innode(NodeCellRef),
}

fn select<KS, PS>(node: &NodeCellRef) -> Vec<NodeWriteGuard<KS, PS>>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let search = mut_search::<KS, PS>(node, &smallvec!());
    match search {
        MutSearchResult::External => {
            let mut collected = vec![write_node(node)];
            while collected.len() < LEVEL_PAGE_DIFF_MULTIPLIER {
                let right = write_node(
                    collected
                        .last_mut()
                        .unwrap()
                        .right_ref_mut_no_empty()
                        .unwrap(),
                );
                if right.is_none() {
                    break;
                } else {
                    collected.push(right);
                }
            }
            return collected;
        }
        MutSearchResult::Internal(node) => select::<KS, PS>(&node),
    }
}

fn prune_selected<'a, KS, PS>(node: &NodeCellRef, bound: &EntryKey)
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let first_search = mut_search::<KS, PS>(node, &smallvec!());
    match first_search {
        MutSearchResult::Internal(sub_node_ref) => {
            let sub_node = read_unchecked::<KS, PS>(&sub_node_ref);
            if !sub_node.is_empty_node() && !sub_node.is_ext() {
                prune_selected::<KS, PS>(&sub_node_ref, bound);
            }
        }
        MutSearchResult::External => unreachable!(),
    };
    let mut node_ref = node.clone();
    loop {
        let mut page = write_node::<KS, PS>(&node_ref);
        let page_len = page.len();
        if !page.is_empty_node() {
            let mut ptr_indices: HashSet<_> = page.innode().ptrs.as_slice_immute()[..page_len + 1]
                .iter()
                .enumerate()
                .filter_map(|(i, sub_level)| {
                    if read_unchecked::<KS, PS>(sub_level).is_empty_node() {
                        Some(i)
                    } else {
                        None
                    }
                })
                .collect();
            let page_right_bound = page.right_bound().clone();
            if ptr_indices.len() == page.len() + 1 {
                // all sub nodes are empty
                // will set current node empty either
                let next_page_ref = page.innode().right.clone();
                *page = NodeData::Empty(box EmptyNode {
                    left: None,
                    right: next_page_ref,
                });
            } else {
                let mut innode = page.innode_mut();
                let mut new_keys = KS::init();
                let mut new_ptrs = PS::init();
                {
                    let ptrs: Vec<&mut _> = innode.ptrs.as_slice()[..page_len + 1]
                        .iter_mut()
                        .enumerate()
                        .filter(|(i, _)| !ptr_indices.contains(&i))
                        .map(|(_, p)| p)
                        .collect();

                    let keys: Vec<&mut _> = innode.keys.as_slice()[..page_len]
                        .iter_mut()
                        .enumerate()
                        .filter(|(i, _)| !ptr_indices.contains(&i))
                        .map(|(_, k)| k)
                        .collect();
                    debug!("Prune filtered page have keys {:?}", &keys);
                    debug_assert_eq!(ptrs.len(), keys.len() + 1);
                    innode.len = keys.len();
                    let new_keys = new_keys.as_slice();
                    let new_ptrs = new_ptrs.as_slice();
                    for (i, key) in keys.into_iter().enumerate() {
                        debug_assert!(key > &mut smallvec!(0));
                        mem::swap(&mut new_keys[i], key);
                    }
                    for (i, ptr) in ptrs.into_iter().enumerate() {
                        debug_assert!(!ptr.is_default());
                        mem::swap(&mut new_ptrs[i], ptr);
                    }
                }
                innode.keys = new_keys;
                innode.ptrs = new_ptrs;
            }
            if &page_right_bound >= bound {
                break;
            }
        }
        node_ref = page.right_ref().unwrap().clone();
    }
}

pub fn level_merge<KS, PS>(src_tree: &BPlusTree<KS, PS>, dest_tree: &LevelTree) -> usize
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let mut left_most_leaf_guards = select::<KS, PS>(&src_tree.get_root());
    let merge_page_len = left_most_leaf_guards.len();
    let mut num_keys_removed = 0;
    let left_most_id = left_most_leaf_guards.first().unwrap().ext_id();
    let prune_bound = left_most_leaf_guards.last().unwrap().right_bound().clone();

    debug!("Merge selected {} pages", left_most_leaf_guards.len());
    debug_assert_eq!(
        left_most_id,
        src_tree.head_page_id,
        "{}",
        left_most_leaf_guards.first().unwrap().type_name()
    );

    // merge to dest_tree
    {
        let mut deleted_keys = src_tree.deleted.write();
        let mut merged_deleted_keys = vec![];
        let keys: Vec<EntryKey> = left_most_leaf_guards
            .iter()
            .filter(|&g| !g.is_empty_node())
            .map(|g| &g.keys()[..g.len()])
            .flatten()
            .filter(|&k| {
                if deleted_keys.contains(k) {
                    merged_deleted_keys.push(k.clone());
                    false
                } else {
                    true
                }
            })
            .cloned()
            .collect_vec();
        num_keys_removed = keys.len();
        debug!("Merge selected keys are {:?}", &keys);
        dest_tree.merge_with_keys(box keys);
        for rk in &merged_deleted_keys {
            deleted_keys.remove(rk);
        }
    }

    // adjust leaf left, right references
    {
        let right_right_most = left_most_leaf_guards
            .last()
            .unwrap()
            .right_ref()
            .unwrap()
            .clone();

        let left_left_most = left_most_leaf_guards
            .first()
            .unwrap()
            .left_ref()
            .unwrap()
            .clone();

        debug_assert!(read_unchecked::<KS, PS>(&left_left_most).is_none());

        for mut g in &mut left_most_leaf_guards {
            external::make_deleted(&g.ext_id());
            **g = NodeData::Empty(box EmptyNode {
                left: Some(left_left_most.clone()),
                right: right_right_most.clone(),
            });
        }

        let mut new_first_node = write_node::<KS, PS>(&right_right_most);
        let mut new_first_node_ext = new_first_node.extnode_mut();
        new_first_node_ext.id = src_tree.head_page_id;
        new_first_node_ext.prev = left_left_most;

        ExtNode::<KS, PS>::make_changed(&right_right_most, src_tree);
    }

    // cleanup upper level references
    prune_selected::<KS, PS>(&src_tree.get_root(), &prune_bound);

    src_tree.len.fetch_sub(num_keys_removed, Relaxed);

    merge_page_len
}
<|endoftext|>


<commit_before>//! Access to I/O ports

use core::marker::PhantomData;

pub trait PortReadWrite {
    unsafe fn read(port: u16) -> Self;
    unsafe fn write(port: u16, value: Self);
}

impl PortReadWrite for u8 {
    #[inline]
    unsafe fn read(port: u16) -> u8 {
        let value: u8;
        asm!("inb %dx, %al" : "={ax}"(value) : "{dx}"(port) :: "volatile");
        value
    }

    #[inline]
    unsafe fn write(port: u16, value: u8) {
        asm!("outb %al, %dx" :: "{dx}"(port), "{al}"(value) :: "volatile");
    }
}

impl PortReadWrite for u16 {
    #[inline]
    unsafe fn read(port: u16) -> u16 {
        let value: u16;
        asm!("inw %dx, %ax" : "={ax}"(value) : "{dx}"(port) :: "volatile");
        value
    }

    #[inline]
    unsafe fn write(port: u16, value: u16) {
        asm!("outw %ax, %dx" :: "{dx}"(port), "{al}"(value) :: "volatile");
    }
}

impl PortReadWrite for u32 {
    #[inline]
    unsafe fn read(port: u16) -> u32 {
        let value: u32;
        asm!("inl %dx, %eax" : "={ax}"(value) : "{dx}"(port) :: "volatile");
        value
    }

    #[inline]
    unsafe fn write(port: u16, value: u32) {
        asm!("outl %eax, %dx" :: "{dx}"(port), "{al}"(value) :: "volatile");
    }
}

pub struct Port<T: PortReadWrite> {
    port: u16,
    phantom: PhantomData<T>,
}

impl<T: PortReadWrite> Port<T> {
    pub const fn new(port: u16) -> Port<T> {
        Port {
            port: port,
            phantom: PhantomData,
        }
    }

    #[inline]
    pub unsafe fn read(&self) -> T {
        T::read(self.port)
    }

    #[inline]
    pub unsafe fn write(&mut self, value: T) {
        T::write(self.port, value)
    }
}
<commit_msg>Rename PortReadWrite::{read, write} functions<commit_after>//! Access to I/O ports

use core::marker::PhantomData;

pub trait PortReadWrite {
    unsafe fn read_from_port(port: u16) -> Self;
    unsafe fn write_to_port(port: u16, value: Self);
}

impl PortReadWrite for u8 {
    #[inline]
    unsafe fn read_from_port(port: u16) -> u8 {
        let value: u8;
        asm!("inb %dx, %al" : "={ax}"(value) : "{dx}"(port) :: "volatile");
        value
    }

    #[inline]
    unsafe fn write_to_port(port: u16, value: u8) {
        asm!("outb %al, %dx" :: "{dx}"(port), "{al}"(value) :: "volatile");
    }
}

impl PortReadWrite for u16 {
    #[inline]
    unsafe fn read_from_port(port: u16) -> u16 {
        let value: u16;
        asm!("inw %dx, %ax" : "={ax}"(value) : "{dx}"(port) :: "volatile");
        value
    }

    #[inline]
    unsafe fn write_to_port(port: u16, value: u16) {
        asm!("outw %ax, %dx" :: "{dx}"(port), "{al}"(value) :: "volatile");
    }
}

impl PortReadWrite for u32 {
    #[inline]
    unsafe fn read_from_port(port: u16) -> u32 {
        let value: u32;
        asm!("inl %dx, %eax" : "={ax}"(value) : "{dx}"(port) :: "volatile");
        value
    }

    #[inline]
    unsafe fn write_to_port(port: u16, value: u32) {
        asm!("outl %eax, %dx" :: "{dx}"(port), "{al}"(value) :: "volatile");
    }
}

pub struct Port<T: PortReadWrite> {
    port: u16,
    phantom: PhantomData<T>,
}

impl<T: PortReadWrite> Port<T> {
    pub const fn new(port: u16) -> Port<T> {
        Port {
            port: port,
            phantom: PhantomData,
        }
    }

    #[inline]
    pub unsafe fn read(&self) -> T {
        T::read_from_port(self.port)
    }

    #[inline]
    pub unsafe fn write(&mut self, value: T) {
        T::write_to_port(self.port, value)
    }
}
<|endoftext|>