<commit_before>pub trait Pad {
    fn pad_left(&self, length: usize, padding_character: char) -> String;
    fn pad_right(&self, length: usize, padding_character: char) -> String;
}

impl<T: AsRef<str>> Pad for T {
    fn pad_left(&self, length: usize, padding_character: char) -> String {
        let padding_length = get_padding_length(self.as_ref(), length);
        let padding = get_padding(padding_character, padding_length);

        format!("{}{}", padding, self.as_ref())
    }

    fn pad_right(&self, length: usize, padding_character: char) -> String {
        let padding_length = get_padding_length(self.as_ref(), length);
        let padding = get_padding(padding_character, padding_length);

        format!("{}{}", self.as_ref(), padding)
    }
}

fn get_padding_length(content: &str, length: usize) -> usize {
    let content_length = content.chars().count();
    if content_length > length {
        0
    } else {
        length - content_length
    }
}

fn get_padding(padding_character: char, length: usize) -> String {
    unsafe {
        String::from_utf8_unchecked(vec![padding_character as u8; length])
    }
}

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

    #[test]
    fn pad_left_works() {
        assert_eq!("    1", "1".pad_left(5, ' '));
    }

    #[test]
    fn pad_right_works() {
        assert_eq!("1    ", "1".pad_right(5, ' '));
    }
}
<commit_msg>Avoid format!() macro<commit_after>pub trait Pad {
    fn pad_left(&self, length: usize, padding_character: char) -> String;
    fn pad_right(&self, length: usize, padding_character: char) -> String;
}

impl<T: AsRef<str>> Pad for T {
    fn pad_left(&self, length: usize, padding_character: char) -> String {
        let padding_length = get_padding_length(self.as_ref(), length);
        let padding = get_padding(padding_character, padding_length);

        padding + self.as_ref()
    }

    fn pad_right(&self, length: usize, padding_character: char) -> String {
        let padding_length = get_padding_length(self.as_ref(), length);
        let padding = get_padding(padding_character, padding_length);

        self.as_ref().to_owned() + &padding
    }
}

fn get_padding_length(content: &str, length: usize) -> usize {
    let content_length = content.chars().count();
    if content_length > length {
        0
    } else {
        length - content_length
    }
}

fn get_padding(padding_character: char, length: usize) -> String {
    unsafe {
        String::from_utf8_unchecked(vec![padding_character as u8; length])
    }
}

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

    #[test]
    fn pad_left_works() {
        assert_eq!("    1", "1".pad_left(5, ' '));
    }

    #[test]
    fn pad_right_works() {
        assert_eq!("1    ", "1".pad_right(5, ' '));
    }
}
<|endoftext|>


<commit_before>/* Copyright 2015 Jordan Miner
 *
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 * option. This file may not be copied, modified, or distributed
 * except according to those terms.
 */

extern crate serde_json;

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

mod idl;
mod decode;
mod encode;

pub use idl::Lexer;
pub use idl::IdlError;
pub use idl::parse_idl;
pub use decode::DecodeError;
pub use decode::{
    decode,
    decode_var_len_u64,
    decode_zig_zag,
};
pub use encode::{
    encode_var_len_u64,
    encode_zig_zag,
};

