<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::fmt;
use std::io::Write;
use std::mem;

use syn;

use bindgen::config::{Config, Language};
use bindgen::declarationtyperesolver::DeclarationTypeResolver;
use bindgen::ir::{
    AnnotationSet, Cfg, ConditionWrite, Documentation, GenericParams, Item, ItemContainer, Path,
    ToCondition, Type,
};
use bindgen::writer::{Source, SourceWriter};

#[derive(Debug, Clone)]
pub enum Literal {
    Expr(String),
    Struct {
        name: String,
        export_name: String,
        fields: Vec<(String, Literal)>,
    },
}

impl fmt::Display for Literal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Literal::Expr(v) => write!(f, "{}", v),
            Literal::Struct {
                name: _,
                export_name,
                fields,
            } => write!(
                f,
                "({}){{ {} }}",
                export_name,
                fields
                    .iter()
                    .map(|(key, lit)| format!(".{} = {}", key, lit))
                    .collect::<Vec<String>>()
                    .join(", "),
            ),
        }
    }
}

impl Literal {
    pub fn rename_for_config(&mut self, config: &Config) {
        match self {
            Literal::Struct {
                name: _,
                ref mut export_name,
                fields: _,
            } => config.export.rename(export_name),
            Literal::Expr(_) => {}
        }
    }

    pub fn load(expr: &syn::Expr) -> Result<Literal, String> {
        match expr {
            &syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Str(ref value),
                ..
            }) => Ok(Literal::Expr(format!("u8\"{}\"", value.value()))),
            &syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Byte(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value()))),
            &syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Char(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value()))),
            &syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Int(ref value),
                ..
            }) => match value.suffix() {
                syn::IntSuffix::Usize
                | syn::IntSuffix::U8
                | syn::IntSuffix::U16
                | syn::IntSuffix::U32
                | syn::IntSuffix::U64
                | syn::IntSuffix::U128
                | syn::IntSuffix::None => Ok(Literal::Expr(format!("{}", value.value()))),
                syn::IntSuffix::Isize
                | syn::IntSuffix::I8
                | syn::IntSuffix::I16
                | syn::IntSuffix::I32
                | syn::IntSuffix::I64
                | syn::IntSuffix::I128 => unsafe {
                    Ok(Literal::Expr(format!(
                        "{}",
                        mem::transmute::<u64, i64>(value.value())
                    )))
                },
            },
            &syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Float(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value()))),
            &syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Bool(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value))),

            &syn::Expr::Struct(syn::ExprStruct {
                ref path,
                ref fields,
                ..
            }) => {
                let struct_name = path.segments[0].ident.to_string();
                let mut field_pairs: Vec<(String, Literal)> = Vec::new();
                for field in fields {
                    let ident = match field.member {
                        syn::Member::Named(ref name) => name.to_string(),
                        syn::Member::Unnamed(ref index) => format!("_{}", index.index),
                    };
                    let key = ident.to_string();
                    let value = Literal::load(&field.expr)?;
                    field_pairs.push((key, value));
                }
                Ok(Literal::Struct {
                    name: struct_name.clone(),
                    export_name: struct_name,
                    fields: field_pairs,
                })
            }
            _ => Err("Unsupported literal expression.".to_owned()),
        }
    }
}

#[derive(Debug, Clone)]
pub struct Constant {
    pub path: Path,
    pub export_name: String,
    pub ty: Type,
    pub value: Literal,
    pub cfg: Option<Cfg>,
    pub annotations: AnnotationSet,
    pub documentation: Documentation,
}

impl Constant {
    pub fn load(
        path: Path,
        item: &syn::ItemConst,
        mod_cfg: &Option<Cfg>,
    ) -> Result<Constant, String> {
        let ty = Type::load(&item.ty)?;

        if ty.is_none() {
            return Err("Cannot have a zero sized const definition.".to_owned());
        }

        let ty = ty.unwrap();

        if !ty.is_primitive_or_ptr_primitive()
            && match *item.expr {
                syn::Expr::Struct(_) => false,
                _ => true,
            } {
            return Err("Unhanded const definition".to_owned());
        }

        Ok(Constant::new(
            path,
            ty,
            Literal::load(&item.expr)?,
            Cfg::append(mod_cfg, Cfg::load(&item.attrs)),
            AnnotationSet::load(&item.attrs)?,
            Documentation::load(&item.attrs),
        ))
    }

    pub fn load_assoc(
        name: String,
        item: &syn::ImplItemConst,
        impl_ty: &syn::Type,
        mod_cfg: &Option<Cfg>,
    ) -> Result<Constant, String> {
        let ty = Type::load(&item.ty)?;

        if ty.is_none() {
            return Err("Cannot have a zero sized const definition.".to_owned());
        }
        let ty = ty.unwrap();
        if !ty.is_primitive_or_ptr_primitive()
            && match item.expr {
                syn::Expr::Struct(_) => false,
                _ => true,
            } {
            return Err("Unhanded const definition".to_owned());
        }

        let impl_ty = Type::load(impl_ty)?;
        if impl_ty.is_none() {
            return Err("impl has an empty type".to_owned());
        }
        let impl_ty = impl_ty.unwrap();

        let struct_path = impl_ty.get_root_path().unwrap();
        let full_name = Path::new(format!("{}_{}", struct_path, name));

        Ok(Constant::new(
            full_name,
            ty,
            Literal::load(&item.expr)?,
            Cfg::append(mod_cfg, Cfg::load(&item.attrs)),
            AnnotationSet::load(&item.attrs)?,
            Documentation::load(&item.attrs),
        ))
    }

    pub fn new(
        path: Path,
        ty: Type,
        value: Literal,
        cfg: Option<Cfg>,
        annotations: AnnotationSet,
        documentation: Documentation,
    ) -> Self {
        let export_name = path.name().to_owned();
        Self {
            path,
            export_name,
            ty,
            value,
            cfg,
            annotations,
            documentation,
        }
    }
}

impl Item for Constant {
    fn path(&self) -> &Path {
        &self.path
    }

    fn export_name(&self) -> &str {
        &self.export_name
    }

    fn cfg(&self) -> &Option<Cfg> {
        &self.cfg
    }

    fn annotations(&self) -> &AnnotationSet {
        &self.annotations
    }

    fn annotations_mut(&mut self) -> &mut AnnotationSet {
        &mut self.annotations
    }

    fn container(&self) -> ItemContainer {
        ItemContainer::Constant(self.clone())
    }

    fn rename_for_config(&mut self, config: &Config) {
        config.export.rename(&mut self.export_name);
        self.value.rename_for_config(config);
        self.ty.rename_for_config(config, &GenericParams::default()); // FIXME: should probably propagate something here
    }

    fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) {
        self.ty.resolve_declaration_types(resolver);
    }
}

impl Source for Constant {
    fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        let condition = (&self.cfg).to_condition(config);
        condition.write_before(config, out);
        if config.constant.allow_static_const && config.language == Language::Cxx {
            if let Type::ConstPtr(..) = self.ty {
                out.write("static ");
            } else {
                out.write("static const ");
            }
            self.ty.write(config, out);
            write!(out, " {} = {};", self.export_name(), self.value)
        } else {
            write!(out, "#define {} {}", self.export_name(), self.value)
        }
        condition.write_after(config, out);
    }
}
<commit_msg>Propagate rename in struct literals<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::fmt;
use std::io::Write;
use std::mem;

use syn;

use bindgen::config::{Config, Language};
use bindgen::declarationtyperesolver::DeclarationTypeResolver;
use bindgen::ir::{
    AnnotationSet, Cfg, ConditionWrite, Documentation, GenericParams, Item, ItemContainer, Path,
    ToCondition, Type,
};
use bindgen::writer::{Source, SourceWriter};

#[derive(Debug, Clone)]
pub enum Literal {
    Expr(String),
    Struct {
        name: String,
        export_name: String,
        fields: Vec<(String, Literal)>,
    },
}

impl fmt::Display for Literal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Literal::Expr(v) => write!(f, "{}", v),
            Literal::Struct {
                name: _,
                export_name,
                fields,
            } => write!(
                f,
                "({}){{ {} }}",
                export_name,
                fields
                    .iter()
                    .map(|(key, lit)| format!(".{} = {}", key, lit))
                    .collect::<Vec<String>>()
                    .join(", "),
            ),
        }
    }
}

impl Literal {
    pub fn rename_for_config(&mut self, config: &Config) {
        match self {
            Literal::Struct {
                name: _,
                ref mut export_name,
                fields,
            } => {
                config.export.rename(export_name);
                for (_, lit) in fields {
                    lit.rename_for_config(config);
                }
            }
            Literal::Expr(_) => {}
        }
    }

