<commit_before>use class::TypeParams;
use ctxt::{NodeMap, SemContext};
use dora_parser::ast::Type::{TypeBasic, TypeLambda, TypeSelf, TypeTuple};
use dora_parser::ast::{Stmt, Type};
use dora_parser::error::msg::Msg;
use mem;
use sym::Sym::{SymClass, SymClassTypeParam, SymFctTypeParam, SymStruct, SymTrait};
use ty::BuiltinType;

mod abstractck;
mod clsdefck;
mod constdefck;
mod fctdefck;
mod flowck;
mod globaldef;
mod globaldefck;
mod implck;
mod impldefck;
mod nameck;
mod prelude;
mod returnck;
pub mod specialize;
mod structdefck;
mod superck;
mod traitdefck;
mod typeck;

macro_rules! return_on_error {
    ($ctxt: ident) => {{
        if $ctxt.diag.lock().has_errors() {
            return;
        }
    }};
}

pub fn check<'ast>(ctxt: &mut SemContext<'ast>) {
    let mut map_cls_defs = NodeMap::new(); // get ClassId from ast node
    let mut map_struct_defs = NodeMap::new(); // get StructId from ast node
    let mut map_trait_defs = NodeMap::new(); // get TraitId from ast node
    let mut map_impl_defs = NodeMap::new(); // get ImplId from ast node
    let mut map_global_defs = NodeMap::new(); // get GlobalId from ast node
    let mut map_const_defs = NodeMap::new(); // get ConstId from ast node

    // add user defined fcts and classes to ctxt
    // this check does not look into fct or class bodies
    globaldef::check(
        ctxt,
        &mut map_cls_defs,
        &mut map_struct_defs,
        &mut map_trait_defs,
        &mut map_impl_defs,
        &mut map_global_defs,
        &mut map_const_defs,
    );
    return_on_error!(ctxt);

    // define internal classes
    prelude::internal_classes(ctxt);

    // checks class/struct/trait definitions/bodies
    clsdefck::check(ctxt, &map_cls_defs);
    structdefck::check(ctxt, &map_struct_defs);
    traitdefck::check(ctxt, &map_trait_defs);
    impldefck::check(ctxt, &map_impl_defs);
    globaldefck::check(ctxt, &map_global_defs);
    constdefck::check(ctxt, &map_const_defs);
    return_on_error!(ctxt);

    // check names/identifiers of local variables
    // and their usage (variable def/use, function calls) in function bodies
    nameck::check(ctxt);
    return_on_error!(ctxt);

    // check type definitions of params,
    // return types and local variables in functions
    fctdefck::check(ctxt);
    return_on_error!(ctxt);

    superck::check_override(ctxt);
    return_on_error!(ctxt);

    // check impl methods against trait definition
    implck::check(ctxt);
    return_on_error!(ctxt);

    // define internal functions
    prelude::internal_functions(ctxt);

    // check types of expressions in functions
    typeck::check(ctxt);
    return_on_error!(ctxt);

    // are break and continue used in the right places?
    flowck::check(ctxt);

    // checks if function has a return value
    returnck::check(ctxt);

    // add size of super classes to field offsets
    superck::check(ctxt);
    return_on_error!(ctxt);

    abstractck::check(ctxt);

    // check for internal functions or classes
    internalck(ctxt);
    return_on_error!(ctxt);

    // initialize addresses for global variables
    init_global_addresses(ctxt);
}

fn internalck<'ast>(ctxt: &SemContext<'ast>) {
    for fct in ctxt.fcts.iter() {
        let fct = fct.read();

        if fct.in_class() {
            continue;
        }

        if fct.internal && !fct.internal_resolved {
            ctxt.diag.lock().report(fct.pos, Msg::UnresolvedInternal);
        }

        if fct.kind.is_definition() && !fct.in_trait() {
            ctxt.diag.lock().report(fct.pos, Msg::MissingFctBody);
        }
    }

    for cls in ctxt.classes.iter() {
        let cls = cls.read();

        if cls.internal && !cls.internal_resolved {
            ctxt.diag.lock().report(cls.pos, Msg::UnresolvedInternal);
        }

        for method in &cls.methods {
            let method = ctxt.fcts.idx(*method);
            let method = method.read();

            if method.internal && !method.internal_resolved {
                ctxt.diag.lock().report(method.pos, Msg::UnresolvedInternal);
            }

            if method.kind.is_definition() && !method.is_abstract {
                ctxt.diag.lock().report(method.pos, Msg::MissingFctBody);
            }
        }
    }
}

fn init_global_addresses<'ast>(ctxt: &SemContext<'ast>) {
    let globals = ctxt.globals.lock();
    let mut size = 0;
    let mut offsets = Vec::with_capacity(globals.len());

    for glob in globals.iter() {
        let glob = glob.lock();

        let ty_size = glob.ty.size(ctxt);
        let ty_align = glob.ty.align(ctxt);

        offsets.push(mem::align_i32(size, ty_align));
        size += ty_size;
    }

    let ptr = ctxt.gc.alloc_perm(size as usize);

    for (ind, glob) in globals.iter().enumerate() {
        let mut glob = glob.lock();
        let offset = offsets[ind];

        glob.address_value = ptr.offset(offset as usize);
    }
}

pub fn read_type<'ast>(ctxt: &SemContext<'ast>, t: &'ast Type) -> Option<BuiltinType> {
    match *t {
        TypeSelf(_) => {
            return Some(BuiltinType::This);
        }

        TypeBasic(ref basic) => {
            let sym = ctxt.sym.lock().get(basic.name);
            if let Some(sym) = sym {
                match sym {
                    SymClass(cls_id) => {
                        let ty = if basic.params.len() > 0 {
                            let mut type_params = Vec::new();

                            for param in &basic.params {
                                let param = read_type(ctxt, param);

                                if let Some(param) = param {
                                    type_params.push(param);
                                } else {
                                    return None;
                                }
                            }

                            let cls = ctxt.classes.idx(cls_id);
                            let cls = cls.read();

                            if cls.type_params.len() != type_params.len() {
                                let msg = Msg::WrongNumberTypeParams(
                                    cls.type_params.len(),
                                    type_params.len(),
                                );
                                ctxt.diag.lock().report(basic.pos, msg);
                                return None;
                            }

                            for (tp, ty) in cls.type_params.iter().zip(type_params.iter()) {
                                if let Some(cls_id) = tp.class_bound {
                                    let cls = ctxt.cls(cls_id);

                                    if !ty.subclass_from(ctxt, cls) {
                                        let name = ty.name(ctxt);
                                        let cls = cls.name(ctxt);

                                        let msg = Msg::ClassBoundNotSatisfied(name, cls);
                                        ctxt.diag.lock().report(basic.pos, msg);
                                    }
                                }

                                let cls_id = if let Some(cls_id) = ty.cls_id(ctxt) {
                                    cls_id
                                } else {
                                    continue;
                                };

                                let cls = ctxt.classes.idx(cls_id);
                                let cls = cls.read();

                                for &trait_bound in &tp.trait_bounds {
                                    if !cls.traits.contains(&trait_bound) {
                                        let bound = ctxt.traits[trait_bound].read();
                                        let name = ty.name(ctxt);
                                        let trait_name = ctxt.interner.str(bound.name).to_string();
                                        let msg = Msg::TraitBoundNotSatisfied(name, trait_name);
                                        ctxt.diag.lock().report(bound.pos, msg);
                                    }
                                }
                            }

                            let list_id = ctxt.lists.lock().insert(type_params.into());
                            BuiltinType::Class(cls.id, list_id)
                        } else {
                            let cls = ctxt.classes.idx(cls_id);
                            let cls = cls.read();

                            cls.ty
                        };

                        return Some(ty);
                    }

                    SymTrait(trait_id) => {
                        if basic.params.len() > 0 {
                            let msg = Msg::NoTypeParamsExpected;
                            ctxt.diag.lock().report(basic.pos, msg);
                        }

                        return Some(BuiltinType::Trait(trait_id));
                    }

                    SymStruct(struct_id) => {
                        if basic.params.len() > 0 {
                            let msg = Msg::NoTypeParamsExpected;
                            ctxt.diag.lock().report(basic.pos, msg);
                        }

                        let list_id = ctxt.lists.lock().insert(TypeParams::empty());
                        return Some(BuiltinType::Struct(struct_id, list_id));
                    }

                    SymClassTypeParam(cls_id, type_param_id) => {
                        if basic.params.len() > 0 {
                            let msg = Msg::NoTypeParamsExpected;
                            ctxt.diag.lock().report(basic.pos, msg);
                        }

                        return Some(BuiltinType::ClassTypeParam(cls_id, type_param_id));
                    }

                    SymFctTypeParam(fct_id, type_param_id) => {
                        if basic.params.len() > 0 {
                            let msg = Msg::NoTypeParamsExpected;
                            ctxt.diag.lock().report(basic.pos, msg);
                        }

                        return Some(BuiltinType::FctTypeParam(fct_id, type_param_id));
                    }

                    _ => {
                        let name = ctxt.interner.str(basic.name).to_string();
                        let msg = Msg::ExpectedType(name);
                        ctxt.diag.lock().report(basic.pos, msg);
                    }
                }
            } else {
                let name = ctxt.interner.str(basic.name).to_string();
                let msg = Msg::UnknownType(name);
                ctxt.diag.lock().report(basic.pos, msg);
            }
        }

        TypeTuple(ref tuple) if tuple.subtypes.len() == 0 => {
            return Some(BuiltinType::Unit);
        }

        TypeLambda(ref lambda) => {
            let mut params = vec![];

            for param in &lambda.params {
                if let Some(p) = read_type(ctxt, param) {
                    params.push(p);
                } else {
                    return None;
                }
            }

            let ret = if let Some(ret) = read_type(ctxt, &lambda.ret) {
                ret
            } else {
                return None;
            };

            let ty = ctxt.lambda_types.lock().insert(params, ret);
            let ty = BuiltinType::Lambda(ty);

            return Some(ty);
        }

        _ => ctxt.diag.lock().report_unimplemented(t.pos()),
    }

    None
}