#[derive(Debug, Clone, PartialEq)]
pub enum Value<'a, 'b> {
	Null,
	Boolean(bool),
	Int(i32),
	Long(i64),
	Float(f32),
	Double(f64),
	Bytes(Cow<'b, [u8]>),
	String(Cow<'b, str>),
	Record(Rc<RecordSchema<'a>>, Vec<Value<'a, 'b>>),
	Enum(Rc<EnumSchema<'a>>, i32),
	Array(Vec<Value<'a, 'b>>),
	Map(HashMap<Cow<'b, str>, Value<'a, 'b>>),
	Fixed(Rc<FixedSchema<'a>>, Cow<'b, [u8]>),
}

macro_rules! value_unwrap_fn {
    ($n: ident, $t:ty, $variant:ident, $val_pat:pat => $ret:expr) => {
        pub fn $n(&self) -> $t {
            match self {
                $val_pat => $ret,
                _ => panic!(concat!(
                    "called `Value::", stringify!($n), "()` on a non-`", stringify!($variant), "` value: {:?}"), self),
            }
        }
    };
}

impl<'a, 'b> Value<'a, 'b> {
    value_unwrap_fn!(unwrap_boolean, bool, Boolean, &Value::Boolean(val) => val);
    value_unwrap_fn!(unwrap_int, i32, Int, &Value::Int(val) => val);
    value_unwrap_fn!(unwrap_long, i64, Long, &Value::Long(val) => val);
    value_unwrap_fn!(unwrap_float, f32, Float, &Value::Float(val) => val);
    value_unwrap_fn!(unwrap_double, f64, Double, &Value::Double(val) => val);
    value_unwrap_fn!(unwrap_bytes, &Cow<'b, [u8]>, Bytes, &Value::Bytes(ref val) => val);
    value_unwrap_fn!(unwrap_string, &Cow<'b, str>, String, &Value::String(ref val) => val);
    value_unwrap_fn!(unwrap_record, (&Rc<RecordSchema<'a>>, &Vec<Value<'a, 'b>>),
        Record, &Value::Record(ref sch, ref val) => (sch, val));
    value_unwrap_fn!(unwrap_enum, (&Rc<EnumSchema<'a>>, i32),
        Enum, &Value::Enum(ref sch, val) => (sch, val));
    value_unwrap_fn!(unwrap_array, &Vec<Value<'a, 'b>>, Array, &Value::Array(ref val) => val);
    value_unwrap_fn!(unwrap_map, &HashMap<Cow<'b, str>, Value<'a, 'b>>,
        Map, &Value::Map(ref val) => val);
    value_unwrap_fn!(unwrap_fixed, (&Rc<FixedSchema<'a>>, &Cow<'b, [u8]>),
        Fixed, &Value::Fixed(ref sch, ref val) => (sch, val));
}

#[test]
fn test_value_unwrap() {
    assert_eq!(Value::Boolean(true).unwrap_boolean(), true);
    assert_eq!(Value::Int(4).unwrap_int(), 4);
    assert_eq!(Value::Long(7).unwrap_long(), 7);
    assert_eq!(Value::Float(3.14).unwrap_float(), 3.14);
    assert_eq!(Value::Double(3.14).unwrap_double(), 3.14);
    assert_eq!(Value::Bytes(Cow::Borrowed(&b"hi"[..])).unwrap_bytes(), &Cow::Borrowed(&b"hi"[..]));
    assert_eq!(Value::String(Cow::Borrowed(&"hi"[..])).unwrap_string(), &Cow::Borrowed(&"hi"[..]));
}

#[derive(Debug, Clone, PartialEq)]
pub struct Property<'a> {
    pub name: Cow<'a, str>,
    pub value: serde_json::Value,
}

impl<'a> Property<'a> {
    pub fn new(name: Cow<'a, str>, value: serde_json::Value) -> Property {
        Property {
            name: name,
            value: value,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Field<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
    pub properties: Vec<Property<'a>>,
	pub ty: Schema<'a>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct RecordSchema<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
    pub properties: Vec<Property<'a>>,
	pub fields: Vec<Field<'a>>,
	pub field_indexes: HashMap<Cow<'a, str>, usize>,
}

fn create_field_indexes<'a>(fields: &Vec<Field<'a>>) -> HashMap<Cow<'a, str>, usize> {
    fields.iter().enumerate().fold(HashMap::new(), |mut map, (i, f)| {
        map.insert(f.name.clone(), i);
        map
    })
}

impl<'a> RecordSchema<'a> {
    pub fn new(name: Cow<'a, str>,
               doc: Option<Cow<'a, str>>,
               properties: Vec<Property<'a>>,
               fields: Vec<Field<'a>>)
               -> RecordSchema<'a> {
        let indexes = create_field_indexes(&fields);
        RecordSchema {
            name: name,
            doc: doc,
            properties: properties,
            fields: fields,
            field_indexes: indexes,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct EnumSymbol<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct EnumSchema<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
    pub properties: Vec<Property<'a>>,
	pub symbols: Vec<EnumSymbol<'a>>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct FixedSchema<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
    pub properties: Vec<Property<'a>>,
	pub size: usize,
}

impl<'a> FixedSchema<'a> {
    pub fn new(name: Cow<'a, str>,
               doc: Option<Cow<'a, str>>,
               properties: Vec<Property<'a>>,
               size: usize)
               -> FixedSchema<'a> {
        FixedSchema {
            name: name,
            properties: properties,
            doc: doc,
            size: size,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Schema<'a> {
	Null,
	Boolean,
	Int,
	Long,
	Float,
	Double,
	Bytes,
	String,
	Record(Rc<RecordSchema<'a>>),
	Error(Rc<RecordSchema<'a>>),
	Enum(Rc<EnumSchema<'a>>),
	Array {
		items: Box<Schema<'a>>,
	},
	Map {
		values: Box<Schema<'a>>,
	},
	Union {
		tys: Vec<Schema<'a>>,
	},
	Fixed(Rc<FixedSchema<'a>>),
}

//impl<'a> Schema<'a> {
//    pub fn to_static(&self) -> Schema<'static> {
//    }
//}

#[derive(Debug, Clone, PartialEq)]
pub struct Message<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct Protocol<'a> {
    pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
    pub properties: Vec<Property<'a>>,
    pub tys: Vec<Schema<'a>>,
    pub messages: Vec<Message<'a>>,
}
<commit_msg>Expose DecodeErrorKind<commit_after>/* Copyright 2015 Jordan Miner
 *
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 * option. This file may not be copied, modified, or distributed
 * except according to those terms.
 */

extern crate serde_json;

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

mod idl;
mod decode;
mod encode;

pub use idl::Lexer;
pub use idl::IdlError;
pub use idl::parse_idl;
pub use decode::{
    DecodeError,
    DecodeErrorKind,
    decode,
    decode_var_len_u64,
    decode_zig_zag,
};
pub use encode::{
    encode_var_len_u64,
    encode_zig_zag,
};

#[derive(Debug, Clone, PartialEq)]
pub enum Value<'a, 'b> {
	Null,
	Boolean(bool),
	Int(i32),
	Long(i64),
	Float(f32),
	Double(f64),
	Bytes(Cow<'b, [u8]>),
	String(Cow<'b, str>),
	Record(Rc<RecordSchema<'a>>, Vec<Value<'a, 'b>>),
	Enum(Rc<EnumSchema<'a>>, i32),
	Array(Vec<Value<'a, 'b>>),
	Map(HashMap<Cow<'b, str>, Value<'a, 'b>>),
	Fixed(Rc<FixedSchema<'a>>, Cow<'b, [u8]>),
}

macro_rules! value_unwrap_fn {
    ($n: ident, $t:ty, $variant:ident, $val_pat:pat => $ret:expr) => {
        pub fn $n(&self) -> $t {
            match self {
                $val_pat => $ret,
                _ => panic!(concat!(
                    "called `Value::", stringify!($n), "()` on a non-`", stringify!($variant), "` value: {:?}"), self),
            }
        }
    };
}

impl<'a, 'b> Value<'a, 'b> {
    value_unwrap_fn!(unwrap_boolean, bool, Boolean, &Value::Boolean(val) => val);
    value_unwrap_fn!(unwrap_int, i32, Int, &Value::Int(val) => val);
    value_unwrap_fn!(unwrap_long, i64, Long, &Value::Long(val) => val);
    value_unwrap_fn!(unwrap_float, f32, Float, &Value::Float(val) => val);
    value_unwrap_fn!(unwrap_double, f64, Double, &Value::Double(val) => val);
    value_unwrap_fn!(unwrap_bytes, &Cow<'b, [u8]>, Bytes, &Value::Bytes(ref val) => val);
    value_unwrap_fn!(unwrap_string, &Cow<'b, str>, String, &Value::String(ref val) => val);
    value_unwrap_fn!(unwrap_record, (&Rc<RecordSchema<'a>>, &Vec<Value<'a, 'b>>),
        Record, &Value::Record(ref sch, ref val) => (sch, val));
    value_unwrap_fn!(unwrap_enum, (&Rc<EnumSchema<'a>>, i32),
        Enum, &Value::Enum(ref sch, val) => (sch, val));
    value_unwrap_fn!(unwrap_array, &Vec<Value<'a, 'b>>, Array, &Value::Array(ref val) => val);
    value_unwrap_fn!(unwrap_map, &HashMap<Cow<'b, str>, Value<'a, 'b>>,
        Map, &Value::Map(ref val) => val);
    value_unwrap_fn!(unwrap_fixed, (&Rc<FixedSchema<'a>>, &Cow<'b, [u8]>),
        Fixed, &Value::Fixed(ref sch, ref val) => (sch, val));
}

#[test]
fn test_value_unwrap() {
    assert_eq!(Value::Boolean(true).unwrap_boolean(), true);
    assert_eq!(Value::Int(4).unwrap_int(), 4);
    assert_eq!(Value::Long(7).unwrap_long(), 7);
    assert_eq!(Value::Float(3.14).unwrap_float(), 3.14);
    assert_eq!(Value::Double(3.14).unwrap_double(), 3.14);
    assert_eq!(Value::Bytes(Cow::Borrowed(&b"hi"[..])).unwrap_bytes(), &Cow::Borrowed(&b"hi"[..]));
    assert_eq!(Value::String(Cow::Borrowed(&"hi"[..])).unwrap_string(), &Cow::Borrowed(&"hi"[..]));
}

#[derive(Debug, Clone, PartialEq)]
pub struct Property<'a> {
    pub name: Cow<'a, str>,
    pub value: serde_json::Value,
}

impl<'a> Property<'a> {
    pub fn new(name: Cow<'a, str>, value: serde_json::Value) -> Property {
        Property {
            name: name,
            value: value,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Field<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
    pub properties: Vec<Property<'a>>,
	pub ty: Schema<'a>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct RecordSchema<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
    pub properties: Vec<Property<'a>>,
	pub fields: Vec<Field<'a>>,
	pub field_indexes: HashMap<Cow<'a, str>, usize>,
}

fn create_field_indexes<'a>(fields: &Vec<Field<'a>>) -> HashMap<Cow<'a, str>, usize> {
    fields.iter().enumerate().fold(HashMap::new(), |mut map, (i, f)| {
        map.insert(f.name.clone(), i);
        map
    })
}

impl<'a> RecordSchema<'a> {
    pub fn new(name: Cow<'a, str>,
               doc: Option<Cow<'a, str>>,
               properties: Vec<Property<'a>>,
               fields: Vec<Field<'a>>)
               -> RecordSchema<'a> {
        let indexes = create_field_indexes(&fields);
        RecordSchema {
            name: name,
            doc: doc,
            properties: properties,
            fields: fields,
            field_indexes: indexes,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct EnumSymbol<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct EnumSchema<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
    pub properties: Vec<Property<'a>>,
	pub symbols: Vec<EnumSymbol<'a>>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct FixedSchema<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
    pub properties: Vec<Property<'a>>,
	pub size: usize,
}

impl<'a> FixedSchema<'a> {
    pub fn new(name: Cow<'a, str>,
               doc: Option<Cow<'a, str>>,
               properties: Vec<Property<'a>>,
               size: usize)
               -> FixedSchema<'a> {
        FixedSchema {
            name: name,
            properties: properties,
            doc: doc,
            size: size,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Schema<'a> {
	Null,
	Boolean,
	Int,
	Long,
	Float,
	Double,
	Bytes,
	String,
	Record(Rc<RecordSchema<'a>>),
	Error(Rc<RecordSchema<'a>>),
	Enum(Rc<EnumSchema<'a>>),
	Array {
		items: Box<Schema<'a>>,
	},
	Map {
		values: Box<Schema<'a>>,
	},
	Union {
		tys: Vec<Schema<'a>>,
	},
	Fixed(Rc<FixedSchema<'a>>),
}

//impl<'a> Schema<'a> {
//    pub fn to_static(&self) -> Schema<'static> {
//    }
//}

#[derive(Debug, Clone, PartialEq)]
pub struct Message<'a> {
	pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct Protocol<'a> {
    pub name: Cow<'a, str>,
	pub doc: Option<Cow<'a, str>>,
    pub properties: Vec<Property<'a>>,
    pub tys: Vec<Schema<'a>>,
    pub messages: Vec<Message<'a>>,
}
<|endoftext|>


<commit_before>#![feature(io)]
#![feature(path)]
#![feature(fs)]
#![feature(collections)]
#![feature(core)]

use std::fs::{File};
use std::string::String;
use std::str::StrExt;
use std::path::AsPath;
use std::error::FromError;
use std::io::{Read, BufReader};
use std::vec::Vec;
use std::num::ParseIntError;
use std::mem;

pub enum Error {
    IOError,
    ParseError,
    DataTypeError,
    FieldTypeError,
    MalformedError,
    NotImplemented
}

impl FromError<std::io::Error> for Error {
    fn from_error(_: std::io::Error) -> Error {
        Error::IOError
    }
}

impl FromError<ParseIntError> for Error {
    fn from_error(_: ParseIntError) -> Error {
        Error::ParseError
    }
}

pub enum DataType {
    XDRFloat,
    FloatLE,
}

impl DataType {
    fn from_str(s: &str) -> Result<DataType, Error> {
        match s {
            "float_le" => Ok(DataType::FloatLE),
            "xdr_float" => Ok(DataType::XDRFloat),
            _ => Err(Error::DataTypeError)
        }
    }
}

pub enum FieldType {
    Uniform
}

impl FieldType {
    fn from_str(s: &str) -> Result<FieldType, Error> {
        match s {
            "uniform" => Ok(FieldType::Uniform),
            _ => Err(Error::FieldTypeError)
        }
    }
}

pub struct AVSFile<'a> {
    pub ndim: usize,
    pub sizes: Vec<usize>,
    pub data_type: DataType,
    pub field_type: FieldType,
    reader: Box<Read + 'a>
}

impl<'a> AVSFile<'a> {
    pub fn read_f32(self: &mut Self) -> Result<f32, Error> {
        match self.data_type {
            DataType::XDRFloat => {
                let mut buf = [ 0u8; 4 ];
                assert!(try!(self.reader.read(&mut buf)) == 4);
                (&mut buf).reverse();
                Ok(unsafe { mem::transmute(buf) } )
            }
            DataType::FloatLE => {
                let mut buf = [ 0u8; 4 ];
                assert!(try!(self.reader.read(&mut buf)) == 4);
                Ok(unsafe { mem::transmute(buf) } )
            }
        }
    }

    pub fn open<P: AsPath>(path: &P) -> Result<AVSFile, Error> {
        let mut reader = BufReader::new(try!(File::open(path)));

        let mut ndim: Option<usize> = None;
        let mut sizes = Vec::<Option<usize>>::new();
        let mut data_type: Option<DataType> = None;
        let mut field_type: Option<FieldType> = None;
        let mut external: Option<String> = None;

        let mut line = String::new();
        let mut last_char: u8 = 0;
        loop {
            let mut new_char_buf: [u8;1] = [ 0u8 ];
            try!(reader.read(&mut new_char_buf));

            // break on two chr 14s
            let new_char = new_char_buf[0];
            if (new_char, last_char) == (14u8, 14u8) {
                break;
            }
            last_char = new_char;

            line.push(new_char as char);

            // new line; process the line and discard
            if new_char == 10 {
                let tokens: Vec<&str> = line.split('=')
                    .map(|s| s.trim()).collect();
                match &tokens[] {
                    ["ndim", s] => {
                        let nd = try!(s.parse::<usize>());
                        ndim = Some(nd);
                        for _ in 0..nd {
                            sizes.push(None);
                        }
                    },
                    ["dim1", s] => sizes[0] = Some(try!(s.parse::<usize>())),
                    ["dim2", s] => sizes[1] = Some(try!(s.parse::<usize>())),
                    ["dim3", s] => sizes[2] = Some(try!(s.parse::<usize>())),
                    ["dim4", s] => sizes[2] = Some(try!(s.parse::<usize>())),
                    ["dim5", s] => sizes[2] = Some(try!(s.parse::<usize>())),
                    ["dim6", s] => sizes[2] = Some(try!(s.parse::<usize>())),
                    ["dim7", s] => sizes[2] = Some(try!(s.parse::<usize>())),
                    ["data", s] =>
                        data_type = Some(try!(DataType::from_str(s))),
                    ["field", s] =>
                        field_type = Some(try!(FieldType::from_str(s))),
                    ["variable 1 file", s] =>
                        external = Some(String::from_str(s)),
                    _ => {}
                }
            }
            // hack?  code smell?  need borrow in previous block to expire
            if new_char == 10 {
                line.clear();
            }
        }

        match external {
            None => {
                let mut tr = AVSFile {
                    ndim: try!(ndim.ok_or(Error::MalformedError)),
                    sizes: Vec::<usize>::new(),
                    data_type: try!(data_type.ok_or(Error::MalformedError)),
                    field_type: try!(field_type.ok_or(Error::MalformedError)),
                    reader: Box::new(reader),
                };
                for idx in 0..ndim.unwrap() {
                    tr.sizes.push(
                        try!(sizes[idx].ok_or(Error::MalformedError)));
                }
                Ok(tr)
            },
            Some(path) => {
                let new_reader = BufReader::new(try!(File::open(&path)));
                let mut tr = AVSFile {
                    ndim: try!(ndim.ok_or(Error::MalformedError)),
                    sizes: Vec::<usize>::new(),
                    data_type: try!(data_type.ok_or(Error::MalformedError)),
                    field_type: try!(field_type.ok_or(Error::MalformedError)),
                    reader: Box::new(new_reader),
                };
                for idx in 0..ndim.unwrap() {
                    tr.sizes.push(
                        try!(sizes[idx].ok_or(Error::MalformedError)));
                }
                Ok(tr)
            },
        }
    }
}

<commit_msg>reading is a lot quicker now<commit_after>#![feature(io)]
#![feature(path)]
#![feature(fs)]
#![feature(collections)]
#![feature(core)]

use std::fs::{File};
use std::string::String;
use std::str::StrExt;
use std::path::AsPath;
use std::error::FromError;
use std::io::{Read, BufReader};
use std::vec::Vec;
use std::num::ParseIntError;
use std::mem;

pub enum Error {
    IO,
    Parse,
    DataType,
    FieldType,
    Malformed,
    NotImplemented
}

impl FromError<std::io::Error> for Error {
    fn from_error(_: std::io::Error) -> Error {
        Error::IO
    }
}

impl FromError<ParseIntError> for Error {
    fn from_error(_: ParseIntError) -> Error {
        Error::Parse
    }
}

pub enum DataType {
    XDRFloat,
    FloatLE,
}

impl DataType {
    fn from_str(s: &str) -> Result<DataType, Error> {
        match s {
            "float_le" => Ok(DataType::FloatLE),
            "xdr_float" => Ok(DataType::XDRFloat),
            _ => Err(Error::DataType)
        }
    }
}

pub enum FieldType {
    Uniform
}

impl FieldType {
    fn from_str(s: &str) -> Result<FieldType, Error> {
        match s {
            "uniform" => Ok(FieldType::Uniform),
            _ => Err(Error::FieldType)
        }
    }
}

pub struct AVSFile<'a> {
    pub ndim: usize,
    pub sizes: Vec<usize>,
    pub data_type: DataType,
    pub field_type: FieldType,
    reader: Box<Read + 'a>
}

impl<'a> AVSFile<'a> {
    pub fn read_f32(self: &mut Self) -> Result<f32, Error> {
        match self.data_type {
            DataType::XDRFloat => {
                let mut buf = [ 0u8; 4 ];
                let mut read : usize = 0;
                loop {
                    read += try!(self.reader.read(&mut buf[read .. 4]));
                    if read == 4 { break; }
                }
                (&mut buf).reverse();
                Ok(unsafe { mem::transmute(buf) } )
            }
            DataType::FloatLE => {
                let mut buf = [ 0u8; 4 ];
                let mut read : usize = 0;
                loop {
                    read += try!(self.reader.read(&mut buf[read .. 4]));
                    if read == 4 { break; }
                }
                Ok(unsafe { mem::transmute(buf) } )
            }
        }
    }

    pub fn read_all<T>(self: &mut Self) -> Result<Box<[T]>, Error> {
        let size = self.sizes.iter().fold(1 as usize, |l, r| l * *r);
        let mut buf_u8 = Vec::<u8>::with_capacity(mem::size_of::<T>()*size);
        try!(self.reader.read_to_end(&mut buf_u8));
        let buf: Vec<T> = unsafe { mem::transmute(buf_u8) };
        Ok(buf.into_boxed_slice())
    }

    pub fn open<P: AsPath>(path: &P) -> Result<AVSFile, Error> {
        let mut reader = BufReader::new(try!(File::open(path)));

        let mut ndim: Option<usize> = None;
        let mut sizes = Vec::<Option<usize>>::new();
        let mut data_type: Option<DataType> = None;
        let mut field_type: Option<FieldType> = None;
        let mut external: Option<String> = None;

        let mut line = String::new();
        let mut last_char: u8 = 0;
        loop {
            let mut new_char_buf: [u8;1] = [ 0u8 ];
            try!(reader.read(&mut new_char_buf));

            // break on two chr 14s
            let new_char = new_char_buf[0];
            if (new_char, last_char) == (12u8, 12u8) {
                break;
            }
            last_char = new_char;

            line.push(new_char as char);

            // new line; process the line and discard
            if new_char == 10 {
                let tokens: Vec<&str> = line.split('=')
                    .map(|s| s.trim()).collect();
                match &tokens[] {
                    ["ndim", s] => {
                        let nd = try!(s.parse::<usize>());
                        ndim = Some(nd);
                        for _ in 0..nd {
                            sizes.push(None);
                        }
                    },
                    ["dim1", s] => sizes[0] = Some(try!(s.parse::<usize>())),
                    ["dim2", s] => sizes[1] = Some(try!(s.parse::<usize>())),
                    ["dim3", s] => sizes[2] = Some(try!(s.parse::<usize>())),
                    ["dim4", s] => sizes[2] = Some(try!(s.parse::<usize>())),
                    ["dim5", s] => sizes[2] = Some(try!(s.parse::<usize>())),
                    ["dim6", s] => sizes[2] = Some(try!(s.parse::<usize>())),
                    ["dim7", s] => sizes[2] = Some(try!(s.parse::<usize>())),
                    ["data", s] =>
                        data_type = Some(try!(DataType::from_str(s))),
                    ["field", s] =>
                        field_type = Some(try!(FieldType::from_str(s))),
                    ["variable 1 file", s] =>
                        external = Some(String::from_str(s)),
                    _ => {}
                }
            }
            // hack?  code smell?  need borrow in previous block to expire
            if new_char == 10 {
                line.clear();
            }
        }

        match external {
            None => {
                let mut tr = AVSFile {
                    ndim: try!(ndim.ok_or(Error::Malformed)),
                    sizes: Vec::<usize>::new(),
                    data_type: try!(data_type.ok_or(Error::Malformed)),
                    field_type: try!(field_type.ok_or(Error::Malformed)),
                    reader: Box::new(reader),
                };
                for idx in 0..ndim.unwrap() {
                    tr.sizes.push(
                        try!(sizes[idx].ok_or(Error::Malformed)));
                }
                Ok(tr)
            },
            Some(path) => {
                let new_reader = BufReader::new(try!(File::open(&path)));
                let mut tr = AVSFile {
                    ndim: try!(ndim.ok_or(Error::Malformed)),
                    sizes: Vec::<usize>::new(),
                    data_type: try!(data_type.ok_or(Error::Malformed)),
                    field_type: try!(field_type.ok_or(Error::Malformed)),
                    reader: Box::new(new_reader),
                };
                for idx in 0..ndim.unwrap() {
                    tr.sizes.push(
                        try!(sizes[idx].ok_or(Error::Malformed)));
                }
                Ok(tr)
            },
        }
    }
}

<|endoftext|>


<commit_before>//! A wrapper around the uchardet library.  Detects character encodings.
//!
//! Note that the underlying implemention is written in C and C++, and I'm
//! not aware of any security audits which have been performed against it.
//!
//! For more information, see [this project on
//! GitHub](https://github.com/emk/rust-uchardet).

#![license = "Public domain (Unlicense)"]
#![unstable]
#![deny(missing_docs)]

extern crate libc;
extern crate "uchardet-sys" as ffi;

use libc::size_t;
use std::error::Error;
use std::result::Result;
use std::c_str::CString;

/// An error occurred while trying to detect the character encoding.
#[unstable = "Needs review"]
#[deriving(Show)]
pub struct EncodingDetectionError {
    message: String
}

#[unstable = "Needs review"]
impl Error for EncodingDetectionError {
    fn description(&self) -> &str { "encoding detection error" }
    fn detail(&self) -> Option<String> { Some(self.message.clone()) }
    fn cause(&self) -> Option<&Error> { None }
}

/// Either a return value, or an encoding detection error.
#[unstable = "Needs review"]
pub type EncodingDetectionResult<T> = Result<T, EncodingDetectionError>;

/// Detects the encoding of text using the uchardet library.
#[unstable = "Needs review"]
pub struct EncodingDetector {
    ptr: ffi::uchardet_t
}

impl EncodingDetector {
    /// Return the name of the charset used in `data`, or `None` if the
    /// charset is ASCII or if the encoding can't be detected. (Yes, this
    /// API is weird, and we may offer a better alternative in the future.)
    ///
    /// ```
    /// use uchardet::EncodingDetector;
    ///
    /// assert_eq!(None, EncodingDetector::detect("ascii".as_bytes()).unwrap());
    /// assert_eq!(Some("UTF-8".to_string()),
    ///            EncodingDetector::detect("français".as_bytes()).unwrap());
    /// assert_eq!(Some("windows-1252".to_string()),
    ///            EncodingDetector::detect(&[0x66u8, 0x72, 0x61, 0x6e, 0xe7,
    ///                                       0x61, 0x69, 0x73]).unwrap());
    /// ```
    #[unstable = "Needs review"]
    pub fn detect(data: &[u8]) -> EncodingDetectionResult<Option<String>> {
        let mut detector = EncodingDetector::new();
        try!(detector.handle_data(data));
        detector.data_end();
        Ok(detector.charset())
    }

    /// Create a new EncodingDetector.
    #[unstable = "Needs review"]
    pub fn new() -> EncodingDetector {
        let ptr = unsafe { ffi::uchardet_new() };
        assert!(ptr.is_not_null());
        EncodingDetector{ptr: ptr}
    }

    /// Pass a chunk of raw bytes to the detector.  This is a no-op if a
    /// charset has been detected.
    #[unstable = "The underlying API is poorly documented."]
    pub fn handle_data(&mut self, data: &[u8]) -> EncodingDetectionResult<()> {
        let result = unsafe {
            ffi::uchardet_handle_data(self.ptr, data.as_ptr() as *const i8,
                                      data.len() as size_t)
        };
        match result {
            0 => Ok(()),
            _ => {
                let msg =  "Error handling data".to_string();
                Err(EncodingDetectionError{message: msg})
            }
        }
    }

    /// Notify the detector that we're done calling `handle_data`, and that
    /// we want it to make a guess as to our encoding.  This is a no-op if
    /// no data has been passed yet, or if an encoding has been detected
    /// for certain.  From reading the code, it appears that you can safely
    /// call `handle_data` after calling this, but I'm not certain.
    #[unstable = "The underlying API is poorly documented."]
    pub fn data_end(&mut self) {
        unsafe { ffi::uchardet_data_end(self.ptr); }
    }

    /// Reset the detector's internal state.
    #[unstable = "The underlying API is poorly documented."]
    pub fn reset(&mut self) {
        unsafe { ffi::uchardet_reset(self.ptr); }
    }

    /// Get the decoder's current best guess as to the encoding.  Returns
    /// `None` on error, or if the data appears to be ASCII.
    #[unstable = "The underlying API is poorly documented."]
    pub fn charset(&self) -> Option<String> {
        unsafe {
            let internal_str = ffi::uchardet_get_charset(self.ptr);
            assert!(internal_str.is_not_null());
            let c_str = CString::new(internal_str, false);
            match c_str.as_str() {
                None =>
                    panic!("uchardet_get_charset returned invalid value"),
                Some("") => None,
                Some(encoding) => Some(encoding.to_string())
            }
        }
    }
}

#[unstable = "Needs review"]
impl Drop for EncodingDetector {
    fn drop(&mut self) {
        unsafe { ffi::uchardet_delete(self.ptr) };
    }
}
<commit_msg>Rename error types<commit_after>//! A wrapper around the uchardet library.  Detects character encodings.
//!
//! Note that the underlying implemention is written in C and C++, and I'm
//! not aware of any security audits which have been performed against it.
//!
//! For more information, see [this project on
//! GitHub](https://github.com/emk/rust-uchardet).

#![license = "Public domain (Unlicense)"]
#![unstable]
#![deny(missing_docs)]

extern crate libc;
extern crate "uchardet-sys" as ffi;

use libc::size_t;
use std::error::Error;
use std::result::Result;
use std::c_str::CString;

/// An error occurred while trying to detect the character encoding.
#[unstable = "Needs review"]
#[deriving(Show)]
pub struct EncodingDetectorError {
    message: String
}

#[unstable = "Needs review"]
impl Error for EncodingDetectorError {
    fn description(&self) -> &str { "encoding detector error" }
    fn detail(&self) -> Option<String> { Some(self.message.clone()) }
    fn cause(&self) -> Option<&Error> { None }
}

/// Either a return value, or an encoding detection error.
#[unstable = "Needs review"]
pub type EncodingDetectorResult<T> = Result<T, EncodingDetectorError>;

/// Detects the encoding of text using the uchardet library.
#[unstable = "Needs review"]
pub struct EncodingDetector {
    ptr: ffi::uchardet_t
}

impl EncodingDetector {
    /// Return the name of the charset used in `data`, or `None` if the
    /// charset is ASCII or if the encoding can't be detected. (Yes, this
    /// API is weird, and we may offer a better alternative in the future.)
    ///
    /// ```
    /// use uchardet::EncodingDetector;
    ///
    /// assert_eq!(None, EncodingDetector::detect("ascii".as_bytes()).unwrap());
    /// assert_eq!(Some("UTF-8".to_string()),
    ///            EncodingDetector::detect("français".as_bytes()).unwrap());
    /// assert_eq!(Some("windows-1252".to_string()),
    ///            EncodingDetector::detect(&[0x66u8, 0x72, 0x61, 0x6e, 0xe7,
    ///                                       0x61, 0x69, 0x73]).unwrap());
    /// ```
    #[unstable = "Needs review"]
    pub fn detect(data: &[u8]) -> EncodingDetectorResult<Option<String>> {
        let mut detector = EncodingDetector::new();
        try!(detector.handle_data(data));
        detector.data_end();
        Ok(detector.charset())
    }

    /// Create a new EncodingDetector.
    #[unstable = "Needs review"]
    pub fn new() -> EncodingDetector {
        let ptr = unsafe { ffi::uchardet_new() };
        assert!(ptr.is_not_null());
        EncodingDetector{ptr: ptr}
    }

    /// Pass a chunk of raw bytes to the detector.  This is a no-op if a
    /// charset has been detected.
    #[unstable = "The underlying API is poorly documented."]
    pub fn handle_data(&mut self, data: &[u8]) -> EncodingDetectorResult<()> {
        let result = unsafe {
            ffi::uchardet_handle_data(self.ptr, data.as_ptr() as *const i8,
                                      data.len() as size_t)
        };
        match result {
            0 => Ok(()),
            _ => {
                let msg =  "Error handling data".to_string();
                Err(EncodingDetectorError{message: msg})
            }
        }
    }

    /// Notify the detector that we're done calling `handle_data`, and that
    /// we want it to make a guess as to our encoding.  This is a no-op if
    /// no data has been passed yet, or if an encoding has been detected
    /// for certain.  From reading the code, it appears that you can safely
    /// call `handle_data` after calling this, but I'm not certain.
    #[unstable = "The underlying API is poorly documented."]
    pub fn data_end(&mut self) {
        unsafe { ffi::uchardet_data_end(self.ptr); }
    }

    /// Reset the detector's internal state.
    #[unstable = "The underlying API is poorly documented."]
    pub fn reset(&mut self) {
        unsafe { ffi::uchardet_reset(self.ptr); }
    }

    /// Get the decoder's current best guess as to the encoding.  Returns
    /// `None` on error, or if the data appears to be ASCII.
    #[unstable = "The underlying API is poorly documented."]
    pub fn charset(&self) -> Option<String> {
        unsafe {
            let internal_str = ffi::uchardet_get_charset(self.ptr);
            assert!(internal_str.is_not_null());
            let c_str = CString::new(internal_str, false);
            match c_str.as_str() {
                None =>
                    panic!("uchardet_get_charset returned invalid value"),
                Some("") => None,
                Some(encoding) => Some(encoding.to_string())
            }
        }
    }
}

#[unstable = "Needs review"]
impl Drop for EncodingDetector {
    fn drop(&mut self) {
        unsafe { ffi::uchardet_delete(self.ptr) };
    }
}
<|endoftext|>


<commit_before>// XXX: Use a ref-counted gene Pool.
// A population is then only a collection of pool item ids.
// This prevents from duplicating potential large genes.
//
// Use typing to make sure that individuals are evaluated when required.
// fn evaluate(self, evaluator) -> EvaluatedPopulation
// fn add(self, ind) -> Population

#![feature(num_bits_bytes)]
extern crate bit_vec;
extern crate rand;
use rand::{Rng, Rand};
use std::cmp::PartialOrd;

pub mod bit_string;

/// A probability is a value in the range [0.0, 1.0].
/// A probability of 1.0 means `always`, that of 0.0
/// means `never`.
#[derive(Copy, Clone, Debug)]
pub struct Probability(f32);

impl Probability {
    #[inline]
    pub fn new(pb: f32) -> Probability {
        assert!(pb >= 0.0 && pb <= 1.0);
        Probability(pb)
    }
}

impl std::ops::Add<Probability> for Probability {
    type Output = Probability;
    #[inline]
    fn add(self, rhs: Probability) -> Probability {
        Probability::new(self.0 + rhs.0)
    }
}

/// A probability value is a random value in the
/// range [0.0, 1.0).
#[derive(Copy, Clone, Debug)]
pub struct ProbabilityValue(f32);

impl Rand for ProbabilityValue {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> ProbabilityValue {
        let val = rng.gen::<f32>();
        assert!(val >= 0.0 && val < 1.0);
        ProbabilityValue(val)
    }
}

impl ProbabilityValue {
    pub fn is_probable_with(self, pb: Probability) -> bool {
        self.0 < pb.0
    }
}

/// Represents a fitness value.
pub trait Fitness: Clone {
    fn fitter_than(&self, other: &Self) -> bool;
}

/// Maximizes the fitness value as objective.
#[derive(Copy, Clone, Debug)]
pub struct MaxFitness<T:PartialOrd+Clone>(pub T);
impl<T:PartialOrd+Clone> Fitness for MaxFitness<T> {
    fn fitter_than(&self, other: &MaxFitness<T>) -> bool {
        self.0 > other.0
    }
}

/// Minimizes the fitness value as objective.
#[derive(Copy, Clone, Debug)]
pub struct MinFitness<T:PartialOrd+Clone>(pub T);
impl<T:PartialOrd+Clone> Fitness for MinFitness<T> {
    fn fitter_than(&self, other: &MinFitness<T>) -> bool {
        self.0 < other.0
    }
}

/// Represents an individual in a Population.
pub trait Individual: Clone {
}

/// Evaluates the fitness of an Individual.
pub trait Evaluator<I:Individual, F:Fitness> {
    fn fitness(&self, individual: &I) -> F;
}

/// Caches the `fitness` value for an individual.
#[derive(Clone, Debug)]
pub struct EvaluatedIndividual<I:Individual, F:Fitness> {
    individual: I,
    fitness: Option<F>,
}

impl<I:Individual, F:Fitness>  EvaluatedIndividual<I,F> {
    pub fn new(ind: I) -> EvaluatedIndividual<I,F> {
        EvaluatedIndividual{individual: ind, fitness: None}
    }
    pub fn fitness(&self) -> Option<F> {
        self.fitness.clone()
    }
    pub fn individual<'a>(&'a self) -> &'a I {
        &self.individual
    }
}

/// Manages a population of individuals.
#[derive(Clone, Debug)]
pub struct Population<I:Individual, F:Fitness> {
    population: Vec<EvaluatedIndividual<I,F>>
}

impl<I:Individual, F:Fitness> Population<I,F> {
    pub fn new() -> Population<I,F> {
        Population{population: Vec::new()}
    }

    pub fn with_capacity(capa: usize) -> Population<I,F> {
        Population{population: Vec::with_capacity(capa)}
    }

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

    /// Return individual with best fitness.
    pub fn fittest(&self) -> Option<(usize, F)> {
        let mut fittest: Option<(usize, F)> = None;

        for (i, ref ind) in self.population.iter().enumerate() {
            if let Some(ref f) = ind.fitness {
                let mut is_better = true;
                if let Some((_, ref best_f)) = fittest {
                    if !f.fitter_than(best_f) {
                        is_better = false;
                    }
                }
                if is_better {
                    fittest = Some((i, f.clone()));
                }
            }
        }
        return fittest;
    }

    pub fn get_ref<'a>(&'a self, idx: usize) -> &'a EvaluatedIndividual<I, F> {
        &self.population[idx]
    }

    pub fn add_individual(&mut self, ind: I) {
        self.population.push(EvaluatedIndividual::new(ind));
    }

    pub fn add(&mut self, ind: EvaluatedIndividual<I,F>) {
        self.population.push(ind);
    }

    /// Evaluates the whole population, i.e. determines the fitness of
    /// each `individual` (unless already calculated).
    /// Returns the number of evaluations performed.
    pub fn evaluate<E>(&mut self, evaluator: &E) -> usize where E:Evaluator<I,F> {
        let mut nevals = 0;
        for i in self.population.iter_mut() {
            if i.fitness.is_some() { continue; }
            i.fitness = Some(evaluator.fitness(&i.individual));
            nevals += 1;
        }
        return nevals;
    }

    fn add_population(&mut self, p: &Population<I,F>) {
        for ind in p.population.iter() {
            self.add(ind.clone());
        }
    }
}

/// Select the best individual out of `k` randomly choosen.
/// This gives individuals with better fitness a higher chance to reproduce.
/// `n` is the total number of individuals.
///
/// NOTE: We are not using `sample(rng, 0..n, k)` as it is *very* expensive.
/// Instead we call `rng.gen_range()` k-times. The drawn items could be the same,
/// but the probability is very low if `n` high compared to `k`.
pub fn tournament_selection<R:Rng, F, E>(rng: &mut R, evaluate: E, n: usize, k: usize) -> Option<(usize, F)>
  where F:Fitness,
        E:Fn(usize) -> F {
    assert!(n >= k);

    let mut best: Option<(usize, F)> = None;

    for _ in 0..k {
        let i = rng.gen_range(0, n);
        let fitness = evaluate(i);
        let better = match best {
            Some((_, ref current_best_fitness)) => {
                fitness.fitter_than(current_best_fitness)
            }
            None => { true }
       };
       if better {
           best = Some((i, fitness));
       }
    }
    return best;
}

pub enum VariationMethod {
    Crossover,
    Mutation,
    Reproduction,
}

/// Mates two individual, producing two children.
pub trait OpCrossover<I: Individual> {
    fn crossover(&mut self, parent1: &I, parent2: &I) -> (I, I);
}

/// Mutates an individual.
pub trait OpMutate<I: Individual> {
    fn mutate(&mut self, ind: &I) -> I;
}

/// Selects a variation method to use.
pub trait OpVariation {
    fn variation(&mut self) -> VariationMethod;
}

/// Selects a random individual from the population.
pub trait OpSelectRandomIndividual<I: Individual, F: Fitness> {
    fn select_random_individual<'a>(&mut self, population: &'a Population<I, F>) -> &'a EvaluatedIndividual<I, F>;
}

/// Produce new generation through selection of \mu individuals from population.
pub trait OpSelect<I: Individual, F: Fitness> {
    fn select(&mut self, population: &Population<I,F>, mu: usize) -> Population<I,F>;
}

pub fn variation_or<I, F, T>(toolbox: &mut T, population: &Population<I,F>, lambda: usize) -> Population<I,F>
where I: Individual,
      F: Fitness,
      T: OpCrossover<I> + OpMutate<I> + OpVariation + OpSelectRandomIndividual<I,F>
{
    let mut offspring = Population::with_capacity(lambda);
    // Each step produces exactly one child.
    for _ in 0..lambda {
        let method = toolbox.variation();
        let child = match method {
            VariationMethod::Crossover => {
                // select two individuals and mate them.
                // only the first offspring is used, the second is thrown away.
                let parent1 = toolbox.select_random_individual(population);
                let parent2 = toolbox.select_random_individual(population);
                let (child1, _child2) = toolbox.crossover(&parent1.individual, &parent2.individual);
                EvaluatedIndividual::new(child1)
            }
            VariationMethod::Mutation => {
                // select a single individual and mutate it.
                let ind = toolbox.select_random_individual(population);
                let child = toolbox.mutate(&ind.individual);
                EvaluatedIndividual::new(child)
            }
            VariationMethod::Reproduction => {
                let ind = toolbox.select_random_individual(population);
                ind.clone()
            }
        };
        offspring.add(child);
    }
    return offspring;
}

// The (\mu + \lambda) algorithm.
// From `population`, \lambda offspring is produced, through either
// mutation, crossover or random reproduction.
// For the next generation, \mu individuals are selected from the \mu + \lambda (parents and offspring).
pub fn ea_mu_plus_lambda<I,F,T,E,S>(toolbox: &mut T, evaluator: &E, population: &Population<I,F>, mu: usize, lambda: usize, num_generations: usize, stat: S)
    -> Population<I,F>
where I: Individual,
      F: Fitness,
      T: OpCrossover<I> + OpMutate<I> + OpVariation + OpSelectRandomIndividual<I,F> + OpSelect<I,F>,
      E: Evaluator<I,F>,
      S: Fn(usize, &Population<I,F>)
{
    let mut nevals = 0;
    let mut p = population.clone();
    nevals += p.evaluate(evaluator);
    stat(0, &p);

    for gen in 0..num_generations {
        // evaluate population. make sure that every individual has been rated.
        let mut offspring = variation_or(toolbox, &p, lambda);
        offspring.add_population(&p);
        nevals += offspring.evaluate(evaluator);
        // select from offspring the `best` individuals
        p = toolbox.select(&offspring, mu);
        stat(gen+1, &p);
    }

    return p;
}
<commit_msg>Silence warning<commit_after>// XXX: Use a ref-counted gene Pool.
// A population is then only a collection of pool item ids.
// This prevents from duplicating potential large genes.
//
// Use typing to make sure that individuals are evaluated when required.
// fn evaluate(self, evaluator) -> EvaluatedPopulation
// fn add(self, ind) -> Population

#![feature(num_bits_bytes)]
extern crate bit_vec;
extern crate rand;
use rand::{Rng, Rand};
use std::cmp::PartialOrd;

pub mod bit_string;

/// A probability is a value in the range [0.0, 1.0].
/// A probability of 1.0 means `always`, that of 0.0
/// means `never`.
#[derive(Copy, Clone, Debug)]
pub struct Probability(f32);

impl Probability {
    #[inline]
    pub fn new(pb: f32) -> Probability {
        assert!(pb >= 0.0 && pb <= 1.0);
        Probability(pb)
    }
}

impl std::ops::Add<Probability> for Probability {
    type Output = Probability;
    #[inline]
    fn add(self, rhs: Probability) -> Probability {
        Probability::new(self.0 + rhs.0)
    }
}

/// A probability value is a random value in the
/// range [0.0, 1.0).
#[derive(Copy, Clone, Debug)]
pub struct ProbabilityValue(f32);

impl Rand for ProbabilityValue {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> ProbabilityValue {
        let val = rng.gen::<f32>();
        assert!(val >= 0.0 && val < 1.0);
        ProbabilityValue(val)
    }
}

impl ProbabilityValue {
    pub fn is_probable_with(self, pb: Probability) -> bool {
        self.0 < pb.0
    }
}

/// Represents a fitness value.
pub trait Fitness: Clone {
    fn fitter_than(&self, other: &Self) -> bool;
}

/// Maximizes the fitness value as objective.
#[derive(Copy, Clone, Debug)]
pub struct MaxFitness<T:PartialOrd+Clone>(pub T);
impl<T:PartialOrd+Clone> Fitness for MaxFitness<T> {
    fn fitter_than(&self, other: &MaxFitness<T>) -> bool {
        self.0 > other.0
    }
}

/// Minimizes the fitness value as objective.
#[derive(Copy, Clone, Debug)]
pub struct MinFitness<T:PartialOrd+Clone>(pub T);
impl<T:PartialOrd+Clone> Fitness for MinFitness<T> {
    fn fitter_than(&self, other: &MinFitness<T>) -> bool {
        self.0 < other.0
    }
}

/// Represents an individual in a Population.
pub trait Individual: Clone {
}

/// Evaluates the fitness of an Individual.
pub trait Evaluator<I:Individual, F:Fitness> {
    fn fitness(&self, individual: &I) -> F;
}

/// Caches the `fitness` value for an individual.
#[derive(Clone, Debug)]
pub struct EvaluatedIndividual<I:Individual, F:Fitness> {
    individual: I,
    fitness: Option<F>,
}

impl<I:Individual, F:Fitness>  EvaluatedIndividual<I,F> {
    pub fn new(ind: I) -> EvaluatedIndividual<I,F> {
        EvaluatedIndividual{individual: ind, fitness: None}
    }
    pub fn fitness(&self) -> Option<F> {
        self.fitness.clone()
    }
    pub fn individual<'a>(&'a self) -> &'a I {
        &self.individual
    }
}

/// Manages a population of individuals.
#[derive(Clone, Debug)]
pub struct Population<I:Individual, F:Fitness> {
    population: Vec<EvaluatedIndividual<I,F>>
}

impl<I:Individual, F:Fitness> Population<I,F> {
    pub fn new() -> Population<I,F> {
        Population{population: Vec::new()}
    }

    pub fn with_capacity(capa: usize) -> Population<I,F> {
        Population{population: Vec::with_capacity(capa)}
    }

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

    /// Return individual with best fitness.
    pub fn fittest(&self) -> Option<(usize, F)> {
        let mut fittest: Option<(usize, F)> = None;

        for (i, ref ind) in self.population.iter().enumerate() {
            if let Some(ref f) = ind.fitness {
                let mut is_better = true;
                if let Some((_, ref best_f)) = fittest {
                    if !f.fitter_than(best_f) {
                        is_better = false;
                    }
                }
                if is_better {
                    fittest = Some((i, f.clone()));
                }
            }
        }
        return fittest;
    }

    pub fn get_ref<'a>(&'a self, idx: usize) -> &'a EvaluatedIndividual<I, F> {
        &self.population[idx]
    }

    pub fn add_individual(&mut self, ind: I) {
        self.population.push(EvaluatedIndividual::new(ind));
    }

    pub fn add(&mut self, ind: EvaluatedIndividual<I,F>) {
        self.population.push(ind);
    }

    /// Evaluates the whole population, i.e. determines the fitness of
    /// each `individual` (unless already calculated).
    /// Returns the number of evaluations performed.
    pub fn evaluate<E>(&mut self, evaluator: &E) -> usize where E:Evaluator<I,F> {
        let mut nevals = 0;
        for i in self.population.iter_mut() {
            if i.fitness.is_some() { continue; }
            i.fitness = Some(evaluator.fitness(&i.individual));
            nevals += 1;
        }
        return nevals;
    }

    fn add_population(&mut self, p: &Population<I,F>) {
        for ind in p.population.iter() {
            self.add(ind.clone());
        }
    }
}

/// Select the best individual out of `k` randomly choosen.
/// This gives individuals with better fitness a higher chance to reproduce.
/// `n` is the total number of individuals.
///
/// NOTE: We are not using `sample(rng, 0..n, k)` as it is *very* expensive.
/// Instead we call `rng.gen_range()` k-times. The drawn items could be the same,
/// but the probability is very low if `n` high compared to `k`.
pub fn tournament_selection<R:Rng, F, E>(rng: &mut R, evaluate: E, n: usize, k: usize) -> Option<(usize, F)>
  where F:Fitness,
        E:Fn(usize) -> F {
    assert!(n >= k);

    let mut best: Option<(usize, F)> = None;

    for _ in 0..k {
        let i = rng.gen_range(0, n);
        let fitness = evaluate(i);
        let better = match best {
            Some((_, ref current_best_fitness)) => {
                fitness.fitter_than(current_best_fitness)
            }
            None => { true }
       };
       if better {
           best = Some((i, fitness));
       }
    }
    return best;
}

pub enum VariationMethod {
    Crossover,
    Mutation,
    Reproduction,
}

/// Mates two individual, producing two children.
pub trait OpCrossover<I: Individual> {
    fn crossover(&mut self, parent1: &I, parent2: &I) -> (I, I);
}

/// Mutates an individual.
pub trait OpMutate<I: Individual> {
    fn mutate(&mut self, ind: &I) -> I;
}

/// Selects a variation method to use.
pub trait OpVariation {
    fn variation(&mut self) -> VariationMethod;
}

/// Selects a random individual from the population.
pub trait OpSelectRandomIndividual<I: Individual, F: Fitness> {
    fn select_random_individual<'a>(&mut self, population: &'a Population<I, F>) -> &'a EvaluatedIndividual<I, F>;
}

/// Produce new generation through selection of \mu individuals from population.
pub trait OpSelect<I: Individual, F: Fitness> {
    fn select(&mut self, population: &Population<I,F>, mu: usize) -> Population<I,F>;
}

pub fn variation_or<I, F, T>(toolbox: &mut T, population: &Population<I,F>, lambda: usize) -> Population<I,F>
where I: Individual,
      F: Fitness,
      T: OpCrossover<I> + OpMutate<I> + OpVariation + OpSelectRandomIndividual<I,F>
{
    let mut offspring = Population::with_capacity(lambda);
    // Each step produces exactly one child.
    for _ in 0..lambda {
        let method = toolbox.variation();
        let child = match method {
            VariationMethod::Crossover => {
                // select two individuals and mate them.
                // only the first offspring is used, the second is thrown away.
                let parent1 = toolbox.select_random_individual(population);
                let parent2 = toolbox.select_random_individual(population);
                let (child1, _child2) = toolbox.crossover(&parent1.individual, &parent2.individual);
                EvaluatedIndividual::new(child1)
            }
            VariationMethod::Mutation => {
                // select a single individual and mutate it.
                let ind = toolbox.select_random_individual(population);
                let child = toolbox.mutate(&ind.individual);
                EvaluatedIndividual::new(child)
            }
            VariationMethod::Reproduction => {
                let ind = toolbox.select_random_individual(population);
                ind.clone()
            }
        };
        offspring.add(child);
    }
    return offspring;
}

// The (\mu + \lambda) algorithm.
// From `population`, \lambda offspring is produced, through either
// mutation, crossover or random reproduction.
// For the next generation, \mu individuals are selected from the \mu + \lambda (parents and offspring).
pub fn ea_mu_plus_lambda<I,F,T,E,S>(toolbox: &mut T, evaluator: &E, population: &Population<I,F>, mu: usize, lambda: usize, num_generations: usize, stat: S)
    -> Population<I,F>
where I: Individual,
      F: Fitness,
      T: OpCrossover<I> + OpMutate<I> + OpVariation + OpSelectRandomIndividual<I,F> + OpSelect<I,F>,
      E: Evaluator<I,F>,
      S: Fn(usize, &Population<I,F>)
{
    let mut nevals = 0;
    let mut p = population.clone();
    nevals += p.evaluate(evaluator);
    stat(0, &p);

    for gen in 0..num_generations {
        // evaluate population. make sure that every individual has been rated.
        let mut offspring = variation_or(toolbox, &p, lambda);
        offspring.add_population(&p);
        nevals += offspring.evaluate(evaluator);
        // select from offspring the `best` individuals
        p = toolbox.select(&offspring, mu);
        stat(gen+1, &p);
    }

    let _ = nevals;

    return p;
}
<|endoftext|>


<commit_before>/// Df2 files are waveform files from an Optech LiDAR system.

extern crate byteorder;
extern crate rustc_serialize;

use byteorder::{LittleEndian, ReadBytesExt};
use std::fs::File;
use std::io::{self, BufReader, ErrorKind, Read, Seek, SeekFrom};
use std::path::Path;

/// Our custom error enum.
#[derive(Debug)]
pub enum Error {
    /// Shot has an invalid offset.
    InvalidOffset { shot_number: u16, offset: u16 },
    /// The shot number is invalid.
    InvalidShotNumber(u16),
    /// Wrapper around `std::io::Error`.
    Io(io::Error),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

/// Our custom result type.
pub type Result<T> = std::result::Result<T, Error>;

/// Reads df2 waveform data.
#[derive(Debug)]
pub struct Reader<R: Read> {
    reader: R,
}

impl Reader<BufReader<File>> {
    /// Opens a reader for the file at a path.
    ///
    /// # Examples
    ///
    /// ```
    /// use df2::Reader;
    /// let reader = Reader::from_path("data/one-shot.df2").unwrap();
    /// ```
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Reader<BufReader<File>>> {
        let file = BufReader::new(File::open(path)?);
        Ok(Reader { reader: file })
    }
}

impl<R: Read> Reader<R> {
    /// Reads one shot.
    ///
    /// # Examples
    ///
    /// ```
    /// # use df2::Reader;
    /// let mut reader = Reader::from_path("data/one-shot.df2").unwrap();
    /// let shot = reader.read_one().unwrap().unwrap();
    /// ```
    pub fn read_one(&mut self) -> Result<Option<Shot>> {
        // FIXME this isn't exactly correct, a spare byte could be allowed
        let number = match self.reader.read_u16::<LittleEndian>() {
            Ok(number) => number,
            Err(err) => {
                match err.kind() {
                    ErrorKind::UnexpectedEof => return Ok(None),
                    _ => return Err(err.into()),
                }
            }
        };
        let offset = self.reader.read_u16::<LittleEndian>()?;
        let mut bytes_remaining = offset * 2;
        let outgoing = Segment::from_read(&mut self.reader)?;
        bytes_remaining -= outgoing.len();
        let mut segments = Vec::new();
        while bytes_remaining > 0 {
            let segment = Segment::from_read(&mut self.reader)?;
            if segment.len() > bytes_remaining {
                return Err(Error::InvalidOffset {
                    shot_number: number,
                    offset: offset,
                });
            }
            bytes_remaining -= segment.len();
            segments.push(segment);
        }
        Ok(Some(Shot {
            number: number,
            outgoing: outgoing.data,
            segments: segments,
        }))
    }
}

impl<R: Read + Seek> Reader<R> {
    /// Seeks to the shot with the given number.
    ///
    /// Seeking to the n + 1 shot is not an error, but any shots after that *are* errors.
    ///
    /// # Examples
    ///
    /// ```
    /// # use df2::Reader;
    /// let mut reader = Reader::from_path("data/two-shots.df2").unwrap();
    /// assert!(reader.seek(0).is_err());
    /// assert!(reader.seek(1).is_ok());
    /// assert!(reader.seek(2).is_ok());
    /// assert!(reader.seek(3).is_ok());
    /// assert!(reader.seek(4).is_err());
    /// ```
    pub fn seek(&mut self, number: u16) -> Result<()> {
        if number == 0 {
            return Err(Error::InvalidShotNumber(number));
        }
        // TODO optimize by saving locations?
        self.reader.seek(SeekFrom::Start(2))?;
        let mut position: u64 = 2;
        let mut current = 1;
        while current < number {
            let offset = self.reader.read_u16::<LittleEndian>()? * 2 + 2;
            position += 2;
            let new_position = self.reader.seek(SeekFrom::Current(offset as i64))?;
            if new_position != position + offset as u64 {
                return Err(Error::InvalidShotNumber(number));
            }
            position += offset as u64;
            current += 1;
        }
        self.reader.seek(SeekFrom::Current(-2))?;
        Ok(())
    }
}

impl<R: Read> Iterator for Reader<R> {
    type Item = Result<Shot>;
    fn next(&mut self) -> Option<Result<Shot>> {
        match self.read_one() {
            Ok(option) => {
                match option {
                    Some(shot) => Some(Ok(shot)),
                    None => None,
                }
            }
            Err(err) => Some(Err(err)),
        }
    }
}

/// A laser shot.
#[derive(Debug, PartialEq, RustcEncodable)]
pub struct Shot {
    /// The shot number (one-indexed).
    pub number: u16,
    /// The outgoing laser pulse.
    pub outgoing: Vec<u16>,
    /// The waveform segments.
    pub segments: Vec<Segment>,
}

/// A waveform segment.
#[derive(Debug, PartialEq, RustcEncodable)]
pub struct Segment {
    /// The waveform samples.
    pub data: Vec<u16>,
    /// The time interval, in cycles.
    pub time_interval: u16,
}

impl Segment {
    /// Reads a Segment from a path.
    ///
    /// # Examples
    ///
    /// ```
    /// use df2::Segment;
    /// let segment = Segment::from_path("data/one-segment.bin").unwrap();
    /// ```
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Segment> {
        File::open(path)
            .map_err(|err| err.into())
            .and_then(|mut file| Segment::from_read(&mut file))
    }

    /// Reads a Segment from a `Read`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::File;
    /// use df2::Segment;
    /// let mut file = File::open("data/one-segment.bin").unwrap();
    /// let segment = Segment::from_read(&mut file).unwrap();
    /// ```
    pub fn from_read<R: Read>(read: &mut R) -> Result<Segment> {
        let nsamples = read.read_u16::<LittleEndian>()?;
        let data = (0..nsamples).map(|_| read.read_u16::<LittleEndian>().map_err(|err| err.into()))
            .collect::<Result<Vec<u16>>>()?;
        let time_interval = read.read_u16::<LittleEndian>()?;
        // reserved
        let _ = read.read_u16::<LittleEndian>()?;
        Ok(Segment {
            data: data,
            time_interval: time_interval,
        })
    }

    /// Returns the length of this segment in bytes.
    ///
    /// # Examples
    ///
    /// ```
    /// # use df2::Segment;
    /// let segment = Segment::from_path("data/one-segment.bin").unwrap();
    /// assert_eq!(110, segment.len());
    /// ```
    pub fn len(&self) -> u16 {
        self.data.len() as u16 * 2 + 6
    }

    /// Returns true if this segment has no data.
    ///
    /// # Examples
    ///
    /// ```
    /// # use df2::Segment;
    /// let segment = Segment { data: Vec::new(), time_interval: 0 };
    /// assert!(segment.is_empty());
    /// let segment = Segment::from_path("data/one-segment.bin").unwrap();
    /// assert!(!segment.is_empty());
    /// ```
    pub fn is_empty(&self) -> bool {
        self.data.is_empty()
    }
}

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

    #[test]
    fn reader_from_path() {
        assert!(Reader::from_path("data/one-shot.df2").is_ok());
    }

    #[test]
    fn reader_read_one() {
        let mut reader = Reader::from_path("data/one-shot.df2").unwrap();
        let shot = reader.read_one().unwrap().unwrap();
        assert_eq!(1, shot.number);
    }

    #[test]
    fn reader_iterator() {
        let shots: Vec<_> = Reader::from_path("data/one-shot.df2").unwrap().collect();
        assert_eq!(1, shots.len());
    }

    #[test]
    fn reader_seek_identical() {
        let shot_by_iter =
            Reader::from_path("data/two-shots.df2").unwrap().skip(1).next().unwrap().unwrap();
        let mut reader = Reader::from_path("data/two-shots.df2").unwrap();
        reader.seek(2).unwrap();
        let shot_by_seek = reader.read_one().unwrap().unwrap();
        assert_eq!(shot_by_iter, shot_by_seek);
    }

    #[test]
    fn reader_seek_skip_two() {
        let mut reader = Reader::from_path("data/four-shots.df2").unwrap();
        reader.seek(3).unwrap();
        assert_eq!(2, reader.collect::<Result<Vec<Shot>>>().unwrap().len());
    }

    #[test]
    fn segment_from_path() {
        assert!(Segment::from_path("data/one-segment.bin").is_ok());
    }

    #[test]
    fn segment_len() {
        let segment = Segment::from_path("data/one-segment.bin").unwrap();
        assert_eq!(110, segment.len());
    }
}
<commit_msg>Add lints<commit_after>/// Df2 files are waveform files from an Optech LiDAR system.
#[deny(missing_docs,
        missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unstable_features,
        unused_import_braces, unused_qualifications)]

extern crate byteorder;
extern crate rustc_serialize;

use byteorder::{LittleEndian, ReadBytesExt};
use std::fs::File;
use std::io::{self, BufReader, ErrorKind, Read, Seek, SeekFrom};
use std::path::Path;

/// Our custom error enum.
#[derive(Debug)]
pub enum Error {
    /// Shot has an invalid offset.
    InvalidOffset { shot_number: u16, offset: u16 },
    /// The shot number is invalid.
    InvalidShotNumber(u16),
    /// Wrapper around `std::io::Error`.
    Io(io::Error),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

/// Our custom result type.
pub type Result<T> = std::result::Result<T, Error>;

/// Reads df2 waveform data.
#[derive(Debug)]
pub struct Reader<R: Read> {
    reader: R,
}

impl Reader<BufReader<File>> {
    /// Opens a reader for the file at a path.
    ///
    /// # Examples
    ///
    /// ```
    /// use df2::Reader;
    /// let reader = Reader::from_path("data/one-shot.df2").unwrap();
    /// ```
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Reader<BufReader<File>>> {
        let file = BufReader::new(File::open(path)?);
        Ok(Reader { reader: file })
    }
}

impl<R: Read> Reader<R> {
    /// Reads one shot.
    ///
    /// # Examples
    ///
    /// ```
    /// # use df2::Reader;
    /// let mut reader = Reader::from_path("data/one-shot.df2").unwrap();
    /// let shot = reader.read_one().unwrap().unwrap();
    /// ```
    pub fn read_one(&mut self) -> Result<Option<Shot>> {
        // FIXME this isn't exactly correct, a spare byte could be allowed
        let number = match self.reader.read_u16::<LittleEndian>() {
            Ok(number) => number,
            Err(err) => {
                match err.kind() {
                    ErrorKind::UnexpectedEof => return Ok(None),
                    _ => return Err(err.into()),
                }
            }
        };
        let offset = self.reader.read_u16::<LittleEndian>()?;
        let mut bytes_remaining = offset * 2;
        let outgoing = Segment::from_read(&mut self.reader)?;
        bytes_remaining -= outgoing.len();
        let mut segments = Vec::new();
        while bytes_remaining > 0 {
            let segment = Segment::from_read(&mut self.reader)?;
            if segment.len() > bytes_remaining {
                return Err(Error::InvalidOffset {
                    shot_number: number,
                    offset: offset,
                });
            }
            bytes_remaining -= segment.len();
            segments.push(segment);
        }
        Ok(Some(Shot {
            number: number,
            outgoing: outgoing.data,
            segments: segments,
        }))
    }
}

impl<R: Read + Seek> Reader<R> {
    /// Seeks to the shot with the given number.
    ///
    /// Seeking to the n + 1 shot is not an error, but any shots after that *are* errors.
    ///
    /// # Examples
    ///
    /// ```
    /// # use df2::Reader;
    /// let mut reader = Reader::from_path("data/two-shots.df2").unwrap();
    /// assert!(reader.seek(0).is_err());
    /// assert!(reader.seek(1).is_ok());
    /// assert!(reader.seek(2).is_ok());
    /// assert!(reader.seek(3).is_ok());
    /// assert!(reader.seek(4).is_err());
    /// ```
    pub fn seek(&mut self, number: u16) -> Result<()> {
        if number == 0 {
            return Err(Error::InvalidShotNumber(number));
        }
        // TODO optimize by saving locations?
        self.reader.seek(SeekFrom::Start(2))?;
        let mut position: u64 = 2;
        let mut current = 1;
        while current < number {
            let offset = self.reader.read_u16::<LittleEndian>()? * 2 + 2;
            position += 2;
            let new_position = self.reader.seek(SeekFrom::Current(offset as i64))?;
            if new_position != position + offset as u64 {
                return Err(Error::InvalidShotNumber(number));
            }
            position += offset as u64;
            current += 1;
        }
        self.reader.seek(SeekFrom::Current(-2))?;
        Ok(())
    }
}

impl<R: Read> Iterator for Reader<R> {
    type Item = Result<Shot>;
    fn next(&mut self) -> Option<Result<Shot>> {
        match self.read_one() {
            Ok(option) => {
                match option {
                    Some(shot) => Some(Ok(shot)),
                    None => None,
                }
            }
            Err(err) => Some(Err(err)),
        }
    }
}

/// A laser shot.
#[derive(Debug, PartialEq, RustcEncodable)]
pub struct Shot {
    /// The shot number (one-indexed).
    pub number: u16,
    /// The outgoing laser pulse.
    pub outgoing: Vec<u16>,
    /// The waveform segments.
    pub segments: Vec<Segment>,
}

/// A waveform segment.
#[derive(Debug, PartialEq, RustcEncodable)]
pub struct Segment {
    /// The waveform samples.
    pub data: Vec<u16>,
    /// The time interval, in cycles.
    pub time_interval: u16,
}

impl Segment {
    /// Reads a Segment from a path.
    ///
    /// # Examples
    ///
    /// ```
    /// use df2::Segment;
    /// let segment = Segment::from_path("data/one-segment.bin").unwrap();
    /// ```
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Segment> {
        File::open(path)
            .map_err(|err| err.into())
            .and_then(|mut file| Segment::from_read(&mut file))
    }

    /// Reads a Segment from a `Read`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::File;
    /// use df2::Segment;
    /// let mut file = File::open("data/one-segment.bin").unwrap();
    /// let segment = Segment::from_read(&mut file).unwrap();
    /// ```
    pub fn from_read<R: Read>(read: &mut R) -> Result<Segment> {
        let nsamples = read.read_u16::<LittleEndian>()?;
        let data = (0..nsamples).map(|_| read.read_u16::<LittleEndian>().map_err(|err| err.into()))
            .collect::<Result<Vec<u16>>>()?;
        let time_interval = read.read_u16::<LittleEndian>()?;
        // reserved
        let _ = read.read_u16::<LittleEndian>()?;
        Ok(Segment {
            data: data,
            time_interval: time_interval,
        })
    }

    /// Returns the length of this segment in bytes.
    ///
    /// # Examples
    ///
    /// ```
    /// # use df2::Segment;
    /// let segment = Segment::from_path("data/one-segment.bin").unwrap();
    /// assert_eq!(110, segment.len());
    /// ```
    pub fn len(&self) -> u16 {
        self.data.len() as u16 * 2 + 6
    }

    /// Returns true if this segment has no data.
    ///
    /// # Examples
    ///
    /// ```
    /// # use df2::Segment;
    /// let segment = Segment { data: Vec::new(), time_interval: 0 };
    /// assert!(segment.is_empty());
    /// let segment = Segment::from_path("data/one-segment.bin").unwrap();
    /// assert!(!segment.is_empty());
    /// ```
    pub fn is_empty(&self) -> bool {
        self.data.is_empty()
    }
}

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

    #[test]
    fn reader_from_path() {
        assert!(Reader::from_path("data/one-shot.df2").is_ok());
    }

    #[test]
    fn reader_read_one() {
        let mut reader = Reader::from_path("data/one-shot.df2").unwrap();
        let shot = reader.read_one().unwrap().unwrap();
        assert_eq!(1, shot.number);
    }

    #[test]
    fn reader_iterator() {
        let shots: Vec<_> = Reader::from_path("data/one-shot.df2").unwrap().collect();
        assert_eq!(1, shots.len());
    }

    #[test]
    fn reader_seek_identical() {
        let shot_by_iter =
            Reader::from_path("data/two-shots.df2").unwrap().skip(1).next().unwrap().unwrap();
        let mut reader = Reader::from_path("data/two-shots.df2").unwrap();
        reader.seek(2).unwrap();
        let shot_by_seek = reader.read_one().unwrap().unwrap();
        assert_eq!(shot_by_iter, shot_by_seek);
    }

    #[test]
    fn reader_seek_skip_two() {
        let mut reader = Reader::from_path("data/four-shots.df2").unwrap();
        reader.seek(3).unwrap();
        assert_eq!(2, reader.collect::<Result<Vec<Shot>>>().unwrap().len());
    }

    #[test]
    fn segment_from_path() {
        assert!(Segment::from_path("data/one-segment.bin").is_ok());
    }

    #[test]
    fn segment_len() {
        let segment = Segment::from_path("data/one-segment.bin").unwrap();
        assert_eq!(110, segment.len());
    }
}
<|endoftext|>


<commit_before>#![feature(phase)]
extern crate regex;
#[phase(plugin)] extern crate regex_macros;
extern crate serialize;

use std::cell::RefCell;
use std::collections::HashMap;
use std::io::{BufferedReader, BufferedWriter, InvalidInput, IoError, IoResult, TcpStream};
use std::vec::Vec;
use conn::{Conn, Connection};
use data::{Config, IrcReader, IrcWriter, Message};

pub mod conn;
pub mod data;

pub trait Bot<'a> {
    fn send_nick(&self, nick: &str) -> IoResult<()>;
    fn send_user(&self, username: &str, real_name: &str) -> IoResult<()>;
    fn send_join(&self, chan: &str) -> IoResult<()>;
    fn send_mode(&self, chan: &str, mode: &str) -> IoResult<()>;
    fn send_topic(&self, chan: &str, topic: &str) -> IoResult<()>;
    fn send_invite(&self, person: &str, chan: &str) -> IoResult<()>;
    fn send_privmsg(&self, chan: &str, msg: &str) -> IoResult<()>;
    fn identify(&self) -> IoResult<()>;
    fn output(&mut self) -> IoResult<()>;
    fn config(&self) -> Config;
}

pub struct IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    pub conn: RefCell<Connection<T, U>>,
    pub config: Config,
    process: RefCell<|&IrcBot<T, U>, &str, &str, &[&str]|:'a -> IoResult<()>>,
    pub chanlists: HashMap<String, Vec<String>>,
}

impl<'a, T, U> IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    pub fn new(process: |&IrcBot<BufferedWriter<TcpStream>, TcpStream>, &str, &str, &[&str]|:'a -> IoResult<()>) -> IoResult<IrcBot<'a, BufferedWriter<TcpStream>, TcpStream>> {
        let config = try!(Config::load());
        let conn = try!(Connection::connect(config.server.as_slice(), config.port));
        Ok(IrcBot {
            conn: RefCell::new(conn),
            config: config,
            process: RefCell::new(process),
            chanlists: HashMap::new(),
        })
    }

    fn handle_command(&mut self, source: &str, command: &str, args: &[&str]) -> IoResult<()> {
        match (command, args) {
            ("PING", [msg]) => {
                try!(Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "PONG", [msg])));
            },
            ("376", _) => { // End of MOTD
                for chan in self.config.channels.iter() {
                    try!(self.send_join(chan.as_slice()));
                }
            },
            ("422", _) => { // Missing MOTD
                for chan in self.config.channels.iter() {
                    try!(self.send_join(chan.as_slice()));
                }
            },
            ("353", [_, _, chan, users]) => { // /NAMES
                for user in users.split_str(" ") {
                    if !match self.chanlists.find_mut(&String::from_str(chan)) {
                        Some(vec) => {
                            vec.push(String::from_str(user));
                            true
                        },
                        None => false,
                    } {
                        self.chanlists.insert(String::from_str(chan), vec!(String::from_str(user)));
                    }
                }
            },
            ("JOIN", [chan]) => {
                match self.chanlists.find_mut(&String::from_str(chan)) {
                    Some(vec) => {
                        match source.find('!') {
                            Some(i) => vec.push(String::from_str(source.slice_to(i))),
                            None => (),
                        };
                    },
                    None => (),
                }
            },
            ("PART", [chan, _]) => {
                match self.chanlists.find_mut(&String::from_str(chan)) {
                    Some(vec) => {
                        match source.find('!') {
                            Some(i) => {
                                match vec.as_slice().position_elem(&String::from_str(source.slice_to(i))) {
                                    Some(n) => {
                                        vec.swap_remove(n);
                                    },
                                    None => (),
                                };
                            },
                            None => (),
                        };
                    },
                    None => (),
                }
            },
            _ => {
                try!((*self.process.borrow_mut().deref_mut())(self, source, command, args));
            },
        };
        Ok(())
    }
}

impl<'a, T, U> Bot<'a> for IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    fn send_nick(&self, nick: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "NICK", [nick]))
    }

    fn send_user(&self, username: &str, real_name: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "USER", [username, "0", "*", real_name]))
    }

    fn send_join(&self, chan: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "JOIN", [chan.as_slice()]))
    }