    pub fn load(expr: &syn::Expr) -> Result<Literal, String> {
        match expr {
            &syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Str(ref value),
                ..
            }) => Ok(Literal::Expr(format!("u8\"{}\"", value.value()))),
            &syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Byte(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value()))),
            &syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Char(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value()))),
            &syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Int(ref value),
                ..
            }) => match value.suffix() {
                syn::IntSuffix::Usize
                | syn::IntSuffix::U8
                | syn::IntSuffix::U16
                | syn::IntSuffix::U32
                | syn::IntSuffix::U64
                | syn::IntSuffix::U128
                | syn::IntSuffix::None => Ok(Literal::Expr(format!("{}", value.value()))),
                syn::IntSuffix::Isize
                | syn::IntSuffix::I8
                | syn::IntSuffix::I16
                | syn::IntSuffix::I32
                | syn::IntSuffix::I64
                | syn::IntSuffix::I128 => unsafe {
                    Ok(Literal::Expr(format!(
                        "{}",
                        mem::transmute::<u64, i64>(value.value())
                    )))
                },
            },
            &syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Float(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value()))),
            &syn::Expr::Lit(syn::ExprLit {
                lit: syn::Lit::Bool(ref value),
                ..
            }) => Ok(Literal::Expr(format!("{}", value.value))),

            &syn::Expr::Struct(syn::ExprStruct {
                ref path,
                ref fields,
                ..
            }) => {
                let struct_name = path.segments[0].ident.to_string();
                let mut field_pairs: Vec<(String, Literal)> = Vec::new();
                for field in fields {
                    let ident = match field.member {
                        syn::Member::Named(ref name) => name.to_string(),
                        syn::Member::Unnamed(ref index) => format!("_{}", index.index),
                    };
                    let key = ident.to_string();
                    let value = Literal::load(&field.expr)?;
                    field_pairs.push((key, value));
                }
                Ok(Literal::Struct {
                    name: struct_name.clone(),
                    export_name: struct_name,
                    fields: field_pairs,
                })
            }
            _ => Err("Unsupported literal expression.".to_owned()),
        }
    }
}

#[derive(Debug, Clone)]
pub struct Constant {
    pub path: Path,
    pub export_name: String,
    pub ty: Type,
    pub value: Literal,
    pub cfg: Option<Cfg>,
    pub annotations: AnnotationSet,
    pub documentation: Documentation,
}

impl Constant {
    pub fn load(
        path: Path,
        item: &syn::ItemConst,
        mod_cfg: &Option<Cfg>,
    ) -> Result<Constant, String> {
        let ty = Type::load(&item.ty)?;

        if ty.is_none() {
            return Err("Cannot have a zero sized const definition.".to_owned());
        }

        let ty = ty.unwrap();

        if !ty.is_primitive_or_ptr_primitive()
            && match *item.expr {
                syn::Expr::Struct(_) => false,
                _ => true,
            } {
            return Err("Unhanded const definition".to_owned());
        }

        Ok(Constant::new(
            path,
            ty,
            Literal::load(&item.expr)?,
            Cfg::append(mod_cfg, Cfg::load(&item.attrs)),
            AnnotationSet::load(&item.attrs)?,
            Documentation::load(&item.attrs),
        ))
    }

    pub fn load_assoc(
        name: String,
        item: &syn::ImplItemConst,
        impl_ty: &syn::Type,
        mod_cfg: &Option<Cfg>,
    ) -> Result<Constant, String> {
        let ty = Type::load(&item.ty)?;

        if ty.is_none() {
            return Err("Cannot have a zero sized const definition.".to_owned());
        }
        let ty = ty.unwrap();
        if !ty.is_primitive_or_ptr_primitive()
            && match item.expr {
                syn::Expr::Struct(_) => false,
                _ => true,
            } {
            return Err("Unhanded const definition".to_owned());
        }

        let impl_ty = Type::load(impl_ty)?;
        if impl_ty.is_none() {
            return Err("impl has an empty type".to_owned());
        }
        let impl_ty = impl_ty.unwrap();

        let struct_path = impl_ty.get_root_path().unwrap();
        let full_name = Path::new(format!("{}_{}", struct_path, name));

        Ok(Constant::new(
            full_name,
            ty,
            Literal::load(&item.expr)?,
            Cfg::append(mod_cfg, Cfg::load(&item.attrs)),
            AnnotationSet::load(&item.attrs)?,
            Documentation::load(&item.attrs),
        ))
    }

    pub fn new(
        path: Path,
        ty: Type,
        value: Literal,
        cfg: Option<Cfg>,
        annotations: AnnotationSet,
        documentation: Documentation,
    ) -> Self {
        let export_name = path.name().to_owned();
        Self {
            path,
            export_name,
            ty,
            value,
            cfg,
            annotations,
            documentation,
        }
    }
}

impl Item for Constant {
    fn path(&self) -> &Path {
        &self.path
    }

    fn export_name(&self) -> &str {
        &self.export_name
    }

    fn cfg(&self) -> &Option<Cfg> {
        &self.cfg
    }

    fn annotations(&self) -> &AnnotationSet {
        &self.annotations
    }

    fn annotations_mut(&mut self) -> &mut AnnotationSet {
        &mut self.annotations
    }

    fn container(&self) -> ItemContainer {
        ItemContainer::Constant(self.clone())
    }

    fn rename_for_config(&mut self, config: &Config) {
        config.export.rename(&mut self.export_name);
        self.value.rename_for_config(config);
        self.ty.rename_for_config(config, &GenericParams::default()); // FIXME: should probably propagate something here
    }

    fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) {
        self.ty.resolve_declaration_types(resolver);
    }
}

impl Source for Constant {
    fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        let condition = (&self.cfg).to_condition(config);
        condition.write_before(config, out);
        if config.constant.allow_static_const && config.language == Language::Cxx {
            if let Type::ConstPtr(..) = self.ty {
                out.write("static ");
            } else {
                out.write("static const ");
            }
            self.ty.write(config, out);
            write!(out, " {} = {};", self.export_name(), self.value)
        } else {
            write!(out, "#define {} {}", self.export_name(), self.value)
        }
        condition.write_after(config, out);
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Read, Write};
use std::fmt;
use byteorder::{ReadBytesExt, WriteBytesExt};
use instruction::write_to::WriteTo;

const REG_SIZE: usize = 1;
const DIR_SIZE: usize = 4;
const ALT_DIR_SIZE: usize = DIR_SIZE / 2;
const IND_SIZE: usize = 2;

mod direct;
mod indirect;
mod register;

mod alt_direct;

mod dir_ind;
mod dir_ind_reg;
mod dir_reg;
mod ind_reg;

mod alt_dir_ind;
mod alt_dir_ind_reg;
mod alt_dir_reg;

pub use self::direct::Direct;
pub use self::indirect::Indirect;
pub use self::register::{Register, InvalidRegister, REG_MAX};

pub use self::alt_direct::AltDirect;

pub use self::dir_ind::DirInd;
pub use self::dir_ind_reg::DirIndReg;
pub use self::dir_reg::DirReg;
pub use self::ind_reg::IndReg;

pub use self::alt_dir_ind::AltDirInd;
pub use self::alt_dir_ind_reg::AltDirIndReg;
pub use self::alt_dir_reg::AltDirReg;

pub use self::register::Error as RegisterError;
pub use self::dir_ind::Error as DirIndError;
pub use self::dir_ind_reg::Error as DirIndRegError;
pub use self::dir_reg::Error as DirRegError;
pub use self::ind_reg::Error as IndRegError;

pub trait HasParamCode {
    fn has_param_code(&self) -> bool;
}

pub trait ParamTypeOf {
    fn param_type(&self) -> ParamType;
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InvalidParamType(ParamType);

// TODO: make free-construction impossible: use a private field
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ParamType {
    Direct,
    Indirect,
    Register,
}

impl From<ParamType> for u8 {
    fn from(param_type: ParamType) -> Self {
        match param_type {
            ParamType::Direct => 0b10,
            ParamType::Indirect => 0b11,
            ParamType::Register => 0b01,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ParamNumber {
    First,
    Second,
    Third,
    Fourth,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InvalidParamCode(pub u8, ParamNumber);

#[derive(Clone, Copy)]
pub struct ParamCode(u8);

impl fmt::Debug for ParamCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:0<8o}", self.0)
    }
}

impl ParamCode {
    pub fn read_from<R: Read>(reader: &mut R) -> io::Result<Self> {
        let value = reader.read_u8()?;
        let param_code = ParamCode(value);
        Ok(param_code)
    }

    pub fn null() -> Self {
        ParamCode(0)
    }

    pub fn builder() -> ParamCodeBuilder {
        ParamCodeBuilder(0)
    }

    pub fn param_type_of(&self, param: ParamNumber) -> Result<ParamType, InvalidParamCode> {
        let param_type = match param {
            ParamNumber::First => (self.0 & 0b1100_0000) >> 6,
            ParamNumber::Second => (self.0 & 0b0011_0000) >> 4,
            ParamNumber::Third => (self.0 & 0b0000_1100) >> 2,
            ParamNumber::Fourth => (self.0 & 0b0000_0011) >> 0,
        };
        match param_type {
            0b10 => Ok(ParamType::Direct),
            0b11 => Ok(ParamType::Indirect),
            0b01 => Ok(ParamType::Register),
            _ => Err(InvalidParamCode(self.0, param))
        }
    }
}

impl WriteTo for ParamCode {
    fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writer.write_u8(self.0)
    }
}

#[derive(Debug, Clone, Copy)]
pub struct ParamCodeBuilder(u8);

impl ParamCodeBuilder {
    pub fn build(self) -> ParamCode {
        ParamCode(self.0)
    }

    pub fn first<P: ParamTypeOf>(self, param: &P) -> Self {
        let param_type = ParamTypeOf::param_type(param);
        ParamCodeBuilder((self.0 & 0b0011_1111) | Into::<u8>::into(param_type) << 6)
    }