pub fn always_returns(s: &Stmt) -> bool {
    match returnck::returns_value(s) {
        Ok(_) => true,
        Err(_) => false,
    }
}

#[cfg(test)]
mod tests {
    use ctxt::SemContext;
    use dora_parser::error::msg::Msg;
    use dora_parser::lexer::position::Position;
    use test;

    pub fn ok(code: &'static str) {
        test::parse_with_errors(code, |ctxt| {
            let diag = ctxt.diag.lock();
            let errors = diag.errors();

            println!("errors = {:?}", errors);

            for e in errors {
                println!("{}", e.message());
            }

            assert!(!diag.has_errors());
        });
    }

    pub fn ok_with_test<F, R>(code: &'static str, f: F) -> R
    where
        F: FnOnce(&SemContext) -> R,
    {
        test::parse_with_errors(code, |ctxt| {
            let diag = ctxt.diag.lock();
            let errors = diag.errors();

            println!("errors = {:?}", errors);

            for e in errors {
                println!("{}", e.message());
            }

            assert!(!diag.has_errors());

            f(ctxt)
        })
    }

    pub fn err(code: &'static str, pos: Position, msg: Msg) {
        test::parse_with_errors(code, |ctxt| {
            let diag = ctxt.diag.lock();
            let errors = diag.errors();

            println!("errors = {:?}", errors);

            assert_eq!(1, errors.len());
            assert_eq!(pos, errors[0].pos);
            assert_eq!(msg, errors[0].msg);
        });
    }

    pub fn errors(code: &'static str, vec: &[(Position, Msg)]) {
        test::parse_with_errors(code, |ctxt| {
            let diag = ctxt.diag.lock();
            let errors = diag.errors();

            println!("errors = {:?}", errors);
            assert_eq!(vec.len(), errors.len());

            for (ind, error) in errors.iter().enumerate() {
                assert_eq!(vec[ind].0, error.pos);
                assert_eq!(vec[ind].1, error.msg);
            }
        });
    }

    pub fn pos(line: u32, col: u32) -> Position {
        Position::new(line, col)
    }
}
<commit_msg>fix offset for global variables<commit_after>use class::TypeParams;
use ctxt::{NodeMap, SemContext};
use dora_parser::ast::Type::{TypeBasic, TypeLambda, TypeSelf, TypeTuple};
use dora_parser::ast::{Stmt, Type};
use dora_parser::error::msg::Msg;
use mem;
use sym::Sym::{SymClass, SymClassTypeParam, SymFctTypeParam, SymStruct, SymTrait};
use ty::BuiltinType;

mod abstractck;
mod clsdefck;
mod constdefck;
mod fctdefck;
mod flowck;
mod globaldef;
mod globaldefck;
mod implck;
mod impldefck;
mod nameck;
mod prelude;
mod returnck;
pub mod specialize;
mod structdefck;
mod superck;
mod traitdefck;
mod typeck;

macro_rules! return_on_error {
    ($ctxt: ident) => {{
        if $ctxt.diag.lock().has_errors() {
            return;
        }
    }};
}

pub fn check<'ast>(ctxt: &mut SemContext<'ast>) {
    let mut map_cls_defs = NodeMap::new(); // get ClassId from ast node
    let mut map_struct_defs = NodeMap::new(); // get StructId from ast node
    let mut map_trait_defs = NodeMap::new(); // get TraitId from ast node
    let mut map_impl_defs = NodeMap::new(); // get ImplId from ast node
    let mut map_global_defs = NodeMap::new(); // get GlobalId from ast node
    let mut map_const_defs = NodeMap::new(); // get ConstId from ast node

    // add user defined fcts and classes to ctxt
    // this check does not look into fct or class bodies
    globaldef::check(
        ctxt,
        &mut map_cls_defs,
        &mut map_struct_defs,
        &mut map_trait_defs,
        &mut map_impl_defs,
        &mut map_global_defs,
        &mut map_const_defs,
    );
    return_on_error!(ctxt);

    // define internal classes
    prelude::internal_classes(ctxt);

    // checks class/struct/trait definitions/bodies
    clsdefck::check(ctxt, &map_cls_defs);
    structdefck::check(ctxt, &map_struct_defs);
    traitdefck::check(ctxt, &map_trait_defs);
    impldefck::check(ctxt, &map_impl_defs);
    globaldefck::check(ctxt, &map_global_defs);
    constdefck::check(ctxt, &map_const_defs);
    return_on_error!(ctxt);

    // check names/identifiers of local variables
    // and their usage (variable def/use, function calls) in function bodies
    nameck::check(ctxt);
    return_on_error!(ctxt);

    // check type definitions of params,
    // return types and local variables in functions
    fctdefck::check(ctxt);
    return_on_error!(ctxt);

    superck::check_override(ctxt);
    return_on_error!(ctxt);

    // check impl methods against trait definition
    implck::check(ctxt);
    return_on_error!(ctxt);

    // define internal functions
    prelude::internal_functions(ctxt);

    // check types of expressions in functions
    typeck::check(ctxt);
    return_on_error!(ctxt);

    // are break and continue used in the right places?
    flowck::check(ctxt);

    // checks if function has a return value
    returnck::check(ctxt);

    // add size of super classes to field offsets
    superck::check(ctxt);
    return_on_error!(ctxt);

    abstractck::check(ctxt);

    // check for internal functions or classes
    internalck(ctxt);
    return_on_error!(ctxt);

    // initialize addresses for global variables
    init_global_addresses(ctxt);
}

fn internalck<'ast>(ctxt: &SemContext<'ast>) {
    for fct in ctxt.fcts.iter() {
        let fct = fct.read();

        if fct.in_class() {
            continue;
        }

        if fct.internal && !fct.internal_resolved {
            ctxt.diag.lock().report(fct.pos, Msg::UnresolvedInternal);
        }

        if fct.kind.is_definition() && !fct.in_trait() {
            ctxt.diag.lock().report(fct.pos, Msg::MissingFctBody);
        }
    }

    for cls in ctxt.classes.iter() {
        let cls = cls.read();

        if cls.internal && !cls.internal_resolved {
            ctxt.diag.lock().report(cls.pos, Msg::UnresolvedInternal);
        }

        for method in &cls.methods {
            let method = ctxt.fcts.idx(*method);
            let method = method.read();

            if method.internal && !method.internal_resolved {
                ctxt.diag.lock().report(method.pos, Msg::UnresolvedInternal);
            }

            if method.kind.is_definition() && !method.is_abstract {
                ctxt.diag.lock().report(method.pos, Msg::MissingFctBody);
            }
        }
    }
}

fn init_global_addresses<'ast>(ctxt: &SemContext<'ast>) {
    let globals = ctxt.globals.lock();
    let mut size = 0;
    let mut offsets = Vec::with_capacity(globals.len());

    for glob in globals.iter() {
        let glob = glob.lock();

        let ty_size = glob.ty.size(ctxt);
        let ty_align = glob.ty.align(ctxt);

        let offset = mem::align_i32(size, ty_align);
        offsets.push(offset);
        size = offset + ty_size;
    }

    let ptr = ctxt.gc.alloc_perm(size as usize);

    for (ind, glob) in globals.iter().enumerate() {
        let mut glob = glob.lock();
        let offset = offsets[ind];

        glob.address_value = ptr.offset(offset as usize);
    }
}