    fn send_mode(&self, chan: &str, mode: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "MODE", [chan.as_slice(), mode.as_slice()]))
    }

    fn send_topic(&self, chan: &str, topic: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "TOPIC", [chan.as_slice(), topic.as_slice()]))
    }

    fn send_invite(&self, person: &str, chan: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "INVITE", [person.as_slice(), chan.as_slice()]))
    }

    fn send_privmsg(&self, chan: &str, msg: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "PRIVMSG", [chan.as_slice(), msg.as_slice()]))
    }

    fn identify(&self) -> IoResult<()> {
        try!(self.send_nick(self.config.nickname.as_slice()));
        self.send_user(self.config.username.as_slice(), self.config.realname.as_slice())
    }

    fn output(&mut self) -> IoResult<()> {
        let mut reader = match self.conn.borrow_mut().deref_mut() {
            &Conn(_, ref recv) => BufferedReader::new(recv.clone()),
        };
        for line in reader.lines() {
            match line {
                Ok(ln) => {
                    let (source, command, args) = try!(process(ln.as_slice()));
                    try!(self.handle_command(source, command, args.as_slice()));
                    println!("{}", ln)
                },
                Err(e) => println!("Shit, you're fucked! {}", e),
            }
        }
        Ok(())
    }

    fn config(&self) -> Config {
        self.config.clone()
    }
}