    pub fn second<P: ParamTypeOf>(self, param: &P) -> Self {
        let param_type = ParamTypeOf::param_type(param);
        ParamCodeBuilder((self.0 & 0b1100_1111) | Into::<u8>::into(param_type) << 4)
    }

    pub fn third<P: ParamTypeOf>(self, param: &P) -> Self {
        let param_type = ParamTypeOf::param_type(param);
        ParamCodeBuilder((self.0 & 0b1111_0011) | Into::<u8>::into(param_type) << 2)
    }

    pub fn fourth<P: ParamTypeOf>(self, param: &P) -> Self {
        let param_type = ParamTypeOf::param_type(param);
        ParamCodeBuilder((self.0 & 0b1111_1100) | Into::<u8>::into(param_type) << 0)
    }
}

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

    mod first {
        use super::*;

        #[test]
        fn is_direct() {
            let mut param: &[u8] = &[0b10000000];
            let param = ParamCode::try_from(&mut param).unwrap();
            assert_eq!(param.param_type_of(ParamNumber::First).unwrap(), ParamType::Direct);
        }

        #[test]
        fn is_indirect() {
            let mut param: &[u8] = &[0b11000000];
            let param = ParamCode::try_from(&mut param).unwrap();
            assert_eq!(param.param_type_of(ParamNumber::First).unwrap(), ParamType::Indirect);
        }

        #[test]
        fn is_register() {
            let mut param: &[u8] = &[0b01000000];
            let param = ParamCode::try_from(&mut param).unwrap();
            assert_eq!(param.param_type_of(ParamNumber::First).unwrap(), ParamType::Register);
        }

        #[test]
        fn is_invalid() {
            let mut param: &[u8] = &[0b00000000];
            let param = ParamCode::try_from(&mut param).unwrap();
            assert_eq!(param.param_type_of(ParamNumber::First).unwrap_err(), InvalidParamCode(0, ParamNumber::First));
        }
    }

    mod third {
        use super::*;

        #[test]
        fn is_direct() {
            let mut param: &[u8] = &[0b00001000];
            let param = ParamCode::try_from(&mut param).unwrap();
            assert_eq!(param.param_type_of(ParamNumber::Third).unwrap(), ParamType::Direct);
        }

        #[test]
        fn is_indirect() {
            let mut param: &[u8] = &[0b00001100];
            let param = ParamCode::try_from(&mut param).unwrap();
            assert_eq!(param.param_type_of(ParamNumber::Third).unwrap(), ParamType::Indirect);
        }

        #[test]
        fn is_register() {
            let mut param: &[u8] = &[0b00000100];
            let param = ParamCode::try_from(&mut param).unwrap();
            assert_eq!(param.param_type_of(ParamNumber::Third).unwrap(), ParamType::Register);
        }

        #[test]
        fn is_invalid() {
            let mut param: &[u8] = &[0b00000000];
            let param = ParamCode::try_from(&mut param).unwrap();
            assert_eq!(param.param_type_of(ParamNumber::Third).unwrap_err(), InvalidParamCode(0, ParamNumber::Third));
        }
    }

    mod builder {
        use super::*;

        impl ParamTypeOf for ParamType {
            fn param_type(&self) -> ParamType {
                match *self {
                    ParamType::Direct => ParamType::Direct,
                    ParamType::Indirect => ParamType::Indirect,
                    ParamType::Register => ParamType::Register,
                }
            }
        }

        #[test]
        fn first_and_third() {
            let param = ParamCode::builder().first(&ParamType::Direct).third(&ParamType::Register).build();
            assert_eq!(param.param_type_of(ParamNumber::First).unwrap(), ParamType::Direct);
            assert_eq!(param.param_type_of(ParamNumber::Third).unwrap(), ParamType::Register);
        }

        #[test]
        fn redeclare_first() {
            let param = ParamCode::builder().first(&ParamType::Register).first(&ParamType::Direct).build();
            assert_eq!(param.param_type_of(ParamNumber::First).unwrap(), ParamType::Direct);
        }
    }
}
<commit_msg>fix: Use read_from instead of try_from<commit_after>use std::io::{self, Read, Write};
use std::fmt;
use byteorder::{ReadBytesExt, WriteBytesExt};
use instruction::write_to::WriteTo;

const REG_SIZE: usize = 1;
const DIR_SIZE: usize = 4;
const ALT_DIR_SIZE: usize = DIR_SIZE / 2;
const IND_SIZE: usize = 2;

mod direct;
mod indirect;
mod register;

mod alt_direct;

mod dir_ind;
mod dir_ind_reg;
mod dir_reg;
mod ind_reg;

mod alt_dir_ind;
mod alt_dir_ind_reg;
mod alt_dir_reg;

pub use self::direct::Direct;
pub use self::indirect::Indirect;
pub use self::register::{Register, InvalidRegister, REG_MAX};

pub use self::alt_direct::AltDirect;

pub use self::dir_ind::DirInd;
pub use self::dir_ind_reg::DirIndReg;
pub use self::dir_reg::DirReg;
pub use self::ind_reg::IndReg;

pub use self::alt_dir_ind::AltDirInd;
pub use self::alt_dir_ind_reg::AltDirIndReg;
pub use self::alt_dir_reg::AltDirReg;

pub use self::register::Error as RegisterError;
pub use self::dir_ind::Error as DirIndError;
pub use self::dir_ind_reg::Error as DirIndRegError;
pub use self::dir_reg::Error as DirRegError;
pub use self::ind_reg::Error as IndRegError;

pub trait HasParamCode {
    fn has_param_code(&self) -> bool;
}

pub trait ParamTypeOf {
    fn param_type(&self) -> ParamType;
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InvalidParamType(ParamType);

// TODO: make free-construction impossible: use a private field
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ParamType {
    Direct,
    Indirect,
    Register,
}

impl From<ParamType> for u8 {
    fn from(param_type: ParamType) -> Self {
        match param_type {
            ParamType::Direct => 0b10,
            ParamType::Indirect => 0b11,
            ParamType::Register => 0b01,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ParamNumber {
    First,
    Second,
    Third,
    Fourth,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InvalidParamCode(pub u8, ParamNumber);

#[derive(Clone, Copy)]
pub struct ParamCode(u8);

impl fmt::Debug for ParamCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:0<8o}", self.0)
    }
}

impl ParamCode {
    pub fn read_from<R: Read>(reader: &mut R) -> io::Result<Self> {
        let value = reader.read_u8()?;
        let param_code = ParamCode(value);
        Ok(param_code)
    }

    pub fn null() -> Self {
        ParamCode(0)
    }

    pub fn builder() -> ParamCodeBuilder {
        ParamCodeBuilder(0)
    }

    pub fn param_type_of(&self, param: ParamNumber) -> Result<ParamType, InvalidParamCode> {
        let param_type = match param {
            ParamNumber::First => (self.0 & 0b1100_0000) >> 6,
            ParamNumber::Second => (self.0 & 0b0011_0000) >> 4,
            ParamNumber::Third => (self.0 & 0b0000_1100) >> 2,
            ParamNumber::Fourth => (self.0 & 0b0000_0011) >> 0,
        };
        match param_type {
            0b10 => Ok(ParamType::Direct),
            0b11 => Ok(ParamType::Indirect),
            0b01 => Ok(ParamType::Register),
            _ => Err(InvalidParamCode(self.0, param))
        }
    }
}

impl WriteTo for ParamCode {
    fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writer.write_u8(self.0)
    }
}

#[derive(Debug, Clone, Copy)]
pub struct ParamCodeBuilder(u8);

impl ParamCodeBuilder {
    pub fn build(self) -> ParamCode {
        ParamCode(self.0)
    }

    pub fn first<P: ParamTypeOf>(self, param: &P) -> Self {
        let param_type = ParamTypeOf::param_type(param);
        ParamCodeBuilder((self.0 & 0b0011_1111) | Into::<u8>::into(param_type) << 6)
    }

    pub fn second<P: ParamTypeOf>(self, param: &P) -> Self {
        let param_type = ParamTypeOf::param_type(param);
        ParamCodeBuilder((self.0 & 0b1100_1111) | Into::<u8>::into(param_type) << 4)
    }

    pub fn third<P: ParamTypeOf>(self, param: &P) -> Self {
        let param_type = ParamTypeOf::param_type(param);
        ParamCodeBuilder((self.0 & 0b1111_0011) | Into::<u8>::into(param_type) << 2)
    }

    pub fn fourth<P: ParamTypeOf>(self, param: &P) -> Self {
        let param_type = ParamTypeOf::param_type(param);
        ParamCodeBuilder((self.0 & 0b1111_1100) | Into::<u8>::into(param_type) << 0)
    }
}

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

    mod first {
        use super::*;

        #[test]
        fn is_direct() {
            let mut param: &[u8] = &[0b10000000];
            let param = ParamCode::read_from(&mut param).unwrap();
            assert_eq!(param.param_type_of(ParamNumber::First).unwrap(), ParamType::Direct);
        }

        #[test]
        fn is_indirect() {
            let mut param: &[u8] = &[0b11000000];
            let param = ParamCode::read_from(&mut param).unwrap();
            assert_eq!(param.param_type_of(ParamNumber::First).unwrap(), ParamType::Indirect);
        }

        #[test]
        fn is_register() {
            let mut param: &[u8] = &[0b01000000];
            let param = ParamCode::read_from(&mut param).unwrap();
            assert_eq!(param.param_type_of(ParamNumber::First).unwrap(), ParamType::Register);
        }