pub fn read_type<'ast>(ctxt: &SemContext<'ast>, t: &'ast Type) -> Option<BuiltinType> {
    match *t {
        TypeSelf(_) => {
            return Some(BuiltinType::This);
        }

        TypeBasic(ref basic) => {
            let sym = ctxt.sym.lock().get(basic.name);
            if let Some(sym) = sym {
                match sym {
                    SymClass(cls_id) => {
                        let ty = if basic.params.len() > 0 {
                            let mut type_params = Vec::new();

                            for param in &basic.params {
                                let param = read_type(ctxt, param);

                                if let Some(param) = param {
                                    type_params.push(param);
                                } else {
                                    return None;
                                }
                            }

                            let cls = ctxt.classes.idx(cls_id);
                            let cls = cls.read();

                            if cls.type_params.len() != type_params.len() {
                                let msg = Msg::WrongNumberTypeParams(
                                    cls.type_params.len(),
                                    type_params.len(),
                                );
                                ctxt.diag.lock().report(basic.pos, msg);
                                return None;
                            }

                            for (tp, ty) in cls.type_params.iter().zip(type_params.iter()) {
                                if let Some(cls_id) = tp.class_bound {
                                    let cls = ctxt.cls(cls_id);

                                    if !ty.subclass_from(ctxt, cls) {
                                        let name = ty.name(ctxt);
                                        let cls = cls.name(ctxt);

                                        let msg = Msg::ClassBoundNotSatisfied(name, cls);
                                        ctxt.diag.lock().report(basic.pos, msg);
                                    }
                                }

                                let cls_id = if let Some(cls_id) = ty.cls_id(ctxt) {
                                    cls_id
                                } else {
                                    continue;
                                };

                                let cls = ctxt.classes.idx(cls_id);
                                let cls = cls.read();

                                for &trait_bound in &tp.trait_bounds {
                                    if !cls.traits.contains(&trait_bound) {
                                        let bound = ctxt.traits[trait_bound].read();
                                        let name = ty.name(ctxt);
                                        let trait_name = ctxt.interner.str(bound.name).to_string();
                                        let msg = Msg::TraitBoundNotSatisfied(name, trait_name);
                                        ctxt.diag.lock().report(bound.pos, msg);
                                    }
                                }
                            }

                            let list_id = ctxt.lists.lock().insert(type_params.into());
                            BuiltinType::Class(cls.id, list_id)
                        } else {
                            let cls = ctxt.classes.idx(cls_id);
                            let cls = cls.read();

                            cls.ty
                        };

                        return Some(ty);
                    }

                    SymTrait(trait_id) => {
                        if basic.params.len() > 0 {
                            let msg = Msg::NoTypeParamsExpected;
                            ctxt.diag.lock().report(basic.pos, msg);
                        }

                        return Some(BuiltinType::Trait(trait_id));
                    }

                    SymStruct(struct_id) => {
                        if basic.params.len() > 0 {
                            let msg = Msg::NoTypeParamsExpected;
                            ctxt.diag.lock().report(basic.pos, msg);
                        }

                        let list_id = ctxt.lists.lock().insert(TypeParams::empty());
                        return Some(BuiltinType::Struct(struct_id, list_id));
                    }

                    SymClassTypeParam(cls_id, type_param_id) => {
                        if basic.params.len() > 0 {
                            let msg = Msg::NoTypeParamsExpected;
                            ctxt.diag.lock().report(basic.pos, msg);
                        }

                        return Some(BuiltinType::ClassTypeParam(cls_id, type_param_id));
                    }

                    SymFctTypeParam(fct_id, type_param_id) => {
                        if basic.params.len() > 0 {
                            let msg = Msg::NoTypeParamsExpected;
                            ctxt.diag.lock().report(basic.pos, msg);
                        }

                        return Some(BuiltinType::FctTypeParam(fct_id, type_param_id));
                    }

                    _ => {
                        let name = ctxt.interner.str(basic.name).to_string();
                        let msg = Msg::ExpectedType(name);
                        ctxt.diag.lock().report(basic.pos, msg);
                    }
                }
            } else {
                let name = ctxt.interner.str(basic.name).to_string();
                let msg = Msg::UnknownType(name);
                ctxt.diag.lock().report(basic.pos, msg);
            }
        }

        TypeTuple(ref tuple) if tuple.subtypes.len() == 0 => {
            return Some(BuiltinType::Unit);
        }

        TypeLambda(ref lambda) => {
            let mut params = vec![];

            for param in &lambda.params {
                if let Some(p) = read_type(ctxt, param) {
                    params.push(p);
                } else {
                    return None;
                }
            }

            let ret = if let Some(ret) = read_type(ctxt, &lambda.ret) {
                ret
            } else {
                return None;
            };

            let ty = ctxt.lambda_types.lock().insert(params, ret);
            let ty = BuiltinType::Lambda(ty);

            return Some(ty);
        }

        _ => ctxt.diag.lock().report_unimplemented(t.pos()),
    }

    None
}

pub fn always_returns(s: &Stmt) -> bool {
    match returnck::returns_value(s) {
        Ok(_) => true,
        Err(_) => false,
    }
}

#[cfg(test)]
mod tests {
    use ctxt::SemContext;
    use dora_parser::error::msg::Msg;
    use dora_parser::lexer::position::Position;
    use test;

    pub fn ok(code: &'static str) {
        test::parse_with_errors(code, |ctxt| {
            let diag = ctxt.diag.lock();
            let errors = diag.errors();

            println!("errors = {:?}", errors);

            for e in errors {
                println!("{}", e.message());
            }

            assert!(!diag.has_errors());
        });
    }

    pub fn ok_with_test<F, R>(code: &'static str, f: F) -> R
    where
        F: FnOnce(&SemContext) -> R,
    {
        test::parse_with_errors(code, |ctxt| {
            let diag = ctxt.diag.lock();
            let errors = diag.errors();

            println!("errors = {:?}", errors);

            for e in errors {
                println!("{}", e.message());
            }

            assert!(!diag.has_errors());

            f(ctxt)
        })
    }

    pub fn err(code: &'static str, pos: Position, msg: Msg) {
        test::parse_with_errors(code, |ctxt| {
            let diag = ctxt.diag.lock();
            let errors = diag.errors();

            println!("errors = {:?}", errors);

            assert_eq!(1, errors.len());
            assert_eq!(pos, errors[0].pos);
            assert_eq!(msg, errors[0].msg);
        });
    }

    pub fn errors(code: &'static str, vec: &[(Position, Msg)]) {
        test::parse_with_errors(code, |ctxt| {
            let diag = ctxt.diag.lock();
            let errors = diag.errors();

            println!("errors = {:?}", errors);
            assert_eq!(vec.len(), errors.len());

            for (ind, error) in errors.iter().enumerate() {
                assert_eq!(vec[ind].0, error.pos);
                assert_eq!(vec[ind].1, error.msg);
            }
        });
    }

    pub fn pos(line: u32, col: u32) -> Position {
        Position::new(line, col)
    }
}
<|endoftext|>


<commit_before>extern crate mysqlclient_sys as ffi;

mod iterator;

use std::os::{raw as libc};
use std::ffi::CStr;

use mysql::MysqlType;
use result::QueryResult;
use self::iterator::StatementIterator;
use super::bind::Binds;
use super::result::RawResult;

pub struct Statement {
    stmt: *mut ffi::MYSQL_STMT,
    input_binds: Option<Binds>,
}

impl Statement {
    pub fn new(stmt: *mut ffi::MYSQL_STMT) -> Self {
        Statement {
            stmt: stmt,
            input_binds: None,
        }
    }

    pub fn prepare(&self, query: &str) -> QueryResult<()> {
        unsafe {
            ffi::mysql_stmt_prepare(
                self.stmt,
                query.as_ptr() as *const libc::c_char,
                query.len() as libc::c_ulong,
            );
        }
        self.did_an_error_occur()
    }

    pub fn bind(&mut self, binds: Vec<(MysqlType, Option<Vec<u8>>)>) -> QueryResult<()> {
        let mut input_binds = Binds::from_input_data(binds);
        input_binds.with_mysql_binds(|bind_ptr| {
            // This relies on the invariant that the current value of `self.input_binds`
            // will not change without this function being called
            unsafe { ffi::mysql_stmt_bind_param(self.stmt, bind_ptr); }
        });
        self.input_binds = Some(input_binds);
        self.did_an_error_occur()
    }

    pub fn execute(&self) -> QueryResult<()> {
        unsafe { ffi::mysql_stmt_execute(self.stmt); }
        self.did_an_error_occur()
    }

    pub fn affected_rows(&self) -> usize {
        let affected_rows = unsafe { ffi::mysql_stmt_affected_rows(self.stmt) };
        affected_rows as usize
    }

    pub fn results(&mut self) -> QueryResult<StatementIterator> {
        StatementIterator::new(self)
    }

    fn result_metadata(&self) -> QueryResult<Option<RawResult>> {
        let result = unsafe {
            let result_ptr = ffi::mysql_stmt_result_metadata(self.stmt);
            RawResult::from_raw(result_ptr)
        };
        self.did_an_error_occur()?;
        Ok(result)
    }

    fn last_error_message(&self) -> String {
        unsafe { CStr::from_ptr(ffi::mysql_stmt_error(self.stmt)) }
            .to_string_lossy()
            .into_owned()
    }

    /// If the pointers referenced by the `MYSQL_BIND` structures are invalidated,
    /// you must call this function again before calling `mysql_stmt_fetch`.
    pub unsafe fn bind_result(&self, binds: *mut ffi::MYSQL_BIND) -> QueryResult<()> {
        ffi::mysql_stmt_bind_result(self.stmt, binds);
        self.did_an_error_occur()
    }

    pub unsafe fn fetch_column(&self, bind: &mut ffi::MYSQL_BIND, idx: usize, offset: usize)
        -> QueryResult<()>
    {
        ffi::mysql_stmt_fetch_column(
            self.stmt,
            bind,
            idx as libc::c_uint,
            offset as libc::c_ulong,
        );
        self.did_an_error_occur()
    }