fn process(msg: &str) -> IoResult<(&str, &str, Vec<&str>)> {
    let reg = regex!(r"^(?::([^ ]+) )?([^ ]+)(.*)");
    let cap = match reg.captures(msg) {
        Some(x) => x,
        None => return Err(IoError {
            kind: InvalidInput,
            desc: "Failed to parse line",
            detail: None,
        }),
    };
    let source = cap.at(1);
    let command = cap.at(2);
    let args = parse_args(cap.at(3));
    Ok((source, command, args))
}

fn parse_args(line: &str) -> Vec<&str> {
    let reg = regex!(r" ([^: ]+)| :([^\r\n]*)[\r\n]*$");
    reg.captures_iter(line).map(|cap| {
        match cap.at(1) {
            "" => cap.at(2),
            x => x,
        }
    }).collect()
}

#[test]
fn process_line_test() {
    let res = process(":flare.to.ca.fyrechat.net 353 pickles = #pickles :pickles awe\r\n").unwrap();
    let (source, command, args) = res;
    assert_eq!(source, "flare.to.ca.fyrechat.net");
    assert_eq!(command, "353");
    assert_eq!(args, vec!["pickles", "=", "#pickles", "pickles awe"]);

    let res = process("PING :flare.to.ca.fyrechat.net\r\n").unwrap();
    let (source, command, args) = res;
    assert_eq!(source, "");
    assert_eq!(command, "PING");
    assert_eq!(args, vec!["flare.to.ca.fyrechat.net"]);
}