        #[test]
        fn is_invalid() {
            let mut param: &[u8] = &[0b00000000];
            let param = ParamCode::read_from(&mut param).unwrap();
            assert_eq!(param.param_type_of(ParamNumber::First).unwrap_err(), InvalidParamCode(0, ParamNumber::First));
        }
    }

    mod third {
        use super::*;

        #[test]
        fn is_direct() {
            let mut param: &[u8] = &[0b00001000];
            let param = ParamCode::read_from(&mut param).unwrap();
            assert_eq!(param.param_type_of(ParamNumber::Third).unwrap(), ParamType::Direct);
        }

        #[test]
        fn is_indirect() {
            let mut param: &[u8] = &[0b00001100];
            let param = ParamCode::read_from(&mut param).unwrap();
            assert_eq!(param.param_type_of(ParamNumber::Third).unwrap(), ParamType::Indirect);
        }

        #[test]
        fn is_register() {
            let mut param: &[u8] = &[0b00000100];
            let param = ParamCode::read_from(&mut param).unwrap();
            assert_eq!(param.param_type_of(ParamNumber::Third).unwrap(), ParamType::Register);
        }

        #[test]
        fn is_invalid() {
            let mut param: &[u8] = &[0b00000000];
            let param = ParamCode::read_from(&mut param).unwrap();
            assert_eq!(param.param_type_of(ParamNumber::Third).unwrap_err(), InvalidParamCode(0, ParamNumber::Third));
        }
    }

    mod builder {
        use super::*;

        impl ParamTypeOf for ParamType {
            fn param_type(&self) -> ParamType {
                match *self {
                    ParamType::Direct => ParamType::Direct,
                    ParamType::Indirect => ParamType::Indirect,
                    ParamType::Register => ParamType::Register,
                }
            }
        }

        #[test]
        fn first_and_third() {
            let param = ParamCode::builder().first(&ParamType::Direct).third(&ParamType::Register).build();
            assert_eq!(param.param_type_of(ParamNumber::First).unwrap(), ParamType::Direct);
            assert_eq!(param.param_type_of(ParamNumber::Third).unwrap(), ParamType::Register);
        }

        #[test]
        fn redeclare_first() {
            let param = ParamCode::builder().first(&ParamType::Register).first(&ParamType::Direct).build();
            assert_eq!(param.param_type_of(ParamNumber::First).unwrap(), ParamType::Direct);
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::fs;
use std::path::Path;
use std::process::Command;

use core::{PackageIdSpec, Workspace};
use ops;
use util::CargoResult;

pub struct DocOptions<'a> {
    pub open_result: bool,
    pub compile_opts: ops::CompileOptions<'a>,
}

pub fn doc(ws: &Workspace,
           options: &DocOptions) -> CargoResult<()> {
    let package = try!(ws.current());

    let mut lib_names = HashSet::new();
    let mut bin_names = HashSet::new();
    if options.compile_opts.spec.is_empty() {
        for target in package.targets().iter().filter(|t| t.documented()) {
            if target.is_lib() {
                assert!(lib_names.insert(target.crate_name()));
            } else {
                assert!(bin_names.insert(target.crate_name()));
            }
        }
        for bin in bin_names.iter() {
            if lib_names.contains(bin) {
                bail!("cannot document a package where a library and a binary \
                       have the same name. Consider renaming one or marking \
                       the target as `doc = false`")
            }
        }
    }

    try!(ops::compile(ws, &options.compile_opts));

    if options.open_result {
        let name = if options.compile_opts.spec.len() > 1 {
            bail!("Passing multiple packages and `open` is not supported")
        } else if options.compile_opts.spec.len() == 1 {
            try!(PackageIdSpec::parse(&options.compile_opts.spec[0]))
                                             .name().replace("-", "_")
        } else {
            match lib_names.iter().chain(bin_names.iter()).nth(0) {
                Some(s) => s.to_string(),
                None => return Ok(())
            }
        };

        // Don't bother locking here as if this is getting deleted there's
        // nothing we can do about it and otherwise if it's getting overwritten
        // then that's also ok!
        let mut target_dir = ws.target_dir();
        if let Some(triple) = options.compile_opts.target {
            target_dir.push(Path::new(triple).file_stem().unwrap());
        }
        let path = target_dir.join("doc").join(&name).join("index.html");
        let path = path.into_path_unlocked();
        if fs::metadata(&path).is_ok() {
            let mut shell = options.compile_opts.config.shell();
            match open_docs(&path) {
                Ok(m) => try!(shell.status("Launching", m)),
                Err(e) => {
                    try!(shell.warn(
                            "warning: could not determine a browser to open docs with, tried:"));
                    for method in e {
                        try!(shell.warn(format!("\t{}", method)));
                    }
                }
            }
        }
    }

    Ok(())
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
    use std::env;
    let mut methods = Vec::new();
    // trying $BROWSER
    if let Ok(name) = env::var("BROWSER") {
        match Command::new(name).arg(path).status() {
            Ok(_) => return Ok("$BROWSER"),
            Err(_) => methods.push("$BROWSER")
        }
    }

    for m in ["xdg-open", "gnome-open", "kde-open"].iter() {
        match Command::new(m).arg(path).status() {
            Ok(_) => return Ok(m),
            Err(_) => methods.push(m)
        }
    }

    Err(methods)
}

#[cfg(target_os = "windows")]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
    match Command::new("cmd").arg("/C").arg(path).status() {
        Ok(_) => return Ok("cmd /C"),
        Err(_) => return Err(vec!["cmd /C"])
    };
}

#[cfg(target_os = "macos")]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
    match Command::new("open").arg(path).status() {
        Ok(_) => return Ok("open"),
        Err(_) => return Err(vec!["open"])
    };
}
<commit_msg>rustfmt cargo_doc.rs<commit_after>use std::collections::HashSet;
use std::fs;
use std::path::Path;
use std::process::Command;

use core::{PackageIdSpec, Workspace};
use ops;
use util::CargoResult;

pub struct DocOptions<'a> {
    pub open_result: bool,
    pub compile_opts: ops::CompileOptions<'a>,
}

pub fn doc(ws: &Workspace, options: &DocOptions) -> CargoResult<()> {
    let package = try!(ws.current());

    let mut lib_names = HashSet::new();
    let mut bin_names = HashSet::new();
    if options.compile_opts.spec.is_empty() {
        for target in package.targets().iter().filter(|t| t.documented()) {
            if target.is_lib() {
                assert!(lib_names.insert(target.crate_name()));
            } else {
                assert!(bin_names.insert(target.crate_name()));
            }
        }
        for bin in bin_names.iter() {
            if lib_names.contains(bin) {
                bail!("cannot document a package where a library and a binary \
                       have the same name. Consider renaming one or marking \
                       the target as `doc = false`")
            }
        }
    }

    try!(ops::compile(ws, &options.compile_opts));

    if options.open_result {
        let name = if options.compile_opts.spec.len() > 1 {
            bail!("Passing multiple packages and `open` is not supported")
        } else if options.compile_opts.spec.len() == 1 {
            try!(PackageIdSpec::parse(&options.compile_opts.spec[0]))
                .name()
                .replace("-", "_")
        } else {
            match lib_names.iter().chain(bin_names.iter()).nth(0) {
                Some(s) => s.to_string(),
                None => return Ok(()),
            }
        };

        // Don't bother locking here as if this is getting deleted there's
        // nothing we can do about it and otherwise if it's getting overwritten
        // then that's also ok!
        let mut target_dir = ws.target_dir();
        if let Some(triple) = options.compile_opts.target {
            target_dir.push(Path::new(triple).file_stem().unwrap());
        }
        let path = target_dir.join("doc").join(&name).join("index.html");
        let path = path.into_path_unlocked();
        if fs::metadata(&path).is_ok() {
            let mut shell = options.compile_opts.config.shell();
            match open_docs(&path) {
                Ok(m) => try!(shell.status("Launching", m)),
                Err(e) => {
                    try!(shell.warn(
                            "warning: could not determine a browser to open docs with, tried:"));
                    for method in e {
                        try!(shell.warn(format!("\t{}", method)));
                    }
                }
            }
        }
    }

    Ok(())
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
    use std::env;
    let mut methods = Vec::new();
    // trying $BROWSER
    if let Ok(name) = env::var("BROWSER") {
        match Command::new(name).arg(path).status() {
            Ok(_) => return Ok("$BROWSER"),
            Err(_) => methods.push("$BROWSER"),
        }
    }

    for m in ["xdg-open", "gnome-open", "kde-open"].iter() {
        match Command::new(m).arg(path).status() {
            Ok(_) => return Ok(m),
            Err(_) => methods.push(m),
        }
    }

    Err(methods)
}

#[cfg(target_os = "windows")]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
    match Command::new("cmd").arg("/C").arg(path).status() {
        Ok(_) => return Ok("cmd /C"),
        Err(_) => return Err(vec!["cmd /C"]),
    };
}

#[cfg(target_os = "macos")]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
    match Command::new("open").arg(path).status() {
        Ok(_) => return Ok("open"),
        Err(_) => return Err(vec!["open"]),
    };
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::env;
use std::fs;
use std::path::Path;
use std::process::Command;

use core::{Package, PackageIdSpec};
use ops;
use util::CargoResult;