    fn did_an_error_occur(&self) -> QueryResult<()> {
        use result::DatabaseErrorKind;
        use result::Error::DatabaseError;

        let error_message = self.last_error_message();
        if error_message.is_empty() {
            Ok(())
        } else {
            Err(DatabaseError(
                DatabaseErrorKind::__Unknown,
                Box::new(error_message),
            ))
        }
    }
}

impl Drop for Statement {
    fn drop(&mut self) {
        let drop_result = unsafe { ffi::mysql_stmt_close(self.stmt) };
        // FIXME: Remove this before we ship this feature. We don't really care
        // about any of the error cases that can occur, but I suspect we'll need
        // to stick an `Rc<RawConnection>` on this struct to ensure the right
        // drop order once prepared statement caching is added. This is mostly
        // here so I don't forget.
        assert_eq!(0, drop_result, "@sgrif forgot to delete this assertion. Please open a github issue");
    }
}
<commit_msg>Detect unique constraint violations for MySQL<commit_after>extern crate mysqlclient_sys as ffi;

mod iterator;

use std::os::{raw as libc};
use std::ffi::CStr;

use mysql::MysqlType;
use result::{QueryResult, DatabaseErrorKind};
use self::iterator::StatementIterator;
use super::bind::Binds;
use super::result::RawResult;

pub struct Statement {
    stmt: *mut ffi::MYSQL_STMT,
    input_binds: Option<Binds>,
}

impl Statement {
    pub fn new(stmt: *mut ffi::MYSQL_STMT) -> Self {
        Statement {
            stmt: stmt,
            input_binds: None,
        }
    }

    pub fn prepare(&self, query: &str) -> QueryResult<()> {
        unsafe {
            ffi::mysql_stmt_prepare(
                self.stmt,
                query.as_ptr() as *const libc::c_char,
                query.len() as libc::c_ulong,
            );
        }
        self.did_an_error_occur()
    }

    pub fn bind(&mut self, binds: Vec<(MysqlType, Option<Vec<u8>>)>) -> QueryResult<()> {
        let mut input_binds = Binds::from_input_data(binds);
        input_binds.with_mysql_binds(|bind_ptr| {
            // This relies on the invariant that the current value of `self.input_binds`
            // will not change without this function being called
            unsafe { ffi::mysql_stmt_bind_param(self.stmt, bind_ptr); }
        });
        self.input_binds = Some(input_binds);
        self.did_an_error_occur()
    }

    pub fn execute(&self) -> QueryResult<()> {
        unsafe { ffi::mysql_stmt_execute(self.stmt); }
        self.did_an_error_occur()
    }

    pub fn affected_rows(&self) -> usize {
        let affected_rows = unsafe { ffi::mysql_stmt_affected_rows(self.stmt) };
        affected_rows as usize
    }

    pub fn results(&mut self) -> QueryResult<StatementIterator> {
        StatementIterator::new(self)
    }

    fn result_metadata(&self) -> QueryResult<Option<RawResult>> {
        let result = unsafe {
            let result_ptr = ffi::mysql_stmt_result_metadata(self.stmt);
            RawResult::from_raw(result_ptr)
        };
        self.did_an_error_occur()?;
        Ok(result)
    }

    fn last_error_message(&self) -> String {
        unsafe { CStr::from_ptr(ffi::mysql_stmt_error(self.stmt)) }
            .to_string_lossy()
            .into_owned()
    }

    /// If the pointers referenced by the `MYSQL_BIND` structures are invalidated,
    /// you must call this function again before calling `mysql_stmt_fetch`.
    pub unsafe fn bind_result(&self, binds: *mut ffi::MYSQL_BIND) -> QueryResult<()> {
        ffi::mysql_stmt_bind_result(self.stmt, binds);
        self.did_an_error_occur()
    }

    pub unsafe fn fetch_column(&self, bind: &mut ffi::MYSQL_BIND, idx: usize, offset: usize)
        -> QueryResult<()>
    {
        ffi::mysql_stmt_fetch_column(
            self.stmt,
            bind,
            idx as libc::c_uint,
            offset as libc::c_ulong,
        );
        self.did_an_error_occur()
    }

    fn did_an_error_occur(&self) -> QueryResult<()> {
        use result::Error::DatabaseError;

        let error_message = self.last_error_message();
        if error_message.is_empty() {
            Ok(())
        } else {
            Err(DatabaseError(
                self.last_error_type(),
                Box::new(error_message),
            ))
        }
    }