#[test]
fn process_args_test() {
    let res = parse_args("PRIVMSG #vana :hi");
    assert_eq!(res, vec!["#vana", "hi"])
}
<commit_msg>Specified the implementation of IrcBot to go with the new function.<commit_after>#![feature(phase)]
extern crate regex;
#[phase(plugin)] extern crate regex_macros;
extern crate serialize;

use std::cell::RefCell;
use std::collections::HashMap;
use std::io::{BufferedReader, BufferedWriter, InvalidInput, IoError, IoResult, TcpStream};
use std::vec::Vec;
use conn::{Conn, Connection};
use data::{Config, IrcReader, IrcWriter, Message};

pub mod conn;
pub mod data;

pub trait Bot<'a> {
    fn send_nick(&self, nick: &str) -> IoResult<()>;
    fn send_user(&self, username: &str, real_name: &str) -> IoResult<()>;
    fn send_join(&self, chan: &str) -> IoResult<()>;
    fn send_mode(&self, chan: &str, mode: &str) -> IoResult<()>;
    fn send_topic(&self, chan: &str, topic: &str) -> IoResult<()>;
    fn send_invite(&self, person: &str, chan: &str) -> IoResult<()>;
    fn send_privmsg(&self, chan: &str, msg: &str) -> IoResult<()>;
    fn identify(&self) -> IoResult<()>;
    fn output(&mut self) -> IoResult<()>;
    fn config(&self) -> Config;
}