pub struct DocOptions<'a> {
    pub open_result: bool,
    pub compile_opts: ops::CompileOptions<'a>,
}

pub fn doc(manifest_path: &Path,
           options: &DocOptions) -> CargoResult<()> {
    let package = try!(Package::for_path(manifest_path, options.compile_opts.config));

    let mut lib_names = HashSet::new();
    let mut bin_names = HashSet::new();
    if options.compile_opts.spec.is_empty() {
        for target in package.targets().iter().filter(|t| t.documented()) {
            if target.is_lib() {
                assert!(lib_names.insert(target.crate_name()));
            } else {
                assert!(bin_names.insert(target.crate_name()));
            }
        }
        for bin in bin_names.iter() {
            if lib_names.contains(bin) {
                bail!("cannot document a package where a library and a binary \
                       have the same name. Consider renaming one or marking \
                       the target as `doc = false`")
            }
        }
    }

    try!(ops::compile(manifest_path, &options.compile_opts));

    if options.open_result {
        let name = if options.compile_opts.spec.len() > 1 {
            bail!("Passing multiple packages and `open` is not supported")
        } else if options.compile_opts.spec.len() == 1 {
            try!(PackageIdSpec::parse(&options.compile_opts.spec[0]))
                                             .name().replace("-", "_")
        } else {
            match lib_names.iter().chain(bin_names.iter()).nth(0) {
                Some(s) => s.to_string(),
                None => return Ok(())
            }
        };

        let target_dir = options.compile_opts.config.target_dir(&package);
        let path = target_dir.join("doc").join(&name).join("index.html");
        if fs::metadata(&path).is_ok() {
            open_docs(&path);
        }
    }

    Ok(())
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn open_docs(path: &Path) {
    // trying $BROWSER
    match env::var("BROWSER").map(|name| Command::new(name).arg(path).status()) {
        Ok(_) => return,
        Err(_) => ()
    }

    // trying xdg-open
    match Command::new("xdg-open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };

    // trying gnome-open
    match Command::new("gnome-open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };

    // trying kde-open
    match Command::new("kde-open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };
}

#[cfg(target_os = "windows")]
fn open_docs(path: &Path) {
    match Command::new("cmd").arg("/C").arg("start").arg("").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };
}

#[cfg(target_os = "macos")]
fn open_docs(path: &Path) {
    match Command::new("open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };
}
<commit_msg>Warn if could not open docs in browser<commit_after>use std::collections::HashSet;
use std::env;
use std::fs;
use std::path::Path;
use std::process::Command;

use core::{Package, PackageIdSpec};
use ops;
use util::CargoResult;

pub struct DocOptions<'a> {
    pub open_result: bool,
    pub compile_opts: ops::CompileOptions<'a>,
}

pub fn doc(manifest_path: &Path,
           options: &DocOptions) -> CargoResult<()> {
    let package = try!(Package::for_path(manifest_path, options.compile_opts.config));

    let mut lib_names = HashSet::new();
    let mut bin_names = HashSet::new();
    if options.compile_opts.spec.is_empty() {
        for target in package.targets().iter().filter(|t| t.documented()) {
            if target.is_lib() {
                assert!(lib_names.insert(target.crate_name()));
            } else {
                assert!(bin_names.insert(target.crate_name()));
            }
        }
        for bin in bin_names.iter() {
            if lib_names.contains(bin) {
                bail!("cannot document a package where a library and a binary \
                       have the same name. Consider renaming one or marking \
                       the target as `doc = false`")
            }
        }
    }

    try!(ops::compile(manifest_path, &options.compile_opts));

    if options.open_result {
        let name = if options.compile_opts.spec.len() > 1 {
            bail!("Passing multiple packages and `open` is not supported")
        } else if options.compile_opts.spec.len() == 1 {
            try!(PackageIdSpec::parse(&options.compile_opts.spec[0]))
                                             .name().replace("-", "_")
        } else {
            match lib_names.iter().chain(bin_names.iter()).nth(0) {
                Some(s) => s.to_string(),
                None => return Ok(())
            }
        };

        let target_dir = options.compile_opts.config.target_dir(&package);
        let path = target_dir.join("doc").join(&name).join("index.html");
        if fs::metadata(&path).is_ok() {
            match open_docs(&path) {
                Ok(_) => (),
                Err(_) => {
                    println!("warning: could not determine a browser to open docs with.");
                }
            }
        }
    }

    Ok(())
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn open_docs(path: &Path) -> Result<(), ()> {
    // trying $BROWSER
    match env::var("BROWSER").map(|name| Command::new(name).arg(path).status()) {
        Ok(_) => return Ok(()),
        Err(_) => ()
    }

    // trying xdg-open
    match Command::new("xdg-open").arg(path).status() {
        Ok(_) => return Ok(()),
        Err(_) => ()
    };

    // trying gnome-open
    match Command::new("gnome-open").arg(path).status() {
        Ok(_) => return Ok(()),
        Err(_) => ()
    };

    // trying kde-open
    match Command::new("kde-open").arg(path).status() {
        Ok(_) => return Ok(()),
        Err(_) => ()
    };
    Err(())
}

#[cfg(target_os = "windows")]
fn open_docs(path: &Path) -> Result<(), ()> {
    match Command::new("cmd").arg("/C").arg("start").arg("").arg(path).status() {
        Ok(_) => return Ok(()),
        Err(_) => ()
    };
    Err(())
}

#[cfg(target_os = "macos")]
fn open_docs(path: &Path) -> Result<(), ()> {
    match Command::new("open").arg(path).status() {
        Ok(_) => return Ok(()),
        Err(_) => ()
    };
    Err(())
}
<|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}}}]}}"#);
    assert_eq!(result_body, result);
}
<commit_msg>correction<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#"{"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}}}]}}"#);
    assert_eq!(result_body, result);
}
<|endoftext|>


<commit_before>extern crate phone_number as phone;

fn process_clean_case(number: &str, expected: Option<&str>) {
    assert_eq!(phone::number(number), expected.map(|x| x.to_string()));
}

#[test]
fn test_cleans_the_number() {
    process_clean_case("(223) 456-7890", Some("2234567890"));
}

#[test]
#[ignore]
fn test_cleans_numbers_with_dots() {
    process_clean_case("223.456.7890", Some("2234567890"));
}

#[test]
#[ignore]
fn test_cleans_numbers_with_multiple_spaces() {
    process_clean_case("223 456   7890   ", Some("2234567890"));
}

#[test]
#[ignore]
fn test_invalid_when_9_digits() {
    process_clean_case("123456789", None);
}

#[test]
#[ignore]
fn test_invalid_when_11_digits_does_not_start_with_a_1() {
    process_clean_case("22234567890", None);
}

#[test]
#[ignore]
fn test_valid_when_11_digits_and_starting_with_1() {
    process_clean_case("12234567890", Some("2234567890"));
}

#[test]
#[ignore]
fn test_valid_when_11_digits_and_starting_with_1_even_with_punctuation() {
    process_clean_case("+1 (223) 456-7890", Some("2234567890"));
}

#[test]
#[ignore]
fn test_invalid_when_more_than_11_digits() {
    process_clean_case("321234567890", None);
}

#[test]
#[ignore]
fn test_invalid_with_letters() {
    process_clean_case("123-abc-7890", None);
}

#[test]
#[ignore]
fn test_invalid_with_punctuations() {
    process_clean_case("123-@:!-7890", None);
}

#[test]
#[ignore]
fn test_invalid_if_area_code_does_not_start_with_2_9() {
    process_clean_case("(123) 456-7890", None);
}

#[test]
#[ignore]
fn test_invalid_if_exchange_code_does_not_start_with_2_9() {
    process_clean_case("(223) 056-7890", None);
}

#[test]
#[ignore]
fn test_invalid_if_area_code_starts_with_1_on_valid_11digit_number() {
    process_clean_case("1 (123) 456-7890", None);
}

#[test]
#[ignore]
fn test_invalid_if_area_code_starts_with_0_on_valid_11digit_number() {
    process_clean_case("1 (023) 456-7890", None);
}

#[test]
#[ignore]
fn test_invalid_if_area_code_starts_with_1() {
    process_clean_case("(123) 456-7890", None);
}

#[test]
#[ignore]
fn test_invalid_if_exchange_code_starts_with_1() {
    process_clean_case("(223) 156-7890", None);
}

#[test]
#[ignore]
fn test_invalid_if_exchange_code_starts_with_0() {
    process_clean_case("(223) 056-7890", None);
}

#[test]
#[ignore]
fn test_invalid_if_exchange_code_starts_with_1_on_valid_11digit_number() {
    process_clean_case("1 (223) 156-7890", None);
}

#[test]
#[ignore]
fn test_invalid_if_exchange_code_starts_with_0_on_valid_11digit_number() {
    process_clean_case("1 (223) 056-7890", None);
}

#[test]
#[ignore]
fn test_invalid_if_area_code_starts_with_0() {
    process_clean_case("(023) 456-7890", None);
}
<commit_msg>phone-number: Removed the duplicate test cases<commit_after>extern crate phone_number as phone;

fn process_clean_case(number: &str, expected: Option<&str>) {
    assert_eq!(phone::number(number), expected.map(|x| x.to_string()));
}

#[test]
fn test_cleans_the_number() {
    process_clean_case("(223) 456-7890", Some("2234567890"));
}