    fn last_error_type(&self) -> DatabaseErrorKind {
        let last_error_number = unsafe  { ffi::mysql_stmt_errno(self.stmt) };
        // These values are not exposed by the C API, but are documented
        // at https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
        // and are from the ANSI SQLSTATE standard
        match last_error_number {
            1062 | 1586 | 1859 => DatabaseErrorKind::UniqueViolation,
            _ => DatabaseErrorKind::__Unknown,
        }
    }
}

impl Drop for Statement {
    fn drop(&mut self) {
        let drop_result = unsafe { ffi::mysql_stmt_close(self.stmt) };
        // FIXME: Remove this before we ship this feature. We don't really care
        // about any of the error cases that can occur, but I suspect we'll need
        // to stick an `Rc<RawConnection>` on this struct to ensure the right
        // drop order once prepared statement caching is added. This is mostly
        // here so I don't forget.
        assert_eq!(0, drop_result, "@sgrif forgot to delete this assertion. Please open a github issue");
    }
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: 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/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate bragi;
extern crate rustless;
extern crate iron;
extern crate iron_test;
use std::process::Command;

fn get_handler(url: String) -> rustless::Application {
    let api = bragi::api::ApiEndPoint{es_cnx_string: url}.root();
    rustless::Application::new(api)
}

pub fn bragi_tests(es_wrapper: ::ElasticSearchWrapper) {

    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    info!("Launching {}", bano2mimir);
    let status = Command::new(bano2mimir)
                     .args(&["--input=./tests/fixtures/sample-bano.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())])
                     .status()
                     .unwrap();
    assert!(status.success(), "`bano2mimir` failed {}", &status);
    es_wrapper.refresh();

    let handler = get_handler(format!("{}/munin", es_wrapper.host()));

    // Call status
    let resp = iron_test::request::get("http://localhost:3000/status",
                                iron::Headers::new(),
                                &handler).unwrap();
    let result_body = iron_test::response::extract_body_to_string(resp);

    assert_eq!(result_body, r#"{"version":"1.0.0","es":"http://localhost:9242/munin","status":"good"}"#);

    // Call autocomplete
    let resp = iron_test::request::get("http://localhost:3000/autocomplete?q=15 Rue Hector Malot, (Paris)",
                                iron::Headers::new(),
                                &handler).unwrap();
    let result_body = iron_test::response::extract_body_to_string(resp);
    let result = concat!(r#"{"Autocomplete":{"type":"FeatureCollection","#,
                         r#""geocoding":{"version":"0.1.0","query":""},"#,
                         r#""features":[{"type":"Feature","geometry":{"coordinates":"#,
                         r#"[2.3763789999999996,48.846495],"type":"Point"},"#,
                         r#""properties":{"geocoding":{"id":"addr:2.376379;48.846495","#,
                         r#""type":"house","label":"15 Rue Hector Malot, (Paris)","#,
                         r#""name":"15 Rue Hector Malot, (Paris)","housenumber":"15","#,
                         r#""street":"Rue Hector Malot, (Paris)","postcode":null,"#,
                         r#""city":null,"administrative_regions":[]}}}]}}"#);
    assert_eq!(result_body, result);
}
<commit_msg>fix bragi test<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: 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/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate bragi;
extern crate rustless;
extern crate iron;
extern crate iron_test;
use std::process::Command;

fn get_handler(url: String) -> rustless::Application {
    let api = bragi::api::ApiEndPoint{es_cnx_string: url}.root();
    rustless::Application::new(api)
}

pub fn bragi_tests(es_wrapper: ::ElasticSearchWrapper) {

    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    info!("Launching {}", bano2mimir);
    let status = Command::new(bano2mimir)
                     .args(&["--input=./tests/fixtures/sample-bano.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())])
                     .status()
                     .unwrap();
    assert!(status.success(), "`bano2mimir` failed {}", &status);
    es_wrapper.refresh();

    let handler = get_handler(format!("{}/munin", es_wrapper.host()));

    // Call status
    let resp = iron_test::request::get("http://localhost:3000/status",
                                iron::Headers::new(),
                                &handler).unwrap();
    let result_body = iron_test::response::extract_body_to_string(resp);

    assert_eq!(result_body, r#"{"version":"1.0.0","es":"http://localhost:9242/munin","status":"good"}"#);

    // Call autocomplete
    let resp = iron_test::request::get("http://localhost:3000/autocomplete?q=15 Rue Hector Malot, (Paris)",
                                iron::Headers::new(),
                                &handler).unwrap();
    let result_body = iron_test::response::extract_body_to_string(resp);
    let result = concat!(r#"{"type":"FeatureCollection","#,
                         r#""geocoding":{"version":"0.1.0","query":""},"#,
                         r#""features":[{"type":"Feature","geometry":{"coordinates":"#,
                         r#"[2.3763789999999996,48.846495],"type":"Point"},"#,
                         r#""properties":{"geocoding":{"id":"addr:2.376379;48.846495","#,
                         r#""type":"house","label":"15 Rue Hector Malot, (Paris)","#,
                         r#""name":"15 Rue Hector Malot, (Paris)","housenumber":"15","#,
                         r#""street":"Rue Hector Malot, (Paris)","postcode":null,"#,
                         r#""city":null,"administrative_regions":[]}}}]}"#);
    assert_eq!(result_body, result);
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "nightly", feature(test))]

#[cfg(feature = "nightly")]
extern crate test;

#[macro_use]
extern crate stdweb;

#[macro_use]
extern crate lazy_static;

use std::time::Duration;

use stdweb::web::document;
use stdweb::web::event::ClickEvent;
use stdweb::unstable::TryInto;
use stdweb::traits::*;

lazy_static! {
    static ref IS_NODEJS: bool = {
        let is_nodejs: bool = js!(
            return typeof window === "undefined" && typeof process === "object";
        ).try_into().unwrap();

        return is_nodejs;
    };
}

macro_rules! println {
    ($($token:tt)*) => {
        let string = format!( $($token)+ );
        if !*IS_NODEJS {
            let console = document().query_selector( "#console" ).unwrap().unwrap();
            console.append_child( &document().create_text_node( &string ) );
            console.append_child( &document().create_text_node( "\n" ) );
        }
        js! {
            console.log( @{string} );
        }
    };
}

mod utils;
use utils::Stopwatch;

struct Timer {
    timestamp: f64
}

impl Stopwatch for Timer {
    fn now() -> Self {
        if !*IS_NODEJS {
            let timestamp: f64 = js!( return performance.now(); ).try_into().unwrap();
            Timer {
                timestamp: timestamp / 1000_f64
            }
        } else {
            let timestamp: f64 = js!(
                var t = process.hrtime();
                return t[ 0 ] + t[ 1 ] / 1000000000;
            ).try_into().unwrap();

            Timer { timestamp }
        }
    }

    fn elapsed( &self ) -> Duration {
        let now = Timer::now();
        let difference = now.timestamp - self.timestamp;
        let secs = difference.trunc();
        Duration::new( secs as u64, ((difference - secs) * 1_000_000_000.0) as u32 )
    }
}

struct Bench {
    name: String,
    callback: Box< Fn( &Bench ) + 'static >
}

struct Bencher {
    benches: Vec< Bench >
}

impl Bencher {
    fn new() -> Self {
        Bencher { benches: Vec::new() }
    }

    fn add< R, F: 'static + Fn() -> R >( &mut self, name: &str, callback: F ) {
        self.benches.push( Bench {
            name: name.to_owned(),
            callback: Box::new( move |bench| {
                println!( "Benchmarking '{}'...", bench.name );
                let result = utils::benchmark::< Timer, R, F >( &callback );
                println!( "    {}", result );
            })
        });
    }

    fn run( &self ) {
        for bench in &self.benches {
            (bench.callback)( bench );
        }
    }
}

fn main() {
    if !*IS_NODEJS {
        let body = document().query_selector( "body" ).unwrap().unwrap();
        let start = document().create_element( "button" ).unwrap();
        start.set_text_content( "Start" );
        body.append_child( &start );
        let pre = document().create_element( "pre" ).unwrap();
        pre.set_attribute( "id", "console" ).unwrap();
        body.append_child( &pre );
    }

    if cfg!( nightly ) {
        js! {
            console.log( "Compiled with the `nightly` feature!" );
        }
    }

    let mut bencher = Bencher::new();
    bencher.add( "call-into-js", || js!( @(no_return) ) );
    bencher.add( "call-into-js-returning-undefined", || js!() );
    bencher.add( "call-into-js-with-string", || js!( @(no_return) var test = @{"Hello world!"}; ) );

    if !*IS_NODEJS {
        let body = document().query_selector( "body" ).unwrap().unwrap();
        body.add_event_listener( move |_: ClickEvent| {
            bencher.run();
        });
    } else {
        bencher.run();
    }
}
<commit_msg>Refactor the benchmarks slightly<commit_after>#![cfg_attr(feature = "nightly", feature(test))]

#[cfg(feature = "nightly")]
extern crate test;

#[macro_use]
extern crate stdweb;

#[macro_use]
extern crate lazy_static;

use std::time::Duration;

use stdweb::web::document;
use stdweb::web::event::ClickEvent;
use stdweb::unstable::TryInto;
use stdweb::traits::*;

lazy_static! {
    static ref IS_NODEJS: bool = {
        let is_nodejs: bool = js!(
            return typeof window === "undefined" && typeof process === "object";
        ).try_into().unwrap();

        return is_nodejs;
    };
}

macro_rules! println {
    ($($token:tt)*) => {
        let string = format!( $($token)+ );
        if !*IS_NODEJS {
            let console = document().query_selector( "#console" ).unwrap().unwrap();
            console.append_child( &document().create_text_node( &string ) );
            console.append_child( &document().create_text_node( "\n" ) );
        }
        js! {
            console.log( @{string} );
        }
    };
}

mod utils;
use utils::Stopwatch;

struct Timer {
    timestamp: f64
}

impl Stopwatch for Timer {
    fn now() -> Self {
        if !*IS_NODEJS {
            let timestamp: f64 = js!( return performance.now(); ).try_into().unwrap();
            Timer {
                timestamp: timestamp / 1000_f64
            }
        } else {
            let timestamp: f64 = js!(
                var t = process.hrtime();
                return t[ 0 ] + t[ 1 ] / 1000000000;
            ).try_into().unwrap();

            Timer { timestamp }
        }
    }

    fn elapsed( &self ) -> Duration {
        let now = Timer::now();
        let difference = now.timestamp - self.timestamp;
        let secs = difference.trunc();
        Duration::new( secs as u64, ((difference - secs) * 1_000_000_000.0) as u32 )
    }
}

struct Bench {
    name: String,
    callback: Box< Fn( &Bench ) + 'static >
}

struct Bencher {
    benches: Vec< Bench >
}

impl Bencher {
    fn new() -> Self {
        Bencher { benches: Vec::new() }
    }

    fn add< R, F: 'static + Fn() -> R >( &mut self, name: &str, callback: F ) {
        self.benches.push( Bench {
            name: name.to_owned(),
            callback: Box::new( move |bench| {
                println!( "Benchmarking '{}'...", bench.name );
                let result = utils::benchmark::< Timer, R, F >( &callback );
                println!( "    {}", result );
            })
        });
    }

    fn run( &self ) {
        for bench in &self.benches {
            (bench.callback)( bench );
        }
    }
}

fn run_benchmarks< F: FnOnce( &mut Bencher ) >( callback: F ) {
    if !*IS_NODEJS {
        let body = document().query_selector( "body" ).unwrap().unwrap();
        let start = document().create_element( "button" ).unwrap();
        start.set_text_content( "Start" );
        body.append_child( &start );
        let pre = document().create_element( "pre" ).unwrap();
        pre.set_attribute( "id", "console" ).unwrap();
        body.append_child( &pre );
    }

    if cfg!( nightly ) {
        js! {
            console.log( "Compiled with the `nightly` feature!" );
        }
    }

    let mut bencher = Bencher::new();
    callback( &mut bencher );

    if !*IS_NODEJS {
        let body = document().query_selector( "body" ).unwrap().unwrap();
        body.add_event_listener( move |_: ClickEvent| {
            bencher.run();
        });
    } else {
        bencher.run();
    }
}

fn main() {
    run_benchmarks( |bencher| {
        bencher.add( "call-into-js", || js!( @(no_return) ) );
        bencher.add( "call-into-js-returning-undefined", || js!() );
        bencher.add( "call-into-js-with-string", || js!( @(no_return) var test = @{"Hello world!"}; ) );
    });
}
<|endoftext|>


<commit_before>use std::option::Option;
use std::iter::Iterator;
use std::collections::HashMap;

pub struct Scanner<'a> {
    src: &'a str,
    vertical_white_spaces: Vec<char>,
    single_special_chars: Vec<char>,
    double_special_chars: HashMap<char, char>,
    multi_special_chars: Vec<char>,
}

impl<'a> Scanner<'a> {

    pub fn new(src: &'a str) -> Scanner {
        let mut double_special_chars = HashMap::with_capacity(6);
        double_special_chars.insert('=', '=');
        double_special_chars.insert('/', '*');
        double_special_chars.insert('*', '/');
        double_special_chars.insert('-', '-');
        double_special_chars.insert('>', '=');
        double_special_chars.insert('!', '=');
        Scanner {
                src: src,
                vertical_white_spaces: vec![' ', '\t'],
                single_special_chars: vec!['(', ')', '\'', ';', '.', '+'],
                double_special_chars: double_special_chars,
                multi_special_chars: vec!['*', '-', '/'],
        }
    }

    fn first_char(&self) -> char {
        self.nth_char(0).unwrap()
    }

    fn nth_char(&self, index: usize) -> Option<char> {
        self.src.chars().nth(index)
    }

    fn check_double_spec_chars(&self, first_char: &char, next_char: &char) -> bool {
        match self.double_special_chars.get(first_char) {
            Some(c) => *c == *next_char,
            None => false
        }
    }

    fn next_lexem(&mut self) -> Option<&'a str> {
        let first_char = self.first_char();
        let option_nth_char = self.nth_char(1);
        let index = if first_char.is_alphabetic() || first_char.is_digit(10) {
            self.src.chars().take_while(
                |c| !self.vertical_white_spaces.contains(c)
                    && *c != '\n'
                    && !self.single_special_chars.contains(c)
                    && !self.multi_special_chars.contains(c)
                ).count()
        }
        else if self.vertical_white_spaces.contains(&first_char) {
            self.src.chars().take_while(|c| self.vertical_white_spaces.contains(c)).count()
        }
        else if self.single_special_chars.contains(&first_char) {
            1
        }
        else if self.double_special_chars.contains_key(&first_char) && option_nth_char.is_some() {
            if self.check_double_spec_chars(&first_char, &(option_nth_char.unwrap())) {
                2
            }
            else {
                1
            }
        }
        else if first_char == '<' {
            if  option_nth_char.unwrap() == '>' || option_nth_char.unwrap() == '=' {
                2
            }
            else {
                1
            }
        }
        else {
            self.src.chars().take_while(|c| *c == '\n').count()
        };
        let result = &(self.src)[0..index];
        let src_len = self.src.len();
        self.src = &(self.src)[index..src_len];
        Option::Some(result)
    }
}

impl<'a> Iterator for Scanner<'a> {

    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        if self.src.is_empty() {
            return Option::None
        }
        self.next_lexem()
    }
}
<commit_msg>lexer re-factoring<commit_after>use std::option::Option;
use std::iter::Iterator;
use std::collections::HashMap;

pub struct Scanner<'a> {
    src: &'a str,
    horizontal_white_spaces: Vec<char>,
    single_special_chars: Vec<char>,
    double_special_chars: HashMap<char, Vec<char>>,
}

impl<'a> Scanner<'a> {

    pub fn new(src: &'a str) -> Scanner {
        let mut double_special_chars = HashMap::with_capacity(7);
        double_special_chars.insert('=', vec!['=']);
        double_special_chars.insert('/', vec!['*']);
        double_special_chars.insert('*', vec!['/']);
        double_special_chars.insert('-', vec!['-']);
        double_special_chars.insert('>', vec!['=']);
        double_special_chars.insert('!', vec!['=']);
        double_special_chars.insert('<', vec!['=', '>']);
        Scanner {
                src: src,
                horizontal_white_spaces: vec![' ', '\t'],
                single_special_chars: vec!['(', ')', '\'', ';', '.', '+'],
                double_special_chars: double_special_chars,
        }
    }

    fn first_char(&self) -> char {
        self.nth_char(0).unwrap()
    }

    fn nth_char(&self, index: usize) -> Option<char> {
        self.src.chars().nth(index)
    }

    fn check_double_spec_chars(&self, first_char: &char, next_char: &char) -> bool {
        match self.double_special_chars.get(first_char) {
            Some(chars) => (*chars).contains(next_char),
            None => false
        }
    }

    fn find_delimeter_index(&self, first_char: &char, option_nth_char: &Option<char>) -> usize {
        if option_nth_char.is_none() {
            1
        }
        else if first_char.is_alphabetic() || first_char.is_digit(10) {
            self.src.chars().take_while(
                |c| !self.horizontal_white_spaces.contains(c)
                    && *c != '\n'
                    && !self.single_special_chars.contains(c)
                    && !self.double_special_chars.contains_key(c)
                ).count()
        }
        else if self.vertical_white_spaces.contains(&first_char) {
            self.src.chars().take_while(|c| self.horizontal_white_spaces.contains(c)).count()
        }
        else if self.single_special_chars.contains(&first_char) {
            1
        }
        else if self.double_special_chars.contains_key(&first_char) {
            if self.check_double_spec_chars(&first_char, &(option_nth_char.unwrap())) {
                2
            }
            else {
                1
            }
        }
        else {
            self.src.chars().take_while(|c| *c == '\n').count()
        }
    }

    fn get_lexem(&self, index: usize) -> &'a str {
        &(self.src)[0..index]
    }

    fn resize_source(&mut self, index: usize) {
        let src_len = self.src.len();
        self.src = &(self.src)[index..src_len];
    }

    fn next_lexem(&mut self) -> Option<&'a str> {
        let index = self.find_delimeter_index(&self.first_char(), &self.nth_char(1));
        let lexem = self.get_lexem(index);
        self.resize_source(index);
        Option::Some(lexem)
    }
}

impl<'a> Iterator for Scanner<'a> {

    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        if self.src.is_empty() {
            return Option::None
        }
        self.next_lexem()
    }
}
<|endoftext|>