pub struct IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    pub conn: RefCell<Connection<T, U>>,
    pub config: Config,
    process: RefCell<|&IrcBot<T, U>, &str, &str, &[&str]|:'a -> IoResult<()>>,
    pub chanlists: HashMap<String, Vec<String>>,
}

impl<'a> IrcBot<'a, BufferedWriter<TcpStream>, TcpStream> {
    pub fn new(process: |&IrcBot<BufferedWriter<TcpStream>, TcpStream>, &str, &str, &[&str]|:'a -> IoResult<()>) -> IoResult<IrcBot<'a, BufferedWriter<TcpStream>, TcpStream>> {
        let config = try!(Config::load());
        let conn = try!(Connection::connect(config.server.as_slice(), config.port));
        Ok(IrcBot {
            conn: RefCell::new(conn),
            config: config,
            process: RefCell::new(process),
            chanlists: HashMap::new(),
        })
    }
}

impl<'a, T, U> Bot<'a> for IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    fn send_nick(&self, nick: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "NICK", [nick]))
    }

    fn send_user(&self, username: &str, real_name: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "USER", [username, "0", "*", real_name]))
    }

    fn send_join(&self, chan: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "JOIN", [chan.as_slice()]))
    }

    fn send_mode(&self, chan: &str, mode: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "MODE", [chan.as_slice(), mode.as_slice()]))
    }

    fn send_topic(&self, chan: &str, topic: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "TOPIC", [chan.as_slice(), topic.as_slice()]))
    }

    fn send_invite(&self, person: &str, chan: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "INVITE", [person.as_slice(), chan.as_slice()]))
    }

    fn send_privmsg(&self, chan: &str, msg: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "PRIVMSG", [chan.as_slice(), msg.as_slice()]))
    }

    fn identify(&self) -> IoResult<()> {
        try!(self.send_nick(self.config.nickname.as_slice()));
        self.send_user(self.config.username.as_slice(), self.config.realname.as_slice())
    }

    fn output(&mut self) -> IoResult<()> {
        let mut reader = match self.conn.borrow_mut().deref_mut() {
            &Conn(_, ref recv) => BufferedReader::new(recv.clone()),
        };
        for line in reader.lines() {
            match line {
                Ok(ln) => {
                    let (source, command, args) = try!(process(ln.as_slice()));
                    try!(self.handle_command(source, command, args.as_slice()));
                    println!("{}", ln)
                },
                Err(e) => println!("Shit, you're fucked! {}", e),
            }
        }
        Ok(())
    }

    fn config(&self) -> Config {
        self.config.clone()
    }
}