#[test]
#[ignore]
fn test_cleans_numbers_with_dots() {
    process_clean_case("223.456.7890", Some("2234567890"));
}

#[test]
#[ignore]
fn test_cleans_numbers_with_multiple_spaces() {
    process_clean_case("223 456   7890   ", Some("2234567890"));
}

#[test]
#[ignore]
fn test_invalid_when_9_digits() {
    process_clean_case("123456789", None);
}

#[test]
#[ignore]
fn test_invalid_when_11_digits_does_not_start_with_a_1() {
    process_clean_case("22234567890", None);
}

#[test]
#[ignore]
fn test_valid_when_11_digits_and_starting_with_1() {
    process_clean_case("12234567890", Some("2234567890"));
}

#[test]
#[ignore]
fn test_valid_when_11_digits_and_starting_with_1_even_with_punctuation() {
    process_clean_case("+1 (223) 456-7890", Some("2234567890"));
}

#[test]
#[ignore]
fn test_invalid_when_more_than_11_digits() {
    process_clean_case("321234567890", None);
}

#[test]
#[ignore]
fn test_invalid_with_letters() {
    process_clean_case("123-abc-7890", None);
}

#[test]
#[ignore]
fn test_invalid_with_punctuations() {
    process_clean_case("123-@:!-7890", None);
}

#[test]
#[ignore]
fn test_invalid_if_area_code_starts_with_1_on_valid_11digit_number() {
    process_clean_case("1 (123) 456-7890", None);
}

#[test]
#[ignore]
fn test_invalid_if_area_code_starts_with_0_on_valid_11digit_number() {
    process_clean_case("1 (023) 456-7890", None);
}

#[test]
#[ignore]
fn test_invalid_if_area_code_starts_with_1() {
    process_clean_case("(123) 456-7890", None);
}

#[test]
#[ignore]
fn test_invalid_if_exchange_code_starts_with_1() {
    process_clean_case("(223) 156-7890", None);
}

#[test]
#[ignore]
fn test_invalid_if_exchange_code_starts_with_0() {
    process_clean_case("(223) 056-7890", None);
}

#[test]
#[ignore]
fn test_invalid_if_exchange_code_starts_with_1_on_valid_11digit_number() {
    process_clean_case("1 (223) 156-7890", None);
}

#[test]
#[ignore]
fn test_invalid_if_exchange_code_starts_with_0_on_valid_11digit_number() {
    process_clean_case("1 (223) 056-7890", None);
}

#[test]
#[ignore]
fn test_invalid_if_area_code_starts_with_0() {
    process_clean_case("(023) 456-7890", None);
}
<|endoftext|>


<commit_before>use redox::{self, cmp, env};
use redox::collections::BTreeMap;
use redox::fs::{self, File};
use redox::io::{Read, Seek, SeekFrom};
use redox::time::{self, Duration};
use redox::vec::Vec;
use redox::string::{String, ToString};

use orbital::{event, BmpFile, Color, EventOption, MouseEvent, Window};

pub struct FileType {
    description: String,
    icon: BmpFile,
}

impl FileType {
    pub fn new(desc: &str, icon: &str) -> FileType {
        FileType { description: desc.to_string(), icon: load_icon(icon) }
    }

}

pub struct FileManager {
    file_types: BTreeMap<String, FileType>,
    files: Vec<String>,
    file_sizes: Vec<String>,
    selected: isize,
    last_mouse_event: MouseEvent,
    click_time: Duration,
}

fn load_icon(path: &str) -> BmpFile {
    let mut vec: Vec<u8> = Vec::new();
    if let Some(mut file) = File::open(&("file:///ui/mimetypes/".to_string() + path + ".bmp")) {
        file.read_to_end(&mut vec);
    }
    BmpFile::from_data(&vec)
}

impl FileManager {
    pub fn new() -> Self {
        FileManager {
            file_types: {
                let mut file_types = BTreeMap::<String, FileType>::new();
                file_types.insert("/".to_string(),
                                  FileType::new("Folder", "inode-directory"));
                file_types.insert("wav".to_string(),
                                  FileType::new("WAV audio", "audio-x-wav"));
                file_types.insert("bin".to_string(),
                                  FileType::new("Executable", "application-x-executable"));
                file_types.insert("bmp".to_string(),
                                  FileType::new("Bitmap Image", "image-x-generic"));
                file_types.insert("rs".to_string(),
                                  FileType::new("Rust source code", "text-x-makefile"));
                file_types.insert("crate".to_string(),
                                  FileType::new("Rust crate", "application-x-archive"));
                file_types.insert("rlib".to_string(),
                                  FileType::new("Static Rust library", "application-x-object"));
                file_types.insert("asm".to_string(),
                                  FileType::new("Assembly source", "text-x-makefile"));
                file_types.insert("list".to_string(),
                                  FileType::new("Disassembly source", "text-x-makefile"));
                file_types.insert("c".to_string(),
                                  FileType::new("C source code", "text-x-csrc"));
                file_types.insert("cpp".to_string(),
                                  FileType::new("C++ source code", "text-x-c++src"));
                file_types.insert("h".to_string(),
                                  FileType::new("C header", "text-x-chdr"));
                file_types.insert("sh".to_string(),
                                  FileType::new("Shell script", "text-x-script"));
                file_types.insert("lua".to_string(),
                                  FileType::new("Lua script", "text-x-script"));
                file_types.insert("txt".to_string(),
                                  FileType::new("Plain text document", "text-x-generic"));
                file_types.insert("md".to_string(),
                                  FileType::new("Markdown document", "text-x-generic"));
                file_types.insert("toml".to_string(),
                                  FileType::new("TOML document", "text-x-generic"));
                file_types.insert("json".to_string(),
                                  FileType::new("JSON document", "text-x-generic"));
                file_types.insert("REDOX".to_string(),
                                  FileType::new("Redox package", "text-x-generic"));
                file_types.insert(String::new(),
                                  FileType::new("Unknown file", "unknown"));
                file_types
            },
            files: Vec::new(),
            file_sizes: Vec::new(),
            selected: -1,
            last_mouse_event: MouseEvent {
                x: 0,
                y: 0,
                left_button: false,
                middle_button: false,
                right_button: false,
            },
            click_time: Duration::new(0, 0),
        }
    }

    fn load_icon_with(&self, file_name: &str, row: isize, window: &mut Window) {
        if file_name.ends_with('/') {
            window.image(0,
                         32 * row as isize,
                         self.file_types["/"].icon.width(),
                         self.file_types["/"].icon.height(),
                         self.file_types["/"].icon.as_slice());
        } else {
            let pos = file_name.rfind('.').unwrap_or(0) + 1;
            match self.file_types.get(&file_name[pos..]) {
                Some(file_type) => {
                    window.image(0,
                                 32 * row,
                                 file_type.icon.width(),
                                 file_type.icon.height(),
                                 file_type.icon.as_slice());
                }
                None => {
                    window.image(0,
                                 32 * row,
                                 self.file_types[""].icon.width(),
                                 self.file_types[""].icon.height(),
                                 self.file_types[""].icon.as_slice());
                }
            }
        }
    }

    fn get_description(&self, file_name: &str) -> String {
        if file_name.ends_with('/') {
            self.file_types["/"].description.clone()
        } else {
            let pos = file_name.rfind('.').unwrap_or(0) + 1;
            match self.file_types.get(&file_name[pos..]) {
                Some(file_type) => file_type.description.clone(),
                None => self.file_types[""].description.clone(),
            }
        }
    }

    fn draw_content(&mut self, window: &mut Window) {
        window.set(Color::WHITE);

        let mut i = 0;
        let mut row = 0;
        let column = {
            let mut tmp = [0, 0];
            for string in self.files.iter() {
                if tmp[0] < string.len() {
                    tmp[0] = string.len();
                }
            }

            tmp[0] += 1;

            for file_size in self.file_sizes.iter() {
                if tmp[1] < file_size.len() {
                    tmp[1] = file_size.len();
                }
            }

            tmp[1] += tmp[0] + 1;
            tmp
        };
        for (file_name, file_size) in self.files.iter().zip(self.file_sizes.iter()) {
            if i == self.selected {
                let width = window.width();
                window.rect(0, 32 * row as isize, width, 32, Color::rgba(224, 224, 224, 255));
            }

            self.load_icon_with(&file_name, row as isize, window);

            let mut col = 0;
            for c in file_name.chars() {
                if c == '\n' {
                    col = 0;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col < window.width() / 8 && row < window.height() / 32 {
                        window.char(8 * col as isize + 40,
                                    32 * row as isize + 8,
                                    c,
                                    Color::BLACK);
                        col += 1;
                    }
                }
                if col >= window.width() / 8 {
                    col = 0;
                    row += 1;
                }
            }

            col = column[0];

            for c in file_size.chars() {
                if c == '\n' {
                    col = 0;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col < window.width() / 8 && row < window.height() / 32 {
                        window.char(8 * col as isize + 40,
                                    32 * row as isize + 8,
                                    c,
                                    Color::BLACK);
                        col += 1;
                    }
                }
                if col >= window.width() / 8 {
                    col = 0;
                    row += 1;
                }
            }

            col = column[1];

            for c in self.get_description(file_name).chars() {
                if c == '\n' {
                    col = 0;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col < window.width() / 8 && row < window.height() / 32 {
                        window.char(8 * col as isize + 40,
                                    32 * row as isize + 8,
                                    c,
                                    Color::BLACK);
                        col += 1;
                    }
                }
                if col >= window.width() / 8 {
                    col = 0;
                    row += 1;
                }
            }

            row += 1;
            i += 1;
        }

        window.sync();
    }