<commit_before>extern crate flac;

fn run_metaflac(fname: &Path) -> String {
    use std::io::Command;

    // Run metaflac on the specified file and print all streaminfo data.
    let mut child = Command::new("metaflac")
                        .arg("--show-min-blocksize")
                        .arg("--show-max-blocksize")
                        .arg("--show-min-framesize")
                        .arg("--show-max-framesize")
                        .arg("--show-sample-rate")
                        .arg("--show-channels")
                        .arg("--show-bps")
                        .arg("--show-total-samples")
                        .arg("--show-md5sum")
                        .arg(fname.as_str().expect("unsupported filename"))
                        .spawn().ok().expect("failed to run metaflac");

    assert!(child.wait().unwrap().success());

    let output = match child.stdout {
        Some(ref mut stdout) => stdout.read_to_string().ok()
                                      .expect("failed to read metaflac stdout"),
        None => panic!("failed to open metaflac stdout")
    };

    output
}

fn print_hex(seq: &[u8]) -> String {
    let vec: Vec<String> = seq.iter().map(|x| format!("{:0>2x}", *x)).collect();
    vec.concat()
}

fn read_streaminfo(fname: &Path) -> String {
    use std::io::fs::File;
    use flac::FlacStream;

    let mut file = File::open(fname).unwrap();
    let stream = FlacStream::new(&mut file).unwrap();
    let streaminfo = stream.streaminfo();

    // Format the streaminfo in the same way that metaflac prints it.
    format!("{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n",
            streaminfo.min_block_size,
            streaminfo.max_block_size,
            streaminfo.min_frame_size.unwrap_or(0),
            streaminfo.max_frame_size.unwrap_or(0),
            streaminfo.sample_rate,
            streaminfo.n_channels,
            streaminfo.bits_per_sample,
            streaminfo.n_samples.unwrap_or(0),
            print_hex(&streaminfo.md5sum)) // TODO implement LowerHex for &[u8] and submit a PR.
}

fn compare_metaflac(fname: &Path) {
    let metaflac = run_metaflac(fname);
    let streaminfo = read_streaminfo(fname);
    let mut mf_lines = metaflac.lines_any();
    let mut si_lines = streaminfo.lines_any();
    while let (Some(mf), Some(si)) = (mf_lines.next(), si_lines.next()) {
        if mf != si {
            println!("metaflac\n--------\n{}", metaflac);
            println!("streaminfo\n----------\n{}", streaminfo);
            panic!("metaflac disagrees on parsed streaminfo");
        }
    };
}

#[test]
fn verify_streaminfo() {
    use std::io::fs::{readdir, PathExtensions};

    // Compare our streaminfo parsing with metaflac on all flac files in the
    // current directory.
    let dir = readdir(&Path::new(".")).ok().expect("failed to enumerate flac files");
    for path in dir.iter() {
        if path.is_file() && path.extension_str() == Some("flac") {
            print!("    comparing {} ...", path.as_str().expect("unsupported filename"));
            compare_metaflac(path);
            println!(" ok");
        }
    }
}
<commit_msg>use buffered reader for faster testing<commit_after>extern crate flac;

fn run_metaflac(fname: &Path) -> String {
    use std::io::Command;

    // Run metaflac on the specified file and print all streaminfo data.
    let mut child = Command::new("metaflac")
                        .arg("--show-min-blocksize")
                        .arg("--show-max-blocksize")
                        .arg("--show-min-framesize")
                        .arg("--show-max-framesize")
                        .arg("--show-sample-rate")
                        .arg("--show-channels")
                        .arg("--show-bps")
                        .arg("--show-total-samples")
                        .arg("--show-md5sum")
                        .arg(fname.as_str().expect("unsupported filename"))
                        .spawn().ok().expect("failed to run metaflac");

    assert!(child.wait().unwrap().success());

    let output = match child.stdout {
        Some(ref mut stdout) => stdout.read_to_string().ok()
                                      .expect("failed to read metaflac stdout"),
        None => panic!("failed to open metaflac stdout")
    };

    output
}

fn print_hex(seq: &[u8]) -> String {
    let vec: Vec<String> = seq.iter().map(|x| format!("{:0>2x}", *x)).collect();
    vec.concat()
}

fn read_streaminfo(fname: &Path) -> String {
    use std::io::fs::File;
    use std::io::BufferedReader;
    use flac::FlacStream;

    // Use a buffered reader, this speeds up the test by 120%.
    let file = File::open(fname).unwrap();
    let mut reader = BufferedReader::new(file);
    let stream = FlacStream::new(&mut reader).unwrap();
    let streaminfo = stream.streaminfo();

    // Format the streaminfo in the same way that metaflac prints it.
    format!("{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n",
            streaminfo.min_block_size,
            streaminfo.max_block_size,
            streaminfo.min_frame_size.unwrap_or(0),
            streaminfo.max_frame_size.unwrap_or(0),
            streaminfo.sample_rate,
            streaminfo.n_channels,
            streaminfo.bits_per_sample,
            streaminfo.n_samples.unwrap_or(0),
            print_hex(&streaminfo.md5sum)) // TODO implement LowerHex for &[u8] and submit a PR.
}

fn compare_metaflac(fname: &Path) {
    let metaflac = run_metaflac(fname);
    let streaminfo = read_streaminfo(fname);
    let mut mf_lines = metaflac.lines_any();
    let mut si_lines = streaminfo.lines_any();
    while let (Some(mf), Some(si)) = (mf_lines.next(), si_lines.next()) {
        if mf != si {
            println!("metaflac\n--------\n{}", metaflac);
            println!("streaminfo\n----------\n{}", streaminfo);
            panic!("metaflac disagrees on parsed streaminfo");
        }
    };
}