impl<'a, T, U> IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    fn handle_command(&mut self, source: &str, command: &str, args: &[&str]) -> IoResult<()> {
        match (command, args) {
            ("PING", [msg]) => {
                try!(Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "PONG", [msg])));
            },
            ("376", _) => { // End of MOTD
                for chan in self.config.channels.iter() {
                    try!(self.send_join(chan.as_slice()));
                }
            },
            ("422", _) => { // Missing MOTD
                for chan in self.config.channels.iter() {
                    try!(self.send_join(chan.as_slice()));
                }
            },
            ("353", [_, _, chan, users]) => { // /NAMES
                for user in users.split_str(" ") {
                    if !match self.chanlists.find_mut(&String::from_str(chan)) {
                        Some(vec) => {
                            vec.push(String::from_str(user));
                            true
                        },
                        None => false,
                    } {
                        self.chanlists.insert(String::from_str(chan), vec!(String::from_str(user)));
                    }
                }
            },
            ("JOIN", [chan]) => {
                match self.chanlists.find_mut(&String::from_str(chan)) {
                    Some(vec) => {
                        match source.find('!') {
                            Some(i) => vec.push(String::from_str(source.slice_to(i))),
                            None => (),
                        };
                    },
                    None => (),
                }
            },
            ("PART", [chan, _]) => {
                match self.chanlists.find_mut(&String::from_str(chan)) {
                    Some(vec) => {
                        match source.find('!') {
                            Some(i) => {
                                match vec.as_slice().position_elem(&String::from_str(source.slice_to(i))) {
                                    Some(n) => {
                                        vec.swap_remove(n);
                                    },
                                    None => (),
                                };
                            },
                            None => (),
                        };
                    },
                    None => (),
                }
            },
            _ => {
                try!((*self.process.borrow_mut().deref_mut())(self, source, command, args));
            },
        };
        Ok(())
    }
}