    fn main(&mut self, path: &str) {
        let mut width = [48, 48, 48];
        let mut height = 0;
        if let Some(readdir) = fs::read_dir(path) {
            for entry in readdir {
                self.files.push(entry.path().to_string());
                self.file_sizes.push(
                    // When the entry is a folder
                    if entry.path().ends_with('/') {
                        let count = match fs::read_dir(&(path.to_string() + entry.path())) {
                            Some(entry_readdir) => entry_readdir.count(),
                            None => 0
                        };

                        if count == 1 {
                            "1 entry".to_string()
                        } else {
                            format!("{} entries", count)
                        }
                    } else {
                        match File::open(&(path.to_string() + entry.path())) {
                            Some(mut file) => match file.seek(SeekFrom::End(0)) {
                                Some(size) => {
                                    if size >= 1_000_000_000 {
                                        format!("{:.1} GB", (size as f64)/1_000_000_000.0)
                                    } else if size >= 1_000_000 {
                                        format!("{:.1} MB", (size as f64)/1_000_000.0)
                                    } else if size >= 1_000 {
                                        format!("{:.1} KB", (size as f64)/1_000.0)
                                    } else {
                                        format!("{:.1} bytes", size)
                                    }
                                }
                                None => "Failed to seek".to_string()
                            },
                            None => "Failed to open".to_string()
                        }
                    }
                );
                // Unwrapping the last file size will not panic since it has
                // been at least pushed once in the vector
                width[0] = cmp::max(width[0], 48 + (entry.path().len()) * 8);
                width[1] = cmp::max(width[1], 8 + (self.file_sizes.last().unwrap().len()) * 8);
                width[2] = cmp::max(width[2], 8 + (self.get_description(entry.path()).len()) * 8);
            }

            if height < self.files.len() * 32 {
                height = self.files.len() * 32;
            }
        }

        let mut window = Window::new(-1,
                                     -1,
                                     width.iter().sum(),
                                     height,
                                     &path).unwrap();

        self.draw_content(&mut window);

        while let Some(event) = window.poll() {
            match event.to_option() {
                EventOption::Key(key_event) => {
                    if key_event.pressed {
                        match key_event.scancode {
                            event::K_ESC => break,
                            event::K_HOME => self.selected = 0,
                            event::K_UP => if self.selected > 0 {
                                self.selected -= 1;
                            },
                            event::K_END => self.selected = self.files.len() as isize - 1,
                            event::K_DOWN => if self.selected < self.files.len() as isize - 1 {
                                self.selected += 1;
                            },
                            _ => match key_event.character {
                                '\0' => (),
                                '\n' => {
                                    if self.selected >= 0 &&
                                       self.selected < self.files.len() as isize {
                                        match self.files.get(self.selected as usize) {
                                            Some(file) => {
                                                File::exec(&(path.to_string() + &file));
                                            },
                                            None => (),
                                        }
                                    }
                                }
                                _ => {
                                    let mut i = 0;
                                    for file in self.files.iter() {
                                        if file.starts_with(key_event.character) {
                                            self.selected = i;
                                            break;
                                        }
                                        i += 1;
                                    }
                                }
                            },
                        }

                        self.draw_content(&mut window);
                    }
                }
                EventOption::Mouse(mouse_event) => {
                    let mut redraw = false;
                    let mut i = 0;
                    let mut row = 0;
                    for file in self.files.iter() {
                        let mut col = 0;
                        for c in file.chars() {
                            if mouse_event.y >= 32 * row as isize &&
                               mouse_event.y < 32 * row as isize + 32 {
                                self.selected = i;
                                redraw = true;
                            }

                            if c == '\n' {
                                col = 0;
                                row += 1;
                            } else if c == '\t' {
                                col += 8 - col % 8;
                            } else {
                                if col < window.width() / 8 && row < window.height() / 32 {
                                    col += 1;
                                }
                            }
                            if col >= window.width() / 8 {
                                col = 0;
                                row += 1;
                            }
                        }
                        row += 1;
                        i += 1;
                    }

                    if redraw {
                        self.draw_content(&mut window);
                    }

                    //Check for double click
                    if mouse_event.left_button {
                        let click_time = Duration::realtime();

                        if click_time - self.click_time < Duration::new(0, 500 * time::NANOS_PER_MILLI)
                            && self.last_mouse_event.x == mouse_event.x
                            && self.last_mouse_event.y == mouse_event.y {
                            if self.selected >= 0 && self.selected < self.files.len() as isize {
                                if let Some(file) = self.files.get(self.selected as usize) {
                                    File::exec(&(path.to_string() + &file));
                                }
                            }
                            self.click_time = Duration::new(0, 0);
                        } else {
                            self.click_time = click_time;
                        }
                    }
                    self.last_mouse_event = mouse_event;
                }
                EventOption::Quit(quit_event) => break,
                _ => (),
            }
        }
    }
}

pub fn main() {
    match env::args().get(1) {
        Some(arg) => FileManager::new().main(arg),
        None => FileManager::new().main("file:///"),
    }
}
<commit_msg>Make navigation work again<commit_after>use redox::Box;
use redox::{self, cmp, env};
use redox::collections::BTreeMap;
use redox::fs::{self, File};
use redox::io::{Read, Seek, SeekFrom};
use redox::time::{self, Duration};
use redox::vec::Vec;
use redox::string::{String, ToString};

use orbital::{event, BmpFile, Color, EventOption, MouseEvent, Window};

struct FileType {
    description: String,
    icon: BmpFile,
}

impl FileType {
    fn new(desc: &str, icon: &str) -> FileType {
        FileType { description: desc.to_string(), icon: load_icon(icon) }
    }

}

struct FileTypesInfo {
    file_types: BTreeMap<String, FileType>,
}

impl FileTypesInfo {
    pub fn new () -> FileTypesInfo {
        let mut file_types = BTreeMap::<String, FileType>::new();
        file_types.insert("/".to_string(),
                          FileType::new("Folder", "inode-directory"));
        file_types.insert("wav".to_string(),
                          FileType::new("WAV audio", "audio-x-wav"));
        file_types.insert("bin".to_string(),
                          FileType::new("Executable", "application-x-executable"));
        file_types.insert("bmp".to_string(),
                          FileType::new("Bitmap Image", "image-x-generic"));
        file_types.insert("rs".to_string(),
                          FileType::new("Rust source code", "text-x-makefile"));
        file_types.insert("crate".to_string(),
                          FileType::new("Rust crate", "application-x-archive"));
        file_types.insert("rlib".to_string(),
                          FileType::new("Static Rust library", "application-x-object"));
        file_types.insert("asm".to_string(),
                          FileType::new("Assembly source", "text-x-makefile"));
        file_types.insert("list".to_string(),
                          FileType::new("Disassembly source", "text-x-makefile"));
        file_types.insert("c".to_string(),
                          FileType::new("C source code", "text-x-csrc"));
        file_types.insert("cpp".to_string(),
                          FileType::new("C++ source code", "text-x-c++src"));
        file_types.insert("h".to_string(),
                          FileType::new("C header", "text-x-chdr"));
        file_types.insert("sh".to_string(),
                          FileType::new("Shell script", "text-x-script"));
        file_types.insert("lua".to_string(),
                          FileType::new("Lua script", "text-x-script"));
        file_types.insert("txt".to_string(),
                          FileType::new("Plain text document", "text-x-generic"));
        file_types.insert("md".to_string(),
                          FileType::new("Markdown document", "text-x-generic"));
        file_types.insert("toml".to_string(),
                          FileType::new("TOML document", "text-x-generic"));
        file_types.insert("json".to_string(),
                          FileType::new("JSON document", "text-x-generic"));
        file_types.insert("REDOX".to_string(),
                          FileType::new("Redox package", "text-x-generic"));
        file_types.insert("".to_string(),
                          FileType::new("Unknown file", "unknown"));
        FileTypesInfo { file_types: file_types }
    }

    pub fn description_for(&self, file_name: &str) -> String {
        if file_name.ends_with('/') {
            self.file_types["/"].description.clone()
        } else {
            let pos = file_name.rfind('.').unwrap_or(0) + 1;
            let ext = &file_name[pos..];
            if self.file_types.contains_key(ext) {
                self.file_types[ext].description.clone()
            } else {
                self.file_types[""].description.clone()
            }
        }
    }

    pub fn icon_for(&self, file_name: &str) -> &BmpFile {
        if file_name.ends_with('/') {
            &self.file_types["/"].icon
        } else {
            let pos = file_name.rfind('.').unwrap_or(0) + 1;
            let ext = &file_name[pos..];
            if self.file_types.contains_key(ext) {
                &self.file_types[ext].icon
            } else {
                &self.file_types[""].icon
            }
        }
    }
}

enum FileManagerCommand {
    ChangeDir(String),
    Execute(String),
    Redraw,
    Quit,
}

pub struct FileManager {
    file_types_info: FileTypesInfo,
    files: Vec<String>,
    file_sizes: Vec<String>,
    selected: isize,
    last_mouse_event: MouseEvent,
    click_time: Duration,
    window: Box<Window>,
}