#[test]
fn verify_streaminfo() {
    use std::io::fs::{readdir, PathExtensions};

    // Compare our streaminfo parsing with metaflac on all flac files in the
    // current directory.
    let dir = readdir(&Path::new(".")).ok().expect("failed to enumerate flac files");
    for path in dir.iter() {
        if path.is_file() && path.extension_str() == Some("flac") {
            print!("    comparing {} ...", path.as_str().expect("unsupported filename"));
            compare_metaflac(path);
            println!(" ok");
        }
    }
}
<|endoftext|>


<commit_before>//! This module contains all the OpenGEX structures as specified. The module tries to stay as close
//! to the OpenGEX structures as possible.
//!
//! Some of the documentation might be subjected to copyright by Eric Lengyel. For more detailed
//! documentation, please go to http://opengex.org.

use std::collections::HashMap;

/// The Material structure contains information about a material. Material structures are
/// referenced by geometry nodes through MaterialRef structures belonging to GeometryNode
/// structures.
pub struct Material {
    /// Whether the material is two-sided.
    pub two_sided: bool,
    /// An optional name.
    pub name: Option<Name>,
    /// Any number of colors.
    pub color: HashMap<String, Color>,
    /// Any number of parameters.
    pub param: ParamMap,
    /// Any number of textures.
    pub texture: HashMap<String, Texture>,
}

/// A Color structure must contain an RGB or RGBA color value.
pub enum Color {
    /// An RGB color value.
    Rgb(f32, f32, f32),
    /// An RGBA color value.
    Rgba(f32, f32, f32, f32)
}

/// This is a map of different Param structures, for convenience.
pub type ParamMap = HashMap<String, f32>;

/// The Name structure holds the name of a node, morph target, material, or animation clip.
pub type Name = String;

/// The Texture structure holds information about a single texture map, and how it is accessed with
/// texture coordinates.
pub struct Texture {
    /// The index of the texture coordinate set associated with the texture.
    pub texcoord: u32,
    /// A substructure holding the file name of the texture.
    pub file_name: String,
    /// Any number of transformations that are applied to the texture coordinates of a mesh when
    /// they are used to fetch from the texture map.
    pub transformations: Vec<Transformation>,
    /// Any number of animation tracks that are applied to the texture coordinate transformations.
    pub animation: Vec<Animation>
}

/// Helper enum to contain all different kinds of Transformations.
pub enum Transformation {
    /// A Transform structure.
    pub Transform(Transform),
    /// A Translation structure.
    pub Translation(Translation),
    /// A Rotation structure.
    pub Rotation(Rotation),
    /// A Scale structure.
    pub Scale(Scale)
}

/// The Transform structure holds one or more 4 x 4 transformation matrices. In the cases that a
/// Transform structure is contained inside any type of node structure, a Texture structure, or a
/// Skin structure, it must contain a single matrix. In the case that a Transform structure is
/// contained inside a Skeleton structure, is must contain an array of matrices with one entry for
/// each bone referenced by the skeleton.
///
/// When contained inside a node structure, a Transform structure can be the target of a track
/// stored inside an Animation structure.
pub struct Transform([f32; 16]);

/// The Translation structure holds a translation transformation in one of several possible
/// variants.
///
/// There are different variants of this type of tranformation, one for each "kind".
///
/// When contained inside a node structure, a Translation structure can be the target of a track
/// stored inside an Animation structure.
pub enum Translation {
    /// The translation occurs along only the X axis.
    pub X(f32),
    /// The translation occurs along only the Y axis.
    pub Y(f32),
    /// The translation occurs along only the Z axis.
    pub Z(f32),
    /// The translation occurs along all three coordinate axes.
    pub Xyz(f32, f32, f32)
}

/// The Rotation structure represents a rotation along one of several axes.
///
/// There are different variants of this type of tranformation, one for each "kind".
///
/// When contained inside a node structure, a Rotation structure can be the target of a track
/// stored in an Animation structure.
pub enum Rotation {
    /// The rotation occurs about the X axis.
    pub X(f32),
    /// The rotation occurs about the Y axis.
    pub Y(f32),
    /// The rotation occurs about the Z axis.
    pub Z(f32),
    /// The rotation occurs about an arbitrary axis. The first entry of this structure is the angle
    /// of rotation. The remaining three entries are respectively the X, Y and Z components of the
    /// axis of rotation.
    pub Axis(f32, f32, f32, f32),
    /// The rotation is given by a quaternion. Please refer to the official OpenGEX documentation
    /// for more information.
    pub Quaternion(f32, f32, f32, f32)
}

/// The Scale structure represents a scale transformation in one of several possible variants.
///
/// There are different variants of this type of tranformation, one for each "kind".
///
/// When contained inside a node structure, a Scale structure can be the target of a strack stored
/// inside an Animation structure.
pub enum Scale {
    /// The scaling occurs along only the X axis.
    pub X(f32),
    /// The scaling occurs along only the Y axis.
    pub Y(f32),
    /// The scaling occurs along only the Z axis.
    pub Z(f32),
    /// The scaling occurs along all three coordinate axes.
    pub Xyz(f32, f32, f32)
}

/// The Animation structure contains animation data for a single node in a scene. Each animation
/// structure is directly contained inside a node structure or Texture structure. Each animation
/// structure contains the data needed to modify its sibling Transformation structures or sibling
/// MorphWeight structures over time.
///
/// More detailed information can be found in the official OpenGEX specification.
pub struct Animation {
    /// Specifies the animation clip index.
    pub clip: u32,
    /// Specifies when the animation begins. If the property is not specifies, the begin time for
    /// the animation is determined by the earliest time values present in the Track structures
    /// belonging to this Animation.
    pub begin: Opt<f32>,
    /// Specifies when the animation ends. Like with the begin property, if the property is not
    /// specified, the end time for the animation is determined by the latest time values present
    /// in the Track structures belonging to this Animation.
    pub end: Opt<f32>,
    /// One or more tracks that each hold animation keys for a single target.
    pub tracks: Vec<Track>,
}

/// Enum wrapping over all possible animation track targets.
pub enum TrackTarget {
    pub Transformation(Transformation),
    pub MorphWeight(MorphWeight)
}

/// The Track structure contains animation key data for a single Transformation or MorphWeight
/// structure.
pub struct Track {
    // TODO: Finish this structure
}
<commit_msg>TrackTarget now contains references instead of the structures themselves<commit_after>//! This module contains all the OpenGEX structures as specified. The module tries to stay as close
//! to the OpenGEX structures as possible.
//!
//! Some of the documentation might be subjected to copyright by Eric Lengyel. For more detailed
//! documentation, please go to http://opengex.org.

use std::collections::HashMap;
use std::rc::Rc;

/// The Material structure contains information about a material. Material structures are
/// referenced by geometry nodes through MaterialRef structures belonging to GeometryNode
/// structures.
pub struct Material {
    /// Whether the material is two-sided.
    pub two_sided: bool,
    /// An optional name.
    pub name: Option<Name>,
    /// Any number of colors.
    pub color: HashMap<String, Color>,
    /// Any number of parameters.
    pub param: ParamMap,
    /// Any number of textures.
    pub texture: HashMap<String, Texture>,
}

/// A Color structure must contain an RGB or RGBA color value.
pub enum Color {
    /// An RGB color value.
    Rgb(f32, f32, f32),
    /// An RGBA color value.
    Rgba(f32, f32, f32, f32)
}

/// This is a map of different Param structures, for convenience.
pub type ParamMap = HashMap<String, f32>;

/// The Name structure holds the name of a node, morph target, material, or animation clip.
pub type Name = String;

/// The Texture structure holds information about a single texture map, and how it is accessed with
/// texture coordinates.
pub struct Texture {
    /// The index of the texture coordinate set associated with the texture.
    pub texcoord: u32,
    /// A substructure holding the file name of the texture.
    pub file_name: String,
    /// Any number of transformations that are applied to the texture coordinates of a mesh when
    /// they are used to fetch from the texture map.
    pub transformations: Vec<Transformation>,
    /// Any number of animation tracks that are applied to the texture coordinate transformations.
    pub animation: Vec<Animation>
}

/// Helper enum to contain all different kinds of Transformations.
pub enum Transformation {
    /// A Transform structure.
    pub Transform(Transform),
    /// A Translation structure.
    pub Translation(Translation),
    /// A Rotation structure.
    pub Rotation(Rotation),
    /// A Scale structure.
    pub Scale(Scale)
}

/// The Transform structure holds one or more 4 x 4 transformation matrices. In the cases that a
/// Transform structure is contained inside any type of node structure, a Texture structure, or a
/// Skin structure, it must contain a single matrix. In the case that a Transform structure is
/// contained inside a Skeleton structure, is must contain an array of matrices with one entry for
/// each bone referenced by the skeleton.
///
/// When contained inside a node structure, a Transform structure can be the target of a track
/// stored inside an Animation structure.
pub struct Transform([f32; 16]);

/// The Translation structure holds a translation transformation in one of several possible
/// variants.
///
/// There are different variants of this type of tranformation, one for each "kind".
///
/// When contained inside a node structure, a Translation structure can be the target of a track
/// stored inside an Animation structure.
pub enum Translation {
    /// The translation occurs along only the X axis.
    pub X(f32),
    /// The translation occurs along only the Y axis.
    pub Y(f32),
    /// The translation occurs along only the Z axis.
    pub Z(f32),
    /// The translation occurs along all three coordinate axes.
    pub Xyz(f32, f32, f32)
}