fn process(msg: &str) -> IoResult<(&str, &str, Vec<&str>)> {
    let reg = regex!(r"^(?::([^ ]+) )?([^ ]+)(.*)");
    let cap = match reg.captures(msg) {
        Some(x) => x,
        None => return Err(IoError {
            kind: InvalidInput,
            desc: "Failed to parse line",
            detail: None,
        }),
    };
    let source = cap.at(1);
    let command = cap.at(2);
    let args = parse_args(cap.at(3));
    Ok((source, command, args))
}

fn parse_args(line: &str) -> Vec<&str> {
    let reg = regex!(r" ([^: ]+)| :([^\r\n]*)[\r\n]*$");
    reg.captures_iter(line).map(|cap| {
        match cap.at(1) {
            "" => cap.at(2),
            x => x,
        }
    }).collect()
}

#[test]
fn process_line_test() {
    let res = process(":flare.to.ca.fyrechat.net 353 pickles = #pickles :pickles awe\r\n").unwrap();
    let (source, command, args) = res;
    assert_eq!(source, "flare.to.ca.fyrechat.net");
    assert_eq!(command, "353");
    assert_eq!(args, vec!["pickles", "=", "#pickles", "pickles awe"]);

    let res = process("PING :flare.to.ca.fyrechat.net\r\n").unwrap();
    let (source, command, args) = res;
    assert_eq!(source, "");
    assert_eq!(command, "PING");
    assert_eq!(args, vec!["flare.to.ca.fyrechat.net"]);
}

#[test]
fn process_args_test() {
    let res = parse_args("PRIVMSG #vana :hi");
    assert_eq!(res, vec!["#vana", "hi"])
}
<|endoftext|>