fn load_icon(path: &str) -> BmpFile {
    let mut vec: Vec<u8> = Vec::new();
    if let Some(mut file) = File::open(&("file:///ui/mimetypes/".to_string() + path + ".bmp")) {
        file.read_to_end(&mut vec);
    }
    BmpFile::from_data(&vec)
}

impl FileManager {
    pub fn new() -> Self {
        FileManager {
            file_types_info: FileTypesInfo::new(),
            files: Vec::new(),
            file_sizes: Vec::new(),
            selected: -1,
            last_mouse_event: MouseEvent {
                x: 0,
                y: 0,
                left_button: false,
                middle_button: false,
                right_button: false,
            },
            click_time: Duration::new(0, 0),
            window: Window::new(-1,-1,0,0,"").unwrap(),
        }
    }

    fn draw_content(&mut self) {
        self.window.set(Color::WHITE);

        let mut i = 0;
        let mut row = 0;
        let column = {
            let mut tmp = [0, 0];
            for string in self.files.iter() {
                if tmp[0] < string.len() {
                    tmp[0] = string.len();
                }
            }

            tmp[0] += 1;

            for file_size in self.file_sizes.iter() {
                if tmp[1] < file_size.len() {
                    tmp[1] = file_size.len();
                }
            }

            tmp[1] += tmp[0] + 1;
            tmp
        };
        for (file_name, file_size) in self.files.iter().zip(self.file_sizes.iter()) {
            if i == self.selected {
                let width = self.window.width();
                self.window.rect(0, 32 * row as isize, width, 32, Color::rgba(224, 224, 224, 255));
            }

            let icon = self.file_types_info.icon_for(&file_name);
            self.window.image(0,
                              32 * row as isize,
                              icon.width(),
                              icon.height(),
                              icon.as_slice());

            let mut col = 0;
            for c in file_name.chars() {
                if c == '\n' {
                    col = 0;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col < self.window.width() / 8 && row < self.window.height() / 32 {
                        self.window.char(8 * col as isize + 40,
                                    32 * row as isize + 8,
                                    c,
                                    Color::BLACK);
                        col += 1;
                    }
                }
                if col >= self.window.width() / 8 {
                    col = 0;
                    row += 1;
                }
            }

            col = column[0];

            for c in file_size.chars() {
                if c == '\n' {
                    col = 0;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col < self.window.width() / 8 && row < self.window.height() / 32 {
                        self.window.char(8 * col as isize + 40,
                                    32 * row as isize + 8,
                                    c,
                                    Color::BLACK);
                        col += 1;
                    }
                }
                if col >= self.window.width() / 8 {
                    col = 0;
                    row += 1;
                }
            }

            col = column[1];

            let description = self.file_types_info.description_for(&file_name);
            for c in description.chars() {
                if c == '\n' {
                    col = 0;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col < self.window.width() / 8 && row < self.window.height() / 32 {
                        self.window.char(8 * col as isize + 40,
                                    32 * row as isize + 8,
                                    c,
                                    Color::BLACK);
                        col += 1;
                    }
                }
                if col >= self.window.width() / 8 {
                    col = 0;
                    row += 1;
                }
            }

            row += 1;
            i += 1;
        }

        self.window.sync();
    }

    fn set_path(&mut self, path: &str) {
        let mut width = [48, 48, 48];
        let mut height = 0;
        if let Some(readdir) = fs::read_dir(path) {
            self.files.clear();
            for entry in readdir {
                self.files.push(entry.path().to_string());
                self.file_sizes.push(
                    // When the entry is a folder
                    if entry.path().ends_with('/') {
                        let count = match fs::read_dir(&(path.to_string() + entry.path())) {
                            Some(entry_readdir) => entry_readdir.count(),
                            None => 0
                        };

                        if count == 1 {
                            "1 entry".to_string()
                        } else {
                            format!("{} entries", count)
                        }
                    } else {
                        match File::open(&(path.to_string() + entry.path())) {
                            Some(mut file) => match file.seek(SeekFrom::End(0)) {
                                Some(size) => {
                                    if size >= 1_000_000_000 {
                                        format!("{:.1} GB", (size as f64)/1_000_000_000.0)
                                    } else if size >= 1_000_000 {
                                        format!("{:.1} MB", (size as f64)/1_000_000.0)
                                    } else if size >= 1_000 {
                                        format!("{:.1} KB", (size as f64)/1_000.0)
                                    } else {
                                        format!("{:.1} bytes", size)
                                    }
                                }
                                None => "Failed to seek".to_string()
                            },
                            None => "Failed to open".to_string()
                        }
                    }
                );
                // Unwrapping the last file size will not panic since it has
                // been at least pushed once in the vector
                let description = self.file_types_info.description_for(entry.path());
                width[0] = cmp::max(width[0], 48 + (entry.path().len()) * 8);
                width[1] = cmp::max(width[1], 8 + (self.file_sizes.last().unwrap().len()) * 8);
                width[2] = cmp::max(width[2], 8 + (description.len()) * 8);
            }

            if height < self.files.len() * 32 {
                height = self.files.len() * 32;
            }
        }
        self.window = Window::new(self.window.x(),
                                  self.window.y(),
                                  width.iter().sum(),
                                  height,
                                  &path).unwrap();
        self.draw_content();
    }

    fn event_loop(&mut self) -> Option<FileManagerCommand> {
        let mut redraw = false;
        let mut command = None;
        if let Some(event) = self.window.poll() {
            match event.to_option() {
                EventOption::Key(key_event) => {
                    if key_event.pressed {
                        match key_event.scancode {
                            event::K_ESC => return Some(FileManagerCommand::Quit),
                            event::K_HOME => self.selected = 0,
                            event::K_UP => if self.selected > 0 {
                                self.selected -= 1;
                                redraw = true
                            },
                            event::K_END => self.selected = self.files.len() as isize - 1,
                            event::K_DOWN => if self.selected < self.files.len() as isize - 1 {
                                self.selected += 1;
                            },
                            _ => match key_event.character {
                                '\0' => (),
                                '\n' => {
                                    if self.selected >= 0 &&
                                       self.selected < self.files.len() as isize {
                                        match self.files.get(self.selected as usize) {
                                            Some(file) => {
                                                if file.ends_with('/') {
                                                    command = Some(FileManagerCommand::ChangeDir(file.clone()));
                                                } else {
                                                    command = Some(FileManagerCommand::Execute(file.clone()));
                                                }
                                            },
                                            None => (),
                                        }
                                    }
                                }
                                _ => {
                                    let mut i = 0;
                                    for file in self.files.iter() {
                                        if file.starts_with(key_event.character) {
                                            self.selected = i;
                                            break;
                                        }
                                        i += 1;
                                    }
                                }
                            },
                        }
                        if command.is_none() && redraw {
                            command = Some(FileManagerCommand::Redraw);
                        }
                    }
                }
                EventOption::Mouse(mouse_event) => {
                    let mut redraw = false;
                    let mut i = 0;
                    let mut row = 0;
                    for file in self.files.iter() {
                        let mut col = 0;
                        for c in file.chars() {
                            if mouse_event.y >= 32 * row as isize &&
                               mouse_event.y < 32 * row as isize + 32 {
                                self.selected = i;
                            }

                            if c == '\n' {
                                col = 0;
                                row += 1;
                            } else if c == '\t' {
                                col += 8 - col % 8;
                            } else {
                                if col < self.window.width() / 8 && row < self.window.height() / 32 {
                                    col += 1;
                                }
                            }
                            if col >= self.window.width() / 8 {
                                col = 0;
                                row += 1;
                            }
                        }
                        row += 1;
                        i += 1; }

                    //Check for double click
                    if mouse_event.left_button {
                        let click_time = Duration::realtime();

                        if click_time - self.click_time < Duration::new(0, 500 * time::NANOS_PER_MILLI)
                            && self.last_mouse_event.x == mouse_event.x
                            && self.last_mouse_event.y == mouse_event.y {
                            if self.selected >= 0 && self.selected < self.files.len() as isize {
                                if let Some(file) = self.files.get(self.selected as usize) {
                                    if file.ends_with('/') {
                                        command = Some(FileManagerCommand::ChangeDir(file.clone()));
                                    } else {
                                        command = Some(FileManagerCommand::Execute(file.clone()));
                                    }
                                }
                            }
                            self.click_time = Duration::new(0, 0);
                        } else {
                            self.click_time = click_time;
                        }
                    }
                    self.last_mouse_event = mouse_event;
                }
                EventOption::Quit(quit_event) => command = Some(FileManagerCommand::Quit),
                _ => (),
            }
        }
        command
    }

    fn main(&mut self, path: &str) {
        let mut current_path = path.to_string();
        self.set_path(path);
        while true {
            match self.event_loop() {
                Some(event) => {
                    match event {
                        FileManagerCommand::ChangeDir(dir) => {
                            current_path = current_path + &dir;
                            self.set_path(&current_path);
                        },
                        FileManagerCommand::Execute(cmd) => { File::exec(&(current_path.clone() + &cmd)); } ,
                        FileManagerCommand::Redraw => (),
                        FileManagerCommand::Quit => break,
                    };
                    self.draw_content();
                },
                None => (),
            };
        }

    }
}

pub fn main() {
    match env::args().get(1) {
        Some(arg) => FileManager::new().main(arg),
        None => FileManager::new().main("file:///"),
    }
}
<|endoftext|>