/// The Rotation structure represents a rotation along one of several axes.
///
/// There are different variants of this type of tranformation, one for each "kind".
///
/// When contained inside a node structure, a Rotation structure can be the target of a track
/// stored in an Animation structure.
pub enum Rotation {
    /// The rotation occurs about the X axis.
    pub X(f32),
    /// The rotation occurs about the Y axis.
    pub Y(f32),
    /// The rotation occurs about the Z axis.
    pub Z(f32),
    /// The rotation occurs about an arbitrary axis. The first entry of this structure is the angle
    /// of rotation. The remaining three entries are respectively the X, Y and Z components of the
    /// axis of rotation.
    pub Axis(f32, f32, f32, f32),
    /// The rotation is given by a quaternion. Please refer to the official OpenGEX documentation
    /// for more information.
    pub Quaternion(f32, f32, f32, f32)
}

/// The Scale structure represents a scale transformation in one of several possible variants.
///
/// There are different variants of this type of tranformation, one for each "kind".
///
/// When contained inside a node structure, a Scale structure can be the target of a strack stored
/// inside an Animation structure.
pub enum Scale {
    /// The scaling occurs along only the X axis.
    pub X(f32),
    /// The scaling occurs along only the Y axis.
    pub Y(f32),
    /// The scaling occurs along only the Z axis.
    pub Z(f32),
    /// The scaling occurs along all three coordinate axes.
    pub Xyz(f32, f32, f32)
}

/// The Animation structure contains animation data for a single node in a scene. Each animation
/// structure is directly contained inside a node structure or Texture structure. Each animation
/// structure contains the data needed to modify its sibling Transformation structures or sibling
/// MorphWeight structures over time.
///
/// More detailed information can be found in the official OpenGEX specification.
pub struct Animation {
    /// Specifies the animation clip index.
    pub clip: u32,
    /// Specifies when the animation begins. If the property is not specifies, the begin time for
    /// the animation is determined by the earliest time values present in the Track structures
    /// belonging to this Animation.
    pub begin: Opt<f32>,
    /// Specifies when the animation ends. Like with the begin property, if the property is not
    /// specified, the end time for the animation is determined by the latest time values present
    /// in the Track structures belonging to this Animation.
    pub end: Opt<f32>,
    /// One or more tracks that each hold animation keys for a single target.
    pub tracks: Vec<Track>,
}

/// Enum wrapping over all possible animation track targets.
pub enum TrackTarget {
    pub Transformation(Rc<Transformation>),
    pub MorphWeight(Rc<MorphWeight>)
}

/// The Track structure contains animation key data for a single Transformation or MorphWeight
/// structure.
pub struct Track {
    // TODO: Finish this structure
}
<|endoftext|>


<commit_before>use position::Position;
use cppn::{Cppn, CppnNodeType};
use std::fmt::Debug;

/// Represents a node in the substrate. `T` is an arbitrary
/// type used to store additional information about that node.
pub struct Node<P: Position, T> {
    pub position: P,
    pub data: T,
}

pub struct Substrate<P: Position, T> {
    nodes: Vec<Node<P, T>>,
}

pub struct LinkIterator<'a,
                        N: CppnNodeType + 'a,
                        P: Position + 'a,
                        T: 'a,
                        EXTID: Copy + Debug + Send + Sized + 'a>
{
    nodes: &'a [Node<P, T>],
    cppn: &'a mut Cppn<'a, N, EXTID>,
    inner: usize,
    outer: usize,
    max_distance: Option<f64>,
}

#[derive(Copy, Clone)]
pub struct Link<'a, P: Position + 'a, T: 'a> {
    pub source: &'a Node<P, T>,
    pub target: &'a Node<P, T>,
    pub source_idx: usize,
    pub target_idx: usize,
    pub weight: f64,
    pub distance: f64,
}

impl<'a, N: CppnNodeType + 'a, P: Position + 'a, T: 'a, EXTID: Copy + Debug + Send + Sized + 'a> Iterator for LinkIterator<'a, N, P, T, EXTID> {
    type Item = Link<'a, P, T>;
    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.inner >= self.nodes.len() {
                self.inner = 0;
                self.outer += 1;
            }
            if self.outer >= self.nodes.len() {
                return None;
            }
            if self.inner == self.outer {
                self.inner += 1;
                continue;
            }

            assert!(self.inner < self.nodes.len() && self.outer < self.nodes.len() &&
                    self.inner != self.outer);
            let source = &self.nodes[self.inner];
            let target = &self.nodes[self.outer];
            let distance = source.position.distance(&target.position);

            // reject a pair of nodes based on `max_distance`.
            if let Some(max_d) = self.max_distance {
                if distance > max_d {
                    self.inner += 1;
                    continue;
                }
            }

            // Calculate the weight between source and target using the CPPN.
            let inputs_to_cppn = [source.position.coords(), target.position.coords()];
            let outputs_from_cppn = self.cppn.calculate(&inputs_to_cppn);
            assert!(outputs_from_cppn.len() == 1);
            let weight = outputs_from_cppn[0];

            let link = Link {
                source: source,
                target: target,
                source_idx: self.inner,
                target_idx: self.outer,
                weight: weight,
                distance: distance,
            };
            self.inner += 1;
            return Some(link);
        }
    }
}

impl<P: Position, T> Substrate<P, T> {
    pub fn new() -> Substrate<P, T> {
        Substrate { nodes: Vec::new() }
    }

    pub fn nodes(&self) -> &[Node<P, T>] {
        &self.nodes
    }

    pub fn add_node(&mut self, position: P, data: T) {
        self.nodes.push(Node {
            position: position,
            data: data,
        });
    }

    /// Iterate over all produced links of Cppn.
    pub fn iter_links<'a, N, EXTID>(&'a self,
                                    cppn: &'a mut Cppn<'a, N, EXTID>,
                                    max_distance: Option<f64>)
                                    -> LinkIterator<'a, N, P, T, EXTID>
        where N: CppnNodeType,
              EXTID: Copy + Debug + Send + Sized
    {
        LinkIterator {
            nodes: &self.nodes,
            cppn: cppn,
            inner: 0,
            outer: 0,
            max_distance: max_distance,
        }
    }
}
<commit_msg>Add missing commit<commit_after>use position::Position;
use cppn::{Cppn, CppnNodeType};

/// Represents a node in the substrate. `T` is an arbitrary
/// type used to store additional information about that node.
pub struct Node<P: Position, T> {
    pub position: P,
    pub data: T,
}

pub struct Substrate<P: Position, T> {
    nodes: Vec<Node<P, T>>,
}

pub struct LinkIterator<'a, N: CppnNodeType + 'a, P: Position + 'a, T: 'a> {
    nodes: &'a [Node<P, T>],
    cppn: &'a mut Cppn<'a, N>,
    inner: usize,
    outer: usize,
    max_distance: Option<f64>,
}

#[derive(Copy, Clone)]
pub struct Link<'a, P: Position + 'a, T: 'a> {
    pub source: &'a Node<P, T>,
    pub target: &'a Node<P, T>,
    pub source_idx: usize,
    pub target_idx: usize,
    pub weight: f64,
    pub distance: f64,
}

impl<'a, N: CppnNodeType + 'a, P: Position + 'a, T: 'a> Iterator for LinkIterator<'a, N, P, T> {
    type Item = Link<'a, P, T>;
    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.inner >= self.nodes.len() {
                self.inner = 0;
                self.outer += 1;
            }
            if self.outer >= self.nodes.len() {
                return None;
            }
            if self.inner == self.outer {
                self.inner += 1;
                continue;
            }

            assert!(self.inner < self.nodes.len() && self.outer < self.nodes.len() &&
                    self.inner != self.outer);
            let source = &self.nodes[self.inner];
            let target = &self.nodes[self.outer];
            let distance = source.position.distance(&target.position);

            // reject a pair of nodes based on `max_distance`.
            if let Some(max_d) = self.max_distance {
                if distance > max_d {
                    self.inner += 1;
                    continue;
                }
            }

            // Calculate the weight between source and target using the CPPN.
            let inputs_to_cppn = [source.position.coords(), target.position.coords()];
            let outputs_from_cppn = self.cppn.calculate(&inputs_to_cppn);
            assert!(outputs_from_cppn.len() == 1);
            let weight = outputs_from_cppn[0];

            let link = Link {
                source: source,
                target: target,
                source_idx: self.inner,
                target_idx: self.outer,
                weight: weight,
                distance: distance,
            };
            self.inner += 1;
            return Some(link);
        }
    }
}

impl<P: Position, T> Substrate<P, T> {
    pub fn new() -> Substrate<P, T> {
        Substrate { nodes: Vec::new() }
    }

    pub fn nodes(&self) -> &[Node<P, T>] {
        &self.nodes
    }

    pub fn add_node(&mut self, position: P, data: T) {
        self.nodes.push(Node {
            position: position,
            data: data,
        });
    }

    /// Iterate over all produced links of Cppn.
    pub fn iter_links<'a, N>(&'a self,
                             cppn: &'a mut Cppn<'a, N>,
                             max_distance: Option<f64>)
                             -> LinkIterator<'a, N, P, T>
        where N: CppnNodeType
    {
        LinkIterator {
            nodes: &self.nodes,
            cppn: cppn,
            inner: 0,
            outer: 0,
            max_distance: max_distance,
        }
    }
}
<|endoftext|>