<commit_before>use std::{fmt, mem};
use std::sync::{Arc, Mutex};

use itertools::{Itertools, MultiPeek};

use unicode::{self, UString};

use lang::{Context, Filter};
use lang::context::PrecedenceGroup;
use util::Labeled;

#[derive(Debug)]
pub enum ParseError {
    InvalidToken(char),
    MismatchedParens(Token, Tf),
    NotAllowed(Filter),
    NotFullyParsed(Vec<Tf>),
    UnbalancedParen(Token)
}

#[derive(Debug)]
pub enum Token {
    /// An unrecognized character
    Invalid(char),
    /// An opening parenthesis `(`
    OpenParen,
    /// A closing parenthesis `)`
    CloseParen,
    /// The sequential execution operator `;;`, and all following code
    AndThen(Code),
    /// A sequence of one or more whitespace characters
    Whitespace
}

//#[derive(Debug)] // https://github.com/bluss/rust-itertools/issues/32
enum CodeVariant {
    Empty,
    UString { s: UString, peek_index: usize },
    UStringIter(MultiPeek<unicode::IntoIter>),
    Mutation
}

impl fmt::Debug for CodeVariant { // https://github.com/bluss/rust-itertools/issues/32
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CodeVariant::Empty => try!(write!(w, "CodeVariant::Empty")),
            CodeVariant::UString { ref s, ref peek_index } => try!(write!(w, "CodeVariant::UString {{ s: {:?}, peek_index: {:?} }}", s, peek_index)),
            CodeVariant::UStringIter(_) => try!(write!(w, "CodeVariant::UStringIter(/* ... */)")),
            CodeVariant::Mutation => try!(write!(w, "CodeVariant::Mutation"))
        }
        Ok(())
    }
}

#[derive(Debug)]
pub struct Code(Mutex<CodeVariant>);

impl Code {
    fn peek(&mut self) -> Option<char> {
        let mut lock = self.0.lock().unwrap();
        match *&mut *lock {
            CodeVariant::Empty => None,
            CodeVariant::UString { ref s, ref mut peek_index } => {
                if *peek_index < s.len() {
                    *peek_index += 1;
                    Some(s[*peek_index - 1])
                } else {
                    None
                }
            }
            CodeVariant::UStringIter(ref mut it) => {
                it.peek().map(|&c| c)
            }
            CodeVariant::Mutation => panic!("code mutex has been emptied")
        }
    }
}

impl Default for Code {
    fn default() -> Code {
        Code(Mutex::new(CodeVariant::Empty))
    }
}

impl<T: Into<UString>> From<T> for Code {
    fn from(code_string: T) -> Code {
        Code(Mutex::new(CodeVariant::UString { s: code_string.into(), peek_index: 0 }))
    }
}

impl Clone for Code {
    fn clone(&self) -> Code {
        let mut lock = self.0.lock().unwrap();
        match *&mut *lock {
            CodeVariant::Empty => Code(Mutex::new(CodeVariant::Empty)),
            CodeVariant::UString { ref s, .. } => Code(Mutex::new(CodeVariant::UString { s: s.clone(), peek_index: 0 })),
            ref mut code_variant @ CodeVariant::UStringIter(_) => {
                if let CodeVariant::UStringIter(it) = mem::replace(code_variant, CodeVariant::Mutation) {
                    let s = it.collect::<UString>();
                    *code_variant = CodeVariant::UString { s: s.clone(), peek_index: 0 };
                    Code(Mutex::new(CodeVariant::UString { s: s, peek_index: 0 }))
                } else {
                    unreachable!()
                }
            }
            CodeVariant::Mutation => panic!("code mutex has been emptied")
        }
    }
}

impl Iterator for Code {
    type Item = char;

    fn next(&mut self) -> Option<char> {
        let mut lock = self.0.lock().unwrap();
        match *&mut *lock {
            CodeVariant::Empty => None,
            ref mut code_variant @ CodeVariant::UString { .. } => {
                if let CodeVariant::UString { s, .. } = mem::replace(code_variant, CodeVariant::Mutation) {
                    let mut iter = s.into_iter().multipeek();
                    let result = iter.next();
                    *code_variant = CodeVariant::UStringIter(iter);
                    result
                } else {
                    unreachable!()
                }
            }
            CodeVariant::UStringIter(ref mut iter) => iter.next(),
            CodeVariant::Mutation => panic!("code mutex has been emptied")
        }
    }
}

struct Tokens {
    code: Code,
    // context: Context
}

impl Tokens {
    fn new<T: Into<Code>>(code: T, _: Context) -> Tokens {
        Tokens {
            code: code.into(),
            // context: context
        }
    }
}

impl Iterator for Tokens {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        use self::Token::*;

        match self.code.next() {
            Some('\t') |
            Some('\n') |
            Some('\r') |
            Some(' ') => Some(Whitespace),
            Some('(') => Some(OpenParen),
            Some(')') => Some(CloseParen),
            Some(';') => {
                if self.code.peek() == Some(';') {
                    self.code.next(); // discard the second semicolon
                    Some(AndThen(mem::replace(&mut self.code, Code::default())))
                } else {
                    Some(Invalid(';'))
                }
            }
            Some(c) => Some(Invalid(c)),
            None => None
        }
    }
}

/// A token or filter, used by the in-place parsing algorithm.
#[derive(Debug)]
pub enum Tf {
    Token(Token),
    Filter(Filter)
}

/// Convert a sequence of tokens into an executable filter.
pub fn parse<T: Into<Code>>(code: T, context: Context) -> Result<Filter, ParseError> {
    parse_inner(Tokens::new(code, context.clone()).map(Tf::Token), context)
}

fn parse_inner<I: IntoIterator<Item = Tf>>(tf_iter: I, context: Context) -> Result<Filter, ParseError> {
    let mut tf = tf_iter.into_iter().collect::<Vec<_>>(); // the list of tokens and filters on which the in-place parsing algorithm operates
    // error if any invalid token is found
    if let Some(pos) = tf.iter().position(|i| if let Tf::Token(Token::Invalid(_)) = *i { true } else { false }) {
        if let Tf::Token(Token::Invalid(c)) = tf[pos] {
            return Err(ParseError::InvalidToken(c));
        } else {
            unreachable!();
        }
    }
    // define the macro used for testing if filters are allowed
    macro_rules! try_filter {
        ($f:expr) => {
            match $f {
                f => {
                    if (context.filter_allowed)(&f) {
                        f
                    } else {
                        return Err(ParseError::NotAllowed(f));
                    }
                }
            }
        }
    }
    // remove leading and trailing whitespace as it is semantically irrelevant
    while let Some(&Tf::Token(Token::Whitespace)) = tf.first() { tf.remove(0); }
    while let Some(&Tf::Token(Token::Whitespace)) = tf.last() { tf.pop(); }
    // return an empty filter if the token list is empty
    if tf.len() == 0 { return Ok(try_filter!(Filter::Empty)); }
    // parse operators in decreasing precedence
    for (_, precedence_group) in context.operators.clone().into_iter().rev() { // iterate from highest to lowest precedence
        match precedence_group {
            PrecedenceGroup::AndThen => {
                let mut found = None; // flag any AndThen tokens and remember their contents
                for idx in (0..tf.len()).rev() { // iterate right-to-left for in-place manipulation
                    if let Some(remaining_code) = mem::replace(&mut found, None) {
                        if let Tf::Token(Token::Whitespace) = tf[idx] {
                            // ignore whitespace between `;;` and its left operand
                            tf.remove(idx);
                            continue;
                        }
                        tf[idx] = Tf::Filter(try_filter!(Filter::AndThen {
                            lhs: Box::new(if let Tf::Filter(ref lhs) = tf[idx] { lhs.clone() } else { try_filter!(Filter::Empty) }),
                            remaining_code: remaining_code
                        }));
                    } else {
                        match tf.remove(idx) {
                            Tf::Token(Token::AndThen(remaining_code)) => {
                                found = Some(remaining_code); // found an AndThen (`;;`), will be merged into a syntax tree with the element to its left
                            }
                            tf_item => {
                                tf.insert(idx, tf_item);
                            }
                        }
                    }
                }
                if let Some(remaining_code) = found {
                    // the code begins with an `;;`
                    tf.insert(0, Tf::Filter(try_filter!(Filter::AndThen {
                        lhs: Box::new(try_filter!(Filter::Empty)),
                        remaining_code: remaining_code
                    })));
                }
            }
            PrecedenceGroup::Circumfix => {
                let mut paren_balance = 0; // how many closing parens have not been matched by opening parens
                let mut paren_start = None; // the index of the outermost closing paren
                for idx in (0..tf.len()).rev() { // iterate right-to-left for in-place manipulation
                    match tf[idx] {
                        Tf::Token(Token::CloseParen) => {
                            if paren_balance == 0 {
                                paren_start = Some(idx);
                            }
                            paren_balance += 1;
                        }
                        Tf::Token(Token::OpenParen) => {
                            paren_balance -= 1;
                            if paren_balance < 0 {
                                return Err(ParseError::UnbalancedParen(Token::OpenParen));
                            } else if paren_balance == 0 {
                                if let Some(paren_start) = paren_start {
                                    if let Tf::Token(Token::CloseParen) = tf[paren_start] {
                                        tf.remove(paren_start);
                                        //let inner = tf.drain(idx + 1..paren_start).collect::<Vec<_>>(); //TODO use this when stabilized
                                        let mut inner = vec![];
                                        for _ in idx + 1..paren_start {
                                            inner.push(tf.remove(idx + 1));
                                        }
                                        tf[idx] = Tf::Filter(try_filter!(Filter::Custom {
                                            attributes: vec![try!(parse_inner(inner, context.clone()))],
                                            run: Box::new(Labeled::new("<filter group (α)>", Arc::new(|attrs, input, output| {
                                                assert_eq!(attrs.len(), 1);
                                                attrs[0].run(input, output)
                                            })))
                                        }));
                                    } else {
                                        return Err(ParseError::MismatchedParens(Token::OpenParen, tf.remove(paren_start)));
                                    }
                                } else {
                                    unreachable!();
                                }
                                paren_start = None;
                            }
                        }
                        _ => { continue; }
                    }
                }
                if paren_balance > 0 {
                    if let Some(paren_start) = paren_start {
                        if let Tf::Token(Token::CloseParen) = tf[paren_start] {
                            return Err(ParseError::UnbalancedParen(Token::CloseParen));
                        } else {
                            unreachable!();
                        }
                    } else {
                        unreachable!();
                    }
                }
            }
        }
    }
    if tf.len() == 1 {
        match tf.pop() {
            Some(Tf::Filter(result)) => Ok(result),
            Some(Tf::Token(token)) => Err(ParseError::NotFullyParsed(vec![Tf::Token(token)])),
            None => unreachable!()
        }
    } else {
        Err(ParseError::NotFullyParsed(tf))
    }
}
<commit_msg>Add support for comments<commit_after>use std::{fmt, mem};
use std::sync::{Arc, Mutex};

use itertools::{Itertools, MultiPeek};

use unicode::{self, UString};

use lang::{Context, Filter};
use lang::context::PrecedenceGroup;
use util::Labeled;

#[derive(Debug)]
pub enum ParseError {
    InvalidToken(char),
    MismatchedParens(Token, Tf),
    NotAllowed(Filter),
    NotFullyParsed(Vec<Tf>),
    UnbalancedParen(Token)
}

#[derive(Debug)]
pub enum Token {
    /// An unrecognized character
    Invalid(char),
    /// An opening parenthesis `(`
    OpenParen,
    /// A closing parenthesis `)`
    CloseParen,
    /// The sequential execution operator `;;`, and all following code
    AndThen(Code),
    /// A sequence of one or more whitespace characters
    Whitespace
}

//#[derive(Debug)] // https://github.com/bluss/rust-itertools/issues/32
enum CodeVariant {
    Empty,
    UString { s: UString, peek_index: usize },
    UStringIter(MultiPeek<unicode::IntoIter>),
    Mutation
}

impl fmt::Debug for CodeVariant { // https://github.com/bluss/rust-itertools/issues/32
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CodeVariant::Empty => try!(write!(w, "CodeVariant::Empty")),
            CodeVariant::UString { ref s, ref peek_index } => try!(write!(w, "CodeVariant::UString {{ s: {:?}, peek_index: {:?} }}", s, peek_index)),
            CodeVariant::UStringIter(_) => try!(write!(w, "CodeVariant::UStringIter(/* ... */)")),
            CodeVariant::Mutation => try!(write!(w, "CodeVariant::Mutation"))
        }
        Ok(())
    }
}

#[derive(Debug)]
pub struct Code(Mutex<CodeVariant>);

impl Code {
    fn peek(&mut self) -> Option<char> {
        let mut lock = self.0.lock().unwrap();
        match *&mut *lock {
            CodeVariant::Empty => None,
            CodeVariant::UString { ref s, ref mut peek_index } => {
                if *peek_index < s.len() {
                    *peek_index += 1;
                    Some(s[*peek_index - 1])
                } else {
                    None
                }
            }
            CodeVariant::UStringIter(ref mut it) => {
                it.peek().map(|&c| c)
            }
            CodeVariant::Mutation => panic!("code mutex has been emptied")
        }
    }
}

impl Default for Code {
    fn default() -> Code {
        Code(Mutex::new(CodeVariant::Empty))
    }
}

impl<T: Into<UString>> From<T> for Code {
    fn from(code_string: T) -> Code {
        Code(Mutex::new(CodeVariant::UString { s: code_string.into(), peek_index: 0 }))
    }
}

impl Clone for Code {
    fn clone(&self) -> Code {
        let mut lock = self.0.lock().unwrap();
        match *&mut *lock {
            CodeVariant::Empty => Code(Mutex::new(CodeVariant::Empty)),
            CodeVariant::UString { ref s, .. } => Code(Mutex::new(CodeVariant::UString { s: s.clone(), peek_index: 0 })),
            ref mut code_variant @ CodeVariant::UStringIter(_) => {
                if let CodeVariant::UStringIter(it) = mem::replace(code_variant, CodeVariant::Mutation) {
                    let s = it.collect::<UString>();
                    *code_variant = CodeVariant::UString { s: s.clone(), peek_index: 0 };
                    Code(Mutex::new(CodeVariant::UString { s: s, peek_index: 0 }))
                } else {
                    unreachable!()
                }
            }
            CodeVariant::Mutation => panic!("code mutex has been emptied")
        }
    }
}

impl Iterator for Code {
    type Item = char;

    fn next(&mut self) -> Option<char> {
        let mut lock = self.0.lock().unwrap();
        match *&mut *lock {
            CodeVariant::Empty => None,
            ref mut code_variant @ CodeVariant::UString { .. } => {
                if let CodeVariant::UString { s, .. } = mem::replace(code_variant, CodeVariant::Mutation) {
                    let mut iter = s.into_iter().multipeek();
                    let result = iter.next();
                    *code_variant = CodeVariant::UStringIter(iter);
                    result
                } else {
                    unreachable!()
                }
            }
            CodeVariant::UStringIter(ref mut iter) => iter.next(),
            CodeVariant::Mutation => panic!("code mutex has been emptied")
        }
    }
}

struct Tokens {
    code: Code,
    // context: Context
}

impl Tokens {
    fn new<T: Into<Code>>(code: T, _: Context) -> Tokens {
        Tokens {
            code: code.into(),
            // context: context
        }
    }
}

impl Iterator for Tokens {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        use self::Token::*;

        match self.code.next() {
            Some('\t') |
            Some('\n') |
            Some('\r') |
            Some(' ') => Some(Whitespace),
            Some('#') => {
                while self.code.peek().map(|c| c != '\n').unwrap_or(false) {
                    self.code.next(); // discard comment contents
                }
                Some(Whitespace) // comments are treated as whitespace
            }
            Some('(') => Some(OpenParen),
            Some(')') => Some(CloseParen),
            Some(';') => {
                if self.code.peek() == Some(';') {
                    self.code.next(); // discard the second semicolon
                    Some(AndThen(mem::replace(&mut self.code, Code::default())))
                } else {
                    Some(Invalid(';'))
                }
            }
            Some(c) => Some(Invalid(c)),
            None => None
        }
    }
}

/// A token or filter, used by the in-place parsing algorithm.
#[derive(Debug)]
pub enum Tf {
    Token(Token),
    Filter(Filter)
}

/// Convert a sequence of tokens into an executable filter.
pub fn parse<T: Into<Code>>(code: T, context: Context) -> Result<Filter, ParseError> {
    parse_inner(Tokens::new(code, context.clone()).map(Tf::Token), context)
}

fn parse_inner<I: IntoIterator<Item = Tf>>(tf_iter: I, context: Context) -> Result<Filter, ParseError> {
    let mut tf = tf_iter.into_iter().collect::<Vec<_>>(); // the list of tokens and filters on which the in-place parsing algorithm operates
    // error if any invalid token is found
    if let Some(pos) = tf.iter().position(|i| if let Tf::Token(Token::Invalid(_)) = *i { true } else { false }) {
        if let Tf::Token(Token::Invalid(c)) = tf[pos] {
            return Err(ParseError::InvalidToken(c));
        } else {
            unreachable!();
        }
    }
    // define the macro used for testing if filters are allowed
    macro_rules! try_filter {
        ($f:expr) => {
            match $f {
                f => {
                    if (context.filter_allowed)(&f) {
                        f
                    } else {
                        return Err(ParseError::NotAllowed(f));
                    }
                }
            }
        }
    }
    // remove leading and trailing whitespace as it is semantically irrelevant
    while let Some(&Tf::Token(Token::Whitespace)) = tf.first() { tf.remove(0); }
    while let Some(&Tf::Token(Token::Whitespace)) = tf.last() { tf.pop(); }
    // return an empty filter if the token list is empty
    if tf.len() == 0 { return Ok(try_filter!(Filter::Empty)); }
    // parse operators in decreasing precedence
    for (_, precedence_group) in context.operators.clone().into_iter().rev() { // iterate from highest to lowest precedence
        match precedence_group {
            PrecedenceGroup::AndThen => {
                let mut found = None; // flag any AndThen tokens and remember their contents
                for idx in (0..tf.len()).rev() { // iterate right-to-left for in-place manipulation
                    if let Some(remaining_code) = mem::replace(&mut found, None) {
                        if let Tf::Token(Token::Whitespace) = tf[idx] {
                            // ignore whitespace between `;;` and its left operand
                            tf.remove(idx);
                            continue;
                        }
                        tf[idx] = Tf::Filter(try_filter!(Filter::AndThen {
                            lhs: Box::new(if let Tf::Filter(ref lhs) = tf[idx] { lhs.clone() } else { try_filter!(Filter::Empty) }),
                            remaining_code: remaining_code
                        }));
                    } else {
                        match tf.remove(idx) {
                            Tf::Token(Token::AndThen(remaining_code)) => {
                                found = Some(remaining_code); // found an AndThen (`;;`), will be merged into a syntax tree with the element to its left
                            }
                            tf_item => {
                                tf.insert(idx, tf_item);
                            }
                        }
                    }
                }
                if let Some(remaining_code) = found {
                    // the code begins with an `;;`
                    tf.insert(0, Tf::Filter(try_filter!(Filter::AndThen {
                        lhs: Box::new(try_filter!(Filter::Empty)),
                        remaining_code: remaining_code
                    })));
                }
            }
            PrecedenceGroup::Circumfix => {
                let mut paren_balance = 0; // how many closing parens have not been matched by opening parens
                let mut paren_start = None; // the index of the outermost closing paren
                for idx in (0..tf.len()).rev() { // iterate right-to-left for in-place manipulation
                    match tf[idx] {
                        Tf::Token(Token::CloseParen) => {
                            if paren_balance == 0 {
                                paren_start = Some(idx);
                            }
                            paren_balance += 1;
                        }
                        Tf::Token(Token::OpenParen) => {
                            paren_balance -= 1;
                            if paren_balance < 0 {
                                return Err(ParseError::UnbalancedParen(Token::OpenParen));
                            } else if paren_balance == 0 {
                                if let Some(paren_start) = paren_start {
                                    if let Tf::Token(Token::CloseParen) = tf[paren_start] {
                                        tf.remove(paren_start);
                                        //let inner = tf.drain(idx + 1..paren_start).collect::<Vec<_>>(); //TODO use this when stabilized
                                        let mut inner = vec![];
                                        for _ in idx + 1..paren_start {
                                            inner.push(tf.remove(idx + 1));
                                        }
                                        tf[idx] = Tf::Filter(try_filter!(Filter::Custom {
                                            attributes: vec![try!(parse_inner(inner, context.clone()))],
                                            run: Box::new(Labeled::new("<filter group (α)>", Arc::new(|attrs, input, output| {
                                                assert_eq!(attrs.len(), 1);
                                                attrs[0].run(input, output)
                                            })))
                                        }));
                                    } else {
                                        return Err(ParseError::MismatchedParens(Token::OpenParen, tf.remove(paren_start)));
                                    }
                                } else {
                                    unreachable!();
                                }
                                paren_start = None;
                            }
                        }
                        _ => { continue; }
                    }
                }
                if paren_balance > 0 {
                    if let Some(paren_start) = paren_start {
                        if let Tf::Token(Token::CloseParen) = tf[paren_start] {
                            return Err(ParseError::UnbalancedParen(Token::CloseParen));
                        } else {
                            unreachable!();
                        }
                    } else {
                        unreachable!();
                    }
                }
            }
        }
    }
    if tf.len() == 1 {
        match tf.pop() {
            Some(Tf::Filter(result)) => Ok(result),
            Some(Tf::Token(token)) => Err(ParseError::NotFullyParsed(vec![Tf::Token(token)])),
            None => unreachable!()
        }
    } else {
        Err(ParseError::NotFullyParsed(tf))
    }
}
<|endoftext|>


<commit_before>//! Read and write Elasto Mania level files.

use std::io::{ Read };
use std::fs::File;
use byteorder::{ ByteOrder, ReadBytesExt, LittleEndian };
use super::{ Position, trim_string };

// Magic arbitrary number; signifies end-of-data. Followed by Top10 list(s).
const EOD: i32 = 0x0067103A;
// Magic arbitrary number; signifies end-of-file.
const EOF: i32 = 0x00845D52;

/// Game version.
#[derive(Debug, PartialEq)]
pub enum Version {
    Across,
    Elma
}

/// Type of object.
#[derive(Debug, PartialEq)]
pub enum ObjectType {
    Apple,
    Exit,
    Killer,
    Player
}

/// Object struct. Every level requires one `ObjectType::Player` Object and at least one `ObjectType::Exit` Object.
#[derive(Debug, PartialEq)]
pub struct Object {
    /// Position. See `Position` struct.
    pub position: Position<f64>,
    /// Type of Object, see `ObjectType`.
    pub object_type: ObjectType,
    /// Applies to `ObjectType::Apple` only.
    ///
    /// 0 = normal
    /// 1 = gravity up
    /// 2 = gravity down
    /// 3 = gravity left
    /// 4 = gravity right
    // TODO: enum with gravity
    pub gravity: i32,
    /// Applies to `ObjectType::Apple` only. Valid values are 1 to 9.
    pub animation: i32
}

/// Polygon struct.
#[derive(Debug, Default, PartialEq)]
pub struct Polygon {
    /// Grass polygon.
    pub grass: bool,
    /// Vector with all vertices, see Position struct.
    pub vertices: Vec<Position<f64>>
}

impl Polygon {
    pub fn new () -> Polygon {
        Polygon {
            grass: false,
            vertices: vec![]
        }
    }
}

/// Picture struct.
#[derive(Debug, PartialEq)]
pub struct Picture {
    /// Picture name.
    pub name: String,
    /// Texture name.
    pub texture: String,
    /// Mask name.
    pub mask: String,
    /// Position. See Position struct.
    pub position: Position<f64>,
    /// Z-distance
    pub distance: i32,
    /// Clipping.
    ///
    /// 0 = unclipped
    /// 1 = ground
    /// 2 = sky
    // TODO: make enum
    pub clip: i32
}

/// Top10 list entry struct.
#[derive(Debug)]
pub struct ListEntry {
    /// Player 1 name.
    pub name_1: String,
    /// Player 2 name.
    pub name_2: String,
    /// Time.
    pub time: i32
}

/// Level struct that contains all level information.
pub struct Level {
    /// Elma or Across level.
    pub version: Version,
    /// Raw binary data of a loaded or finalized constructed level.
    raw: Vec<u8>,
    /// Random number that links level file to replay files.
    pub link: i32,
    /// Contains four integrity checks (See calculate_integrity_sums()).
    pub integrity: [f64; 4],
    /// Level name.
    pub name: String,
    /// LGR file name.
    pub lgr: String,
    /// Ground texture name.
    pub ground: String,
    /// Sky texture name.
    pub sky: String,
    /// Vector with all polygons (See Polygon).
    pub polygons: Vec<Polygon>,
    /// Vector with all objects (See Object).
    pub objects: Vec<Object>,
    /// Vector with all pictures (See Picture).
    pub pictures: Vec<Picture>,
    /// Vector of Top10 single-player names and times.
    pub top10_single: Vec<ListEntry>,
    /// Vector of Top10 multi-player names and times.
    pub top10_multi: Vec<ListEntry>
}

impl Default for Level {
    fn default() -> Level { Level::new() }
}

impl Level {
    /// Returns a new Level struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let level = elma::lev::Level::new();
    /// ```
    pub fn new () -> Level {
        Level {
            version: Version::Elma,
            raw: vec![],
            link: 0,
            integrity: [0.0f64; 4],
            name: String::new(),
            lgr: String::from("default"),
            ground: String::from("ground"),
            sky: String::from("sky"),
            polygons: vec![],
            objects: vec![],
            pictures: vec![],
            top10_single: vec![],
            top10_multi: vec![]
        }
    }

    /// Loads a level file and returns a Level struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let level = elma::lev::Level::load_level("tests/test.lev");
    /// ```
    pub fn load_level (filename: &str) -> Level {
        let mut level = Level::new();
        let mut file = File::open(filename).unwrap();
        let mut buffer = vec![];
        file.read_to_end(&mut buffer).unwrap();
        level.raw = buffer;
        level.parse_level();
        level
    }

    /// Parses the raw binary data into Level struct fields.
    fn parse_level (&mut self) {
        let rem = self.raw.as_slice();

        // POT06 = Across, POT14 = Elma.
        let (version, rem) = rem.split_at(5);
        self.version = match version {
            [80, 79, 84, 49, 52] => Version::Elma,
            [80, 79, 84, 48, 54] => Version::Across,
            _ => panic!("Not a valid level file.")
        };

        // Link.
        let (_, mut rem) = rem.split_at(2); // Never used
        self.link = rem.read_i32::<LittleEndian>().unwrap();

        // Integrity checksums.
        for i in 0..4 {
            self.integrity[i] = rem.read_f64::<LittleEndian>().unwrap();
        }

        // Level name.
        let (name, rem) = rem.split_at(51);
        self.name = trim_string(name).unwrap();
        // LGR name.
        let (lgr, rem) = rem.split_at(16);
        self.lgr = trim_string(lgr).unwrap();
        // Ground texture name.
        let (ground, rem) = rem.split_at(10);
        self.ground = trim_string(ground).unwrap();
        // Sky texture name.
        let (sky, mut rem) = rem.split_at(10);
        self.sky = trim_string(sky).unwrap();

        // Polygons.
        let poly_count = (rem.read_f64::<LittleEndian>().unwrap() - 0.4643643).round() as usize;
        for _ in 0..poly_count {
            let grass = rem.read_i32::<LittleEndian>().unwrap() > 0;
            let vertex_count = rem.read_i32::<LittleEndian>().unwrap();
            let mut vertices: Vec<Position<f64>> = vec![];
            for _ in 0..vertex_count {
                let x = rem.read_f64::<LittleEndian>().unwrap();
                let y = rem.read_f64::<LittleEndian>().unwrap();
                vertices.push(Position {
                    x: x,
                    y: y
                });
            }
            self.polygons.push(Polygon {
                grass: grass,
                vertices: vertices
            });
        }

        // Objects.
        let object_count = (rem.read_f64::<LittleEndian>().unwrap() - 0.4643643).round() as usize;
        for _ in 0..object_count {
            let x = rem.read_f64::<LittleEndian>().unwrap();
            let y = rem.read_f64::<LittleEndian>().unwrap();
            let position = Position { x: x, y: y };
            let object_type = match rem.read_i32::<LittleEndian>().unwrap() {
                1 => ObjectType::Exit,
                2 => ObjectType::Apple,
                3 => ObjectType::Killer,
                4 => ObjectType::Player,
                _ => panic!("Not a valid object type")
            };
            let gravity = rem.read_i32::<LittleEndian>().unwrap();
            let animation = rem.read_i32::<LittleEndian>().unwrap() + 1;

            self.objects.push(Object {
                position: position,
                object_type: object_type,
                gravity: gravity,
                animation: animation
            });
        }

        // Pictures.
        let picture_count = (rem.read_f64::<LittleEndian>().unwrap() - 0.2345672).round() as usize;
        for _ in 0..picture_count {
            let (name, temp_rem) = rem.split_at(10);
            rem = temp_rem;
            let name = trim_string(name).unwrap();
            let (texture, temp_rem) = rem.split_at(10);
            rem = temp_rem;
            let texture = trim_string(texture).unwrap();
            let (mask, temp_rem) = rem.split_at(10);
            rem = temp_rem;
            let mask = trim_string(mask).unwrap();
            let x = rem.read_f64::<LittleEndian>().unwrap();
            let y = rem.read_f64::<LittleEndian>().unwrap();
            let distance = rem.read_i32::<LittleEndian>().unwrap();
            let clip = rem.read_i32::<LittleEndian>().unwrap();

            self.pictures.push(Picture {
                name: name,
                texture: texture,
                mask: mask,
                position: Position { x: x, y: y },
                distance: distance,
                clip: clip
            });
        }
/*
        // EOD marker expected at this point.
        let expected = rem.read_i32::<LittleEndian>().unwrap();
        if expected != EOD { panic!("EOD marker mismatch: x0{:x} != x0{:x}", expected, EOD); }

        // First decrypt the top10 blocks.
        let (mut top10, mut rem) = rem.split_at(688);
        let decrypted_top10_data = crypt_top10(top10);

        // Single-player list.
        let single = &decrypted_top10_data[0..344];
        self.top10_single = parse_top10(single);

        // Multi-player list.
        let multi = &decrypted_top10_data[344..688];
        self.top10_multi = parse_top10(multi);

        // EOF marker expected at this point.
        let expected = rem.read_i32::<LittleEndian>().unwrap();
        if expected != EOF { panic!("EOF marker mismatch: x0{:x} != x0{:x}", expected, EOF); } */
    }

    /// Combines the Level struct fields to generate the raw binary data,
    /// and calculate integrity sums.
    fn update (&self) {
        // TODO: convert
        self.calculate_integrity_sums();
    }

    fn calculate_integrity_sums (&self) {
        // TODO: do that
    }

    /// Converts all struct fields into raw binary form and returns it.
    pub fn get_raw (self) -> Vec<u8> {
        self.update();
        self.raw
    }

    /// Saves level as a file.
    pub fn save_lev (self, filename: &str) {
        self.update();
        // let file = File::create(&filename).unwrap();
        // TODO: write stuff.
    }
}
/*
/// Decrypt and encrypt top10 list data. Same algorithm for both.
pub fn crypt_top10 (top10: &[u8]) -> &[u8] {
    // Who knows
    let mut ebp8: i16 = 0x15;
    let mut ebp10: i16 = 0x2637;

    for mut t in top10.iter_mut().take(688) {
        *t ^= (ebp8 & 0xFF) as u8;
        ebp10 = ebp10.wrapping_add((ebp8.wrapping_rem(0xD3D)).wrapping_mul(0xD3D));
        ebp8 = ebp10.wrapping_mul(0x1F).wrapping_add(0xD3D);
    }

    top10
}*/

/// Parse top10 lists and return a vector of `ListEntry`s
pub fn parse_top10 (top10: &[u8]) -> Vec<ListEntry> {
    let mut list: Vec<ListEntry> = vec![];
    let times = LittleEndian::read_i32(&top10[0..4]);
    for n in 0..times {
        let time_offset = (4 + n * 4) as usize;
        let time_end = time_offset + 4;
        let name_1_offset = (44 + n * 15) as usize;
        let name_1_end = name_1_offset + 15;
        let name_2_offset = (194 + n * 15) as usize;
        let name_2_end = name_2_offset + 15;
        // All of this pains me even though I don't understand it...
        let name_1 = &top10[name_1_offset..name_1_end];
        let name_2 = &top10[name_2_offset..name_2_end];
        list.push(ListEntry {
            time: LittleEndian::read_i32(&top10[time_offset..time_end]),
            name_1: trim_string(name_1).unwrap(),
            name_2: trim_string(name_2).unwrap()
        });
    }
    list
}
<commit_msg>Uncomment old code, fail more<commit_after>//! Read and write Elasto Mania level files.

use std::io::{ Read };
use std::fs::File;
use byteorder::{ ByteOrder, ReadBytesExt, LittleEndian };
use super::{ Position, trim_string };

// Magic arbitrary number; signifies end-of-data. Followed by Top10 list(s).
const EOD: i32 = 0x0067103A;
// Magic arbitrary number; signifies end-of-file.
const EOF: i32 = 0x00845D52;

/// Game version.
#[derive(Debug, PartialEq)]
pub enum Version {
    Across,
    Elma
}

/// Type of object.
#[derive(Debug, PartialEq)]
pub enum ObjectType {
    Apple,
    Exit,
    Killer,
    Player
}

/// Object struct. Every level requires one `ObjectType::Player` Object and at least one `ObjectType::Exit` Object.
#[derive(Debug, PartialEq)]
pub struct Object {
    /// Position. See `Position` struct.
    pub position: Position<f64>,
    /// Type of Object, see `ObjectType`.
    pub object_type: ObjectType,
    /// Applies to `ObjectType::Apple` only.
    ///
    /// 0 = normal
    /// 1 = gravity up
    /// 2 = gravity down
    /// 3 = gravity left
    /// 4 = gravity right
    // TODO: enum with gravity
    pub gravity: i32,
    /// Applies to `ObjectType::Apple` only. Valid values are 1 to 9.
    pub animation: i32
}

/// Polygon struct.
#[derive(Debug, Default, PartialEq)]
pub struct Polygon {
    /// Grass polygon.
    pub grass: bool,
    /// Vector with all vertices, see Position struct.
    pub vertices: Vec<Position<f64>>
}

impl Polygon {
    pub fn new () -> Polygon {
        Polygon {
            grass: false,
            vertices: vec![]
        }
    }
}

/// Picture struct.
#[derive(Debug, PartialEq)]
pub struct Picture {
    /// Picture name.
    pub name: String,
    /// Texture name.
    pub texture: String,
    /// Mask name.
    pub mask: String,
    /// Position. See Position struct.
    pub position: Position<f64>,
    /// Z-distance
    pub distance: i32,
    /// Clipping.
    ///
    /// 0 = unclipped
    /// 1 = ground
    /// 2 = sky
    // TODO: make enum
    pub clip: i32
}

/// Top10 list entry struct.
#[derive(Debug)]
pub struct ListEntry {
    /// Player 1 name.
    pub name_1: String,
    /// Player 2 name.
    pub name_2: String,
    /// Time.
    pub time: i32
}

/// Level struct that contains all level information.
pub struct Level {
    /// Elma or Across level.
    pub version: Version,
    /// Raw binary data of a loaded or finalized constructed level.
    raw: Vec<u8>,
    /// Random number that links level file to replay files.
    pub link: i32,
    /// Contains four integrity checks (See calculate_integrity_sums()).
    pub integrity: [f64; 4],
    /// Level name.
    pub name: String,
    /// LGR file name.
    pub lgr: String,
    /// Ground texture name.
    pub ground: String,
    /// Sky texture name.
    pub sky: String,
    /// Vector with all polygons (See Polygon).
    pub polygons: Vec<Polygon>,
    /// Vector with all objects (See Object).
    pub objects: Vec<Object>,
    /// Vector with all pictures (See Picture).
    pub pictures: Vec<Picture>,
    /// Vector of Top10 single-player names and times.
    pub top10_single: Vec<ListEntry>,
    /// Vector of Top10 multi-player names and times.
    pub top10_multi: Vec<ListEntry>
}

impl Default for Level {
    fn default() -> Level { Level::new() }
}

impl Level {
    /// Returns a new Level struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let level = elma::lev::Level::new();
    /// ```
    pub fn new () -> Level {
        Level {
            version: Version::Elma,
            raw: vec![],
            link: 0,
            integrity: [0.0f64; 4],
            name: String::new(),
            lgr: String::from("default"),
            ground: String::from("ground"),
            sky: String::from("sky"),
            polygons: vec![],
            objects: vec![],
            pictures: vec![],
            top10_single: vec![],
            top10_multi: vec![]
        }
    }

    /// Loads a level file and returns a Level struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let level = elma::lev::Level::load_level("tests/test.lev");
    /// ```
    pub fn load_level (filename: &str) -> Level {
        let mut level = Level::new();
        let mut file = File::open(filename).unwrap();
        let mut buffer = vec![];
        file.read_to_end(&mut buffer).unwrap();
        level.raw = buffer;
        level.parse_level();
        level
    }

    /// Parses the raw binary data into Level struct fields.
    fn parse_level (&mut self) {
        let rem = self.raw.as_slice();

        // POT06 = Across, POT14 = Elma.
        let (version, rem) = rem.split_at(5);
        self.version = match version {
            [80, 79, 84, 49, 52] => Version::Elma,
            [80, 79, 84, 48, 54] => Version::Across,
            _ => panic!("Not a valid level file.")
        };

        // Link.
        let (_, mut rem) = rem.split_at(2); // Never used
        self.link = rem.read_i32::<LittleEndian>().unwrap();

        // Integrity checksums.
        for i in 0..4 {
            self.integrity[i] = rem.read_f64::<LittleEndian>().unwrap();
        }

        // Level name.
        let (name, rem) = rem.split_at(51);
        self.name = trim_string(name).unwrap();
        // LGR name.
        let (lgr, rem) = rem.split_at(16);
        self.lgr = trim_string(lgr).unwrap();
        // Ground texture name.
        let (ground, rem) = rem.split_at(10);
        self.ground = trim_string(ground).unwrap();
        // Sky texture name.
        let (sky, mut rem) = rem.split_at(10);
        self.sky = trim_string(sky).unwrap();

        // Polygons.
        let poly_count = (rem.read_f64::<LittleEndian>().unwrap() - 0.4643643).round() as usize;
        for _ in 0..poly_count {
            let grass = rem.read_i32::<LittleEndian>().unwrap() > 0;
            let vertex_count = rem.read_i32::<LittleEndian>().unwrap();
            let mut vertices: Vec<Position<f64>> = vec![];
            for _ in 0..vertex_count {
                let x = rem.read_f64::<LittleEndian>().unwrap();
                let y = rem.read_f64::<LittleEndian>().unwrap();
                vertices.push(Position {
                    x: x,
                    y: y
                });
            }
            self.polygons.push(Polygon {
                grass: grass,
                vertices: vertices
            });
        }

        // Objects.
        let object_count = (rem.read_f64::<LittleEndian>().unwrap() - 0.4643643).round() as usize;
        for _ in 0..object_count {
            let x = rem.read_f64::<LittleEndian>().unwrap();
            let y = rem.read_f64::<LittleEndian>().unwrap();
            let position = Position { x: x, y: y };
            let object_type = match rem.read_i32::<LittleEndian>().unwrap() {
                1 => ObjectType::Exit,
                2 => ObjectType::Apple,
                3 => ObjectType::Killer,
                4 => ObjectType::Player,
                _ => panic!("Not a valid object type")
            };
            let gravity = rem.read_i32::<LittleEndian>().unwrap();
            let animation = rem.read_i32::<LittleEndian>().unwrap() + 1;

            self.objects.push(Object {
                position: position,
                object_type: object_type,
                gravity: gravity,
                animation: animation
            });
        }

        // Pictures.
        let picture_count = (rem.read_f64::<LittleEndian>().unwrap() - 0.2345672).round() as usize;
        for _ in 0..picture_count {
            let (name, temp_rem) = rem.split_at(10);
            rem = temp_rem;
            let name = trim_string(name).unwrap();
            let (texture, temp_rem) = rem.split_at(10);
            rem = temp_rem;
            let texture = trim_string(texture).unwrap();
            let (mask, temp_rem) = rem.split_at(10);
            rem = temp_rem;
            let mask = trim_string(mask).unwrap();
            let x = rem.read_f64::<LittleEndian>().unwrap();
            let y = rem.read_f64::<LittleEndian>().unwrap();
            let distance = rem.read_i32::<LittleEndian>().unwrap();
            let clip = rem.read_i32::<LittleEndian>().unwrap();

            self.pictures.push(Picture {
                name: name,
                texture: texture,
                mask: mask,
                position: Position { x: x, y: y },
                distance: distance,
                clip: clip
            });
        }

        // EOD marker expected at this point.
        let expected = rem.read_i32::<LittleEndian>().unwrap();
        if expected != EOD { panic!("EOD marker mismatch: x0{:x} != x0{:x}", expected, EOD); }

        // First decrypt the top10 blocks.
        let (mut top10, mut rem) = rem.split_at(688);
        let decrypted_top10_data = crypt_top10(top10);

        // Single-player list.
        let single = &decrypted_top10_data[0..344];
        self.top10_single = parse_top10(single);

        // Multi-player list.
        let multi = &decrypted_top10_data[344..688];
        self.top10_multi = parse_top10(multi);

        // EOF marker expected at this point.
        let expected = rem.read_i32::<LittleEndian>().unwrap();
        if expected != EOF { panic!("EOF marker mismatch: x0{:x} != x0{:x}", expected, EOF); }
    }

    /// Combines the Level struct fields to generate the raw binary data,
    /// and calculate integrity sums.
    fn update (&self) {
        // TODO: convert
        self.calculate_integrity_sums();
    }

    fn calculate_integrity_sums (&self) {
        // TODO: do that
    }

    /// Converts all struct fields into raw binary form and returns it.
    pub fn get_raw (self) -> Vec<u8> {
        self.update();
        self.raw
    }

    /// Saves level as a file.
    pub fn save_lev (self, filename: &str) {
        self.update();
        // let file = File::create(&filename).unwrap();
        // TODO: write stuff.
    }
}

/// Decrypt and encrypt top10 list data. Same algorithm for both.
pub fn crypt_top10 (top10: &[u8]) -> &[u8] {
    // Who knows
    let mut ebp8: i16 = 0x15;
    let mut ebp10: i16 = 0x2637;

    for mut t in top10.iter_mut().take(688) {
        *t ^= (ebp8 & 0xFF) as u8;
        ebp10 = ebp10.wrapping_add((ebp8.wrapping_rem(0xD3D)).wrapping_mul(0xD3D));
        ebp8 = ebp10.wrapping_mul(0x1F).wrapping_add(0xD3D);
    }

    top10
}

/// Parse top10 lists and return a vector of `ListEntry`s
pub fn parse_top10 (top10: &[u8]) -> Vec<ListEntry> {
    let mut list: Vec<ListEntry> = vec![];
    let times = LittleEndian::read_i32(&top10[0..4]);
    for n in 0..times {
        let time_offset = (4 + n * 4) as usize;
        let time_end = time_offset + 4;
        let name_1_offset = (44 + n * 15) as usize;
        let name_1_end = name_1_offset + 15;
        let name_2_offset = (194 + n * 15) as usize;
        let name_2_end = name_2_offset + 15;
        // All of this pains me even though I don't understand it...
        let name_1 = &top10[name_1_offset..name_1_end];
        let name_2 = &top10[name_2_offset..name_2_end];
        list.push(ListEntry {
            time: LittleEndian::read_i32(&top10[time_offset..time_end]),
            name_1: trim_string(name_1).unwrap(),
            name_2: trim_string(name_2).unwrap()
        });
    }
    list
}
<|endoftext|>


<commit_before>mod base;
pub mod mpsc;

pub use base::Future;
pub use base::FutureThen;
pub use base::FutureBind;
pub use base::FutureWrap;
pub use base::lift;

pub use mpsc::ChannelFuture;
<commit_msg>docs: Add crate top level docs<commit_after>//! A simple library for composing the results of future computation results with a minimal
//! overhad.
//!
//! The library does not concern itself with the way that the future result is obtained.
//!
//! It exports the `Future` trait, which is in essence quite similar to the `Iterator` trait.
//! Implementors are required to state which type their `Future` implementation produces and
//! provide the implementation of a single method---`await`---which blocks the running thread
//! and eventually returns an instance of the declared type.
//!
//! The `Future` trait itself provides implementations of methods that allow any `Future`'s
//! implementation to be composed by way of Functor/Monad functions. Therefore, to create a
//! new computation that depends on the future value behind any `Future` implementation, the
//! following can be used:
//!
//! ```rust
//! use zukunft::{Future, lift};
//! // Create a Future that whose await method would immediately resolve to the given value
//! let future = lift(5u8);
//! // Create a computation that would double the original future's value. This, of course,
//! // also returns a future.
//! let future = future.map(|val| 2*val);
//! // Once we have that, increment the value by one
//! let future = future.map(|val| val + 1);
//! // Finally we've set up the computations that should be performed and we sit and wait
//! // for it.
//! assert_eq!(future.await(), 11);
//! ```
//!
//! Additionally, a computation can depend on multiple future results:
//!
//! ```rust
//! use zukunft::{Future, lift};
//! let first = lift(5u8);
//! let second = lift(2u8);
//! let future = first.bind(|val1| {
//!     second.map(move |val2| val1 + val2)
//! });
//! assert_eq!(future.await(), 7);
//! ```
//!
//! Finally, the `mpsc` module provides a simple `Future` implementation that waits for
//! a value to become available on an `std::mpsc` channel before resoloving the future.
//!
//! ```rust
//! use std::thread;
//! use zukunft::{Future, ChannelFuture};
//! let (future, resolver) = ChannelFuture::new();
//! // We can compose computations on top of the future, even if its value is unknown
//! // as of yet...
//! let future = future.map(|val| 2*val);
//! // Resolve the future from a different thread...
//! thread::spawn(move || resolver.send(2u8).unwrap());
//! assert_eq!(future.await(), 4);
//! ```
//!
//! As can be seen from the short examples, the library is not concerned with integrating
//! with any event-loop style mechanism that would allow the computations to automatically
//! run whenever the underlying value resolves. Rather, its only (and quite humble) goal is
//! to provide an API for composing computations on top of results that are not immediately
//! available.
//!
//! Check out [eventual](https://github.com/carllerche/eventual) or
//! [gj](https://github.com/dwrensha/gj) for a future implementation that is async/evented.

mod base;
pub mod mpsc;

pub use base::Future;
pub use base::FutureThen;
pub use base::FutureBind;
pub use base::FutureWrap;
pub use base::lift;

pub use mpsc::ChannelFuture;
<|endoftext|>


<commit_before>// Module for parsing ISO Base Media Format aka video/mp4 streams.

// 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 https://mozilla.org/MPL/2.0/.

/// Basic ISO box structure.
pub struct BoxHeader {
    /// Four character box type
pub name: u32,
    /// Size of the box in bytes
pub size: u64,
    /// Offset to the start of the contained data (or header size).
pub offset: u64,
}

/// File type box 'ftyp'.
pub struct FileTypeBox {
    name: u32,
    size: u64,
    major_brand: u32,
    minor_version: u32,
    compatible_brands: Vec<u32>,
}

/// Movie header box 'mvhd'.
pub struct MovieHeaderBox {
    pub name: u32,
    pub size: u64,
    pub timescale: u32,
    pub duration: u64,
    // Ignore other fields.
}

pub struct TrackHeaderBox {
    pub name: u32,
    pub size: u64,
    pub track_id: u32,
    pub duration: u64,
    pub width: u32,
    pub height: u32,
}

extern crate byteorder;
use byteorder::{BigEndian, ReadBytesExt};
use std::io::{Read, Result, Seek, SeekFrom, Take};
use std::io::Cursor;

/// Parse a box out of a data buffer.
pub fn read_box_header<T: ReadBytesExt>(src: &mut T) -> Option<BoxHeader> {
    let tmp_size = src.read_u32::<BigEndian>().unwrap();
    let name = src.read_u32::<BigEndian>().unwrap();
    let size = match tmp_size {
        1 => src.read_u64::<BigEndian>().unwrap(),
        _ => tmp_size as u64,
    };
    assert!(size >= 8);
    if tmp_size == 1 {
        assert!(size >= 16);
    }
    let offset = match tmp_size {
        1 => 4 + 4 + 8,
        _ => 4 + 4,
    };
    assert!(offset <= size);
    Some(BoxHeader{
        name: name,
        size: size,
        offset: offset,
    })
}

/// Parse the extra header fields for a full box.
fn read_fullbox_extra<T: ReadBytesExt>(src: &mut T) -> (u8, u32) {
    let version = src.read_u8().unwrap();
    let flags_a = src.read_u8().unwrap();
    let flags_b = src.read_u8().unwrap();
    let flags_c = src.read_u8().unwrap();
    (version, (flags_a as u32) << 16 |
              (flags_b as u32) <<  8 |
              (flags_c as u32))
}

/// Skip over the contents of a box.
pub fn skip_box_content<T: ReadBytesExt + Seek>
  (src: &mut T, header: &BoxHeader)
  -> std::io::Result<u64>
{
    src.seek(SeekFrom::Current((header.size - header.offset) as i64))
}

/// Helper to construct a Take over the contents of a box.
fn limit<'a, T: Read>(f: &'a mut T, h: &BoxHeader) -> Take<&'a mut T> {
    f.take(h.size - h.offset)
}

/// Helper to construct a Cursor over the contents of a box.
fn recurse<T: Read>(f: &mut T, h: &BoxHeader) {
    println!("{} -- recursing", h);
    // FIXME: I couldn't figure out how to do this without copying.
    // We use Seek on the Read we return in skip_box_content, but
    // that trait isn't implemented for a Take like our limit()
    // returns. Slurping the buffer and wrapping it in a Cursor
    // functions as a work around.
    let buf: Vec<u8> = limit(f, &h)
        .bytes()
        .map(|u| u.unwrap())
        .collect();
    let mut content = Cursor::new(buf);
    loop {
        read_box(&mut content);
    }
    println!("{} -- end", h);
}

/// Read the contents of a box, including sub boxes.
/// Right now it just prints the box value rather than
/// returning anything.
pub fn read_box<T: Read + Seek>(f: &mut T) {
    read_box_header(f).and_then(|h| {
        match &(fourcc_to_string(h.name))[..] {
            "ftyp" => {
                let mut content = limit(f, &h);
                let ftyp = read_ftyp(&mut content, &h).unwrap();
                println!("{}", ftyp);
            },
            "moov" => recurse(f, &h),
            "mvhd" => {
                let mut content = limit(f, &h);
                let mvhd = read_mvhd(&mut content, &h).unwrap();
                println!("  {}", mvhd);
            },
            "trak" => recurse(f, &h),
            "tkhd" => {
                let mut content = limit(f, &h);
                let tkhd = read_tkhd(&mut content, &h).unwrap();
                println!("  {}", tkhd);
            },
            _ => {
                // Skip the contents of unknown chunks.
                println!("{}", h);
                skip_box_content(f, &h).unwrap();
            },
        };
        Some(()) // and_then needs an Option to return.
    });
}

/// Parse an ftype box.
pub fn read_ftyp<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
  -> Option<FileTypeBox> {
    let major = src.read_u32::<BigEndian>().unwrap();
    let minor = src.read_u32::<BigEndian>().unwrap();
    let brand_count = (head.size - 8 - 8) /4;
    let mut brands = Vec::new();
    for _ in 0..brand_count {
        brands.push(src.read_u32::<BigEndian>().unwrap());
    }
    Some(FileTypeBox{
        name: head.name,
        size: head.size,
        major_brand: major,
        minor_version: minor,
        compatible_brands: brands,
    })
}

/// Parse an mvhd box.
pub fn read_mvhd<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
  -> Option<MovieHeaderBox> {
    let (version, _) = read_fullbox_extra(src);
    match version {
        1 => {
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 16];
            let r = src.read(&mut skip).unwrap();
            assert!(r == skip.len());
        },
        0 => {
            // 32 bit creation and modification times.
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 8];
            let r = src.read(&mut skip).unwrap();
            assert!(r == skip.len());
        },
        _ => panic!("invalid mhdr version"),
    }
    let timescale = src.read_u32::<BigEndian>().unwrap();
    let duration = match version {
        1 => src.read_u64::<BigEndian>().unwrap(),
        0 => src.read_u32::<BigEndian>().unwrap() as u64,
        _ => panic!("invalid mhdr version"),
    };
    // Skip remaining fields.
    let mut skip: Vec<u8> = vec![0; 80];
    let r = src.read(&mut skip).unwrap();
    assert!(r == skip.len());
    Some(MovieHeaderBox {
        name: head.name,
        size: head.size,
        timescale: timescale,
        duration: duration,
    })
}

/// Parse a tkhd box.
pub fn read_tkhd<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
  -> Option<TrackHeaderBox> {
    let (version, flags) = read_fullbox_extra(src);
    if flags & 0x1u32 == 0 || flags & 0x2u32 == 0 {
        // Track is disabled.
        return None;
    }
    match version {
        1 => {
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 16];
            let r = src.read(&mut skip).unwrap();
            assert!(r == skip.len());
        },
        0 => {
            // 32 bit creation and modification times.
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 8];
            let r = src.read(&mut skip).unwrap();
            assert!(r == skip.len());
        },
        _ => panic!("invalid tkhd version"),
    }
    let track_id = src.read_u32::<BigEndian>().unwrap();
    let _reserved = src.read_u32::<BigEndian>().unwrap();
    assert!(_reserved == 0);
    let duration = match version {
        1 => {
            src.read_u64::<BigEndian>().unwrap()
        },
        0 => src.read_u32::<BigEndian>().unwrap() as u64,
        _ => panic!("invalid tkhd version"),
    };
    let _reserved = src.read_u32::<BigEndian>().unwrap();
    let _reserved = src.read_u32::<BigEndian>().unwrap();
    // Skip uninterested fields.
    let mut skip: Vec<u8> = vec![0; 44];
    let r = src.read(&mut skip).unwrap();
    assert!(r == skip.len());
    let width = src.read_u32::<BigEndian>().unwrap();
    let height = src.read_u32::<BigEndian>().unwrap();
    Some(TrackHeaderBox {
        name: head.name,
        size: head.size,
        track_id: track_id,
        duration: duration,
        width: width,
        height: height,
    })
}

/// Convert the iso box type or other 4-character value to a string.
pub fn fourcc_to_string(name: u32) -> String {
    let u32_to_vec = |u| {
        vec!((u >> 24 & 0xffu32) as u8,
             (u >> 16 & 0xffu32) as u8,
             (u >>  8 & 0xffu32) as u8,
             (u & 0xffu32) as u8)
    };
    let name_bytes = u32_to_vec(name);
    String::from_utf8_lossy(&name_bytes).into_owned()
}

use std::fmt;
impl fmt::Display for BoxHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "'{}' {} bytes", fourcc_to_string(self.name), self.size)
    }
}

impl fmt::Display for FileTypeBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = fourcc_to_string(self.name);
        let brand = fourcc_to_string(self.major_brand);
        write!(f, "'{}' {} bytes '{}' v{}", name, self.size,
            brand, self.minor_version)
    }
}

impl fmt::Display for MovieHeaderBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = fourcc_to_string(self.name);
        write!(f, "'{}' {} bytes duration {}s", name, self.size,
            (self.duration as f64)/(self.timescale as f64))
    }
}

impl fmt::Display for TrackHeaderBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = fourcc_to_string(self.name);
        write!(f, "'{}' {} bytes id {} {}x{}",
            name, self.size, self.track_id,
            self.width, self.height)
    }
}

#[test]
fn test_read_box_header() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 8];  // minimal box length
    write!(&mut test, "test").unwrap(); // box type
    let mut stream = Cursor::new(test);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, 1952805748);
    assert_eq!(parsed.size, 8);
    println!("box {}", parsed);
}

#[test]
fn test_read_box_header_long() {
    use std::io::Cursor;
    let mut test: Vec<u8> = vec![0, 0, 0, 1]; // long box extension code
    test.extend("long".to_string().into_bytes()); // box type
    test.extend(vec![0, 0, 0, 0, 0, 0, 16, 0]); // 64 bit size
    // Skip generating box content.
    let mut stream = Cursor::new(test);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, 1819242087);
    assert_eq!(parsed.size, 4096);
    println!("box {}", parsed);
}

#[test]
fn test_read_ftyp() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 24]; // size
    write!(&mut test, "ftyp").unwrap(); // type
    write!(&mut test, "mp42").unwrap(); // major brand
    test.extend(vec![0, 0, 0, 0]);      // minor version
    write!(&mut test, "isom").unwrap(); // compatible brands...
    write!(&mut test, "mp42").unwrap();
    assert_eq!(test.len(), 24);

    let mut stream = Cursor::new(test);
    let header = read_box_header(&mut stream).unwrap();
    let parsed = read_ftyp(&mut stream, &header).unwrap();
    assert_eq!(parsed.name, 1718909296);
    assert_eq!(parsed.size, 24);
    assert_eq!(parsed.major_brand, 1836069938);
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
    println!("box {}", parsed);
}
<commit_msg>Don't export fourcc_to_string.<commit_after>// Module for parsing ISO Base Media Format aka video/mp4 streams.

// 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 https://mozilla.org/MPL/2.0/.

/// Basic ISO box structure.
pub struct BoxHeader {
    /// Four character box type
pub name: u32,
    /// Size of the box in bytes
pub size: u64,
    /// Offset to the start of the contained data (or header size).
pub offset: u64,
}

/// File type box 'ftyp'.
pub struct FileTypeBox {
    name: u32,
    size: u64,
    major_brand: u32,
    minor_version: u32,
    compatible_brands: Vec<u32>,
}

/// Movie header box 'mvhd'.
pub struct MovieHeaderBox {
    pub name: u32,
    pub size: u64,
    pub timescale: u32,
    pub duration: u64,
    // Ignore other fields.
}

pub struct TrackHeaderBox {
    pub name: u32,
    pub size: u64,
    pub track_id: u32,
    pub duration: u64,
    pub width: u32,
    pub height: u32,
}

extern crate byteorder;
use byteorder::{BigEndian, ReadBytesExt};
use std::io::{Read, Result, Seek, SeekFrom, Take};
use std::io::Cursor;

/// Parse a box out of a data buffer.
pub fn read_box_header<T: ReadBytesExt>(src: &mut T) -> Option<BoxHeader> {
    let tmp_size = src.read_u32::<BigEndian>().unwrap();
    let name = src.read_u32::<BigEndian>().unwrap();
    let size = match tmp_size {
        1 => src.read_u64::<BigEndian>().unwrap(),
        _ => tmp_size as u64,
    };
    assert!(size >= 8);
    if tmp_size == 1 {
        assert!(size >= 16);
    }
    let offset = match tmp_size {
        1 => 4 + 4 + 8,
        _ => 4 + 4,
    };
    assert!(offset <= size);
    Some(BoxHeader{
        name: name,
        size: size,
        offset: offset,
    })
}

/// Parse the extra header fields for a full box.
fn read_fullbox_extra<T: ReadBytesExt>(src: &mut T) -> (u8, u32) {
    let version = src.read_u8().unwrap();
    let flags_a = src.read_u8().unwrap();
    let flags_b = src.read_u8().unwrap();
    let flags_c = src.read_u8().unwrap();
    (version, (flags_a as u32) << 16 |
              (flags_b as u32) <<  8 |
              (flags_c as u32))
}

/// Skip over the contents of a box.
pub fn skip_box_content<T: ReadBytesExt + Seek>
  (src: &mut T, header: &BoxHeader)
  -> std::io::Result<u64>
{
    src.seek(SeekFrom::Current((header.size - header.offset) as i64))
}

/// Helper to construct a Take over the contents of a box.
fn limit<'a, T: Read>(f: &'a mut T, h: &BoxHeader) -> Take<&'a mut T> {
    f.take(h.size - h.offset)
}

/// Helper to construct a Cursor over the contents of a box.
fn recurse<T: Read>(f: &mut T, h: &BoxHeader) {
    println!("{} -- recursing", h);
    // FIXME: I couldn't figure out how to do this without copying.
    // We use Seek on the Read we return in skip_box_content, but
    // that trait isn't implemented for a Take like our limit()
    // returns. Slurping the buffer and wrapping it in a Cursor
    // functions as a work around.
    let buf: Vec<u8> = limit(f, &h)
        .bytes()
        .map(|u| u.unwrap())
        .collect();
    let mut content = Cursor::new(buf);
    loop {
        read_box(&mut content);
    }
    println!("{} -- end", h);
}

/// Read the contents of a box, including sub boxes.
/// Right now it just prints the box value rather than
/// returning anything.
pub fn read_box<T: Read + Seek>(f: &mut T) {
    read_box_header(f).and_then(|h| {
        match &(fourcc_to_string(h.name))[..] {
            "ftyp" => {
                let mut content = limit(f, &h);
                let ftyp = read_ftyp(&mut content, &h).unwrap();
                println!("{}", ftyp);
            },
            "moov" => recurse(f, &h),
            "mvhd" => {
                let mut content = limit(f, &h);
                let mvhd = read_mvhd(&mut content, &h).unwrap();
                println!("  {}", mvhd);
            },
            "trak" => recurse(f, &h),
            "tkhd" => {
                let mut content = limit(f, &h);
                let tkhd = read_tkhd(&mut content, &h).unwrap();
                println!("  {}", tkhd);
            },
            _ => {
                // Skip the contents of unknown chunks.
                println!("{}", h);
                skip_box_content(f, &h).unwrap();
            },
        };
        Some(()) // and_then needs an Option to return.
    });
}

/// Parse an ftype box.
pub fn read_ftyp<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
  -> Option<FileTypeBox> {
    let major = src.read_u32::<BigEndian>().unwrap();
    let minor = src.read_u32::<BigEndian>().unwrap();
    let brand_count = (head.size - 8 - 8) /4;
    let mut brands = Vec::new();
    for _ in 0..brand_count {
        brands.push(src.read_u32::<BigEndian>().unwrap());
    }
    Some(FileTypeBox{
        name: head.name,
        size: head.size,
        major_brand: major,
        minor_version: minor,
        compatible_brands: brands,
    })
}

/// Parse an mvhd box.
pub fn read_mvhd<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
  -> Option<MovieHeaderBox> {
    let (version, _) = read_fullbox_extra(src);
    match version {
        1 => {
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 16];
            let r = src.read(&mut skip).unwrap();
            assert!(r == skip.len());
        },
        0 => {
            // 32 bit creation and modification times.
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 8];
            let r = src.read(&mut skip).unwrap();
            assert!(r == skip.len());
        },
        _ => panic!("invalid mhdr version"),
    }
    let timescale = src.read_u32::<BigEndian>().unwrap();
    let duration = match version {
        1 => src.read_u64::<BigEndian>().unwrap(),
        0 => src.read_u32::<BigEndian>().unwrap() as u64,
        _ => panic!("invalid mhdr version"),
    };
    // Skip remaining fields.
    let mut skip: Vec<u8> = vec![0; 80];
    let r = src.read(&mut skip).unwrap();
    assert!(r == skip.len());
    Some(MovieHeaderBox {
        name: head.name,
        size: head.size,
        timescale: timescale,
        duration: duration,
    })
}

/// Parse a tkhd box.
pub fn read_tkhd<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
  -> Option<TrackHeaderBox> {
    let (version, flags) = read_fullbox_extra(src);
    if flags & 0x1u32 == 0 || flags & 0x2u32 == 0 {
        // Track is disabled.
        return None;
    }
    match version {
        1 => {
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 16];
            let r = src.read(&mut skip).unwrap();
            assert!(r == skip.len());
        },
        0 => {
            // 32 bit creation and modification times.
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 8];
            let r = src.read(&mut skip).unwrap();
            assert!(r == skip.len());
        },
        _ => panic!("invalid tkhd version"),
    }
    let track_id = src.read_u32::<BigEndian>().unwrap();
    let _reserved = src.read_u32::<BigEndian>().unwrap();
    assert!(_reserved == 0);
    let duration = match version {
        1 => {
            src.read_u64::<BigEndian>().unwrap()
        },
        0 => src.read_u32::<BigEndian>().unwrap() as u64,
        _ => panic!("invalid tkhd version"),
    };
    let _reserved = src.read_u32::<BigEndian>().unwrap();
    let _reserved = src.read_u32::<BigEndian>().unwrap();
    // Skip uninterested fields.
    let mut skip: Vec<u8> = vec![0; 44];
    let r = src.read(&mut skip).unwrap();
    assert!(r == skip.len());
    let width = src.read_u32::<BigEndian>().unwrap();
    let height = src.read_u32::<BigEndian>().unwrap();
    Some(TrackHeaderBox {
        name: head.name,
        size: head.size,
        track_id: track_id,
        duration: duration,
        width: width,
        height: height,
    })
}

/// Convert the iso box type or other 4-character value to a string.
fn fourcc_to_string(name: u32) -> String {
    let u32_to_vec = |u| {
        vec!((u >> 24 & 0xffu32) as u8,
             (u >> 16 & 0xffu32) as u8,
             (u >>  8 & 0xffu32) as u8,
             (u & 0xffu32) as u8)
    };
    let name_bytes = u32_to_vec(name);
    String::from_utf8_lossy(&name_bytes).into_owned()
}

use std::fmt;
impl fmt::Display for BoxHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "'{}' {} bytes", fourcc_to_string(self.name), self.size)
    }
}

impl fmt::Display for FileTypeBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = fourcc_to_string(self.name);
        let brand = fourcc_to_string(self.major_brand);
        write!(f, "'{}' {} bytes '{}' v{}", name, self.size,
            brand, self.minor_version)
    }
}

impl fmt::Display for MovieHeaderBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = fourcc_to_string(self.name);
        write!(f, "'{}' {} bytes duration {}s", name, self.size,
            (self.duration as f64)/(self.timescale as f64))
    }
}

impl fmt::Display for TrackHeaderBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = fourcc_to_string(self.name);
        write!(f, "'{}' {} bytes id {} {}x{}",
            name, self.size, self.track_id,
            self.width, self.height)
    }
}

#[test]
fn test_read_box_header() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 8];  // minimal box length
    write!(&mut test, "test").unwrap(); // box type
    let mut stream = Cursor::new(test);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, 1952805748);
    assert_eq!(parsed.size, 8);
    println!("box {}", parsed);
}

#[test]
fn test_read_box_header_long() {
    use std::io::Cursor;
    let mut test: Vec<u8> = vec![0, 0, 0, 1]; // long box extension code
    test.extend("long".to_string().into_bytes()); // box type
    test.extend(vec![0, 0, 0, 0, 0, 0, 16, 0]); // 64 bit size
    // Skip generating box content.
    let mut stream = Cursor::new(test);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, 1819242087);
    assert_eq!(parsed.size, 4096);
    println!("box {}", parsed);
}

#[test]
fn test_read_ftyp() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 24]; // size
    write!(&mut test, "ftyp").unwrap(); // type
    write!(&mut test, "mp42").unwrap(); // major brand
    test.extend(vec![0, 0, 0, 0]);      // minor version
    write!(&mut test, "isom").unwrap(); // compatible brands...
    write!(&mut test, "mp42").unwrap();
    assert_eq!(test.len(), 24);

    let mut stream = Cursor::new(test);
    let header = read_box_header(&mut stream).unwrap();
    let parsed = read_ftyp(&mut stream, &header).unwrap();
    assert_eq!(parsed.name, 1718909296);
    assert_eq!(parsed.size, 24);
    assert_eq!(parsed.major_brand, 1836069938);
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
    println!("box {}", parsed);
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Semantic version parsing and comparison.
//!
//! Semantic versioning (see http://semver.org/) is a set of rules for
//! assigning version numbers.
//!
//! ## SemVer overview
//!
//! Given a version number MAJOR.MINOR.PATCH, increment the:
//!
//! 1. MAJOR version when you make incompatible API changes,
//! 2. MINOR version when you add functionality in a backwards-compatible
//!    manner, and
//! 3. PATCH version when you make backwards-compatible bug fixes.
//!
//! Additional labels for pre-release and build metadata are available as
//! extensions to the MAJOR.MINOR.PATCH format.
//!
//! Any references to 'the spec' in this documentation refer to [version 2.0 of
//! the SemVer spec](http://semver.org/spec/v2.0.0.html).
//!
//! ## SemVer and the Rust ecosystem
//!
//! Rust itself follows the SemVer specification, as does its standard
//! libraries. The two are not tied together.
//!
//! [Cargo](http://crates.io), Rust's package manager, uses SemVer to determine
//! which versions of packages you need installed.
//!
//! ## Versions
//!
//! At its simplest, the `semver` crate allows you to construct `Version`
//! objects using the `parse` method:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3") == Ok(Version {
//!    major: 1,
//!    minor: 2,
//!    patch: 3,
//!    pre: vec!(),
//!    build: vec!(),
//! }));
//! ```
//!
//! If you have multiple `Version`s, you can use the usual comparison operators
//! to compare them:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta"));
//! assert!(Version::parse("1.2.3-alpha2") >  Version::parse("1.2.0"));
//! ```
//!
//! If you explicitly need to modify a Version, SemVer also allows you to
//! increment the major, minor, and patch numbers in accordance with the spec.
//!
//! Please note that in order to do this, you must use a mutable Version:
//!
//! ```{rust}
//! use semver::Version;
//! use std::error::Error;
//!
//! # fn try_increment_patch() -> Result<(), Box<Error>> {
//! let mut bugfix_release = Version::parse("1.0.0")?;
//! bugfix_release.increment_patch();
//!
//! assert_eq!(Ok(bugfix_release), Version::parse("1.0.1"));
//!
//! #    Ok(())
//! # }
//! # fn main() {
//! #    try_increment_patch().unwrap();
//! # }
//! ```
//!
//! When incrementing the minor version number, the patch number resets to zero
//! (in accordance with section 7 of the spec)
//!
//! ```{rust}
//! use semver::Version;
//! use std::error::Error;
//!
//! # fn try_increment_minor() -> Result<(), Box<Error>> {
//! let mut feature_release = Version::parse("1.4.6")?;
//! feature_release.increment_minor();
//!
//! assert_eq!(Ok(feature_release), Version::parse("1.5.0"));
//!
//! #   Ok(())
//! # }
//! # fn main() {
//! #    try_increment_minor().unwrap();
//! # }
//! ```
//!
//! Similarly, when incrementing the major version number, the patch and minor
//! numbers reset to zero (in accordance with section 8 of the spec)
//!
//! ```{rust}
//! use semver::Version;
//! use std::error::Error;
//!
//! # fn try_increment_major() -> Result<(), Box<Error>> {
//! let mut chrome_release = Version::parse("41.5.5377")?;
//! chrome_release.increment_major();
//!
//! assert_eq!(Ok(chrome_release), Version::parse("42.0.0"));
//!
//! #    Ok(())
//! # }
//! # fn main() {
//! #    try_increment_major().unwrap();
//! # }
//! ```
//!
//! ## Requirements
//!
//! The `semver` crate also provides the ability to compare requirements, which
//! are more complex comparisons.
//!
//! For example, creating a requirement that only matches versions greater than
//! or equal to 1.0.0:
//!
//! ```{rust}
//! # #![allow(unstable)]
//! use semver::Version;
//! use semver::VersionReq;
//! use std::error::Error;
//!
//! # fn try_compare() -> Result<(), Box<Error>> {
//! let r = VersionReq::parse(">= 1.0.0")?;
//! let v = Version::parse("1.0.0")?;
//!
//! assert!(r.to_string() == ">= 1.0.0".to_string());
//! assert!(r.matches(&v));
//!
//! #    Ok(())
//! # }
//! # fn main() {
//! #    try_compare().unwrap();
//! # }
//! ```
//!
//! It also allows parsing of `~x.y.z` and `^x.y.z` requirements as defined at
//! https://www.npmjs.org/doc/misc/semver.html
//!
//! **Tilde requirements** specify a minimal version with some updates:
//!
//! ```notrust
//! ~1.2.3 := >=1.2.3 <1.3.0
//! ~1.2   := >=1.2.0 <1.3.0
//! ~1     := >=1.0.0 <2.0.0
//! ```
//!
//! **Caret requirements** allow SemVer compatible updates to a specified
//! verion, `0.x` and `0.x+1` are not considered compatible, but `1.x` and
//! `1.x+1` are.
//!
//! `0.0.x` is not considered compatible with any other version.
//! Missing minor and patch versions are desugared to `0` but allow flexibility
//! for that value.
//!
//! ```notrust
//! ^1.2.3 := >=1.2.3 <2.0.0
//! ^0.2.3 := >=0.2.3 <0.3.0
//! ^0.0.3 := >=0.0.3 <0.0.4
//! ^0.0   := >=0.0.0 <0.1.0
//! ^0     := >=0.0.0 <1.0.0
//! ```
//!
//! **Wildcard requirements** allows parsing of version requirements of the
//! formats `*`, `x.*` and `x.y.*`.
//!
//! ```notrust
//! *     := >=0.0.0
//! 1.*   := >=1.0.0 <2.0.0
//! 1.2.* := >=1.2.0 <1.3.0
//! ```

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://www.rust-lang.org/favicon.ico",
       html_root_url = "https://docs.rs/semver")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

extern crate semver_parser;

// Serialization and deserialization support for version numbers
#[cfg(feature = "serde")]
extern crate serde;

// We take the common approach of keeping our own module system private, and
// just re-exporting the interface that we want.

pub use version::{Identifier, SemVerError, Version};
pub use version::Identifier::{AlphaNumeric, Numeric};
pub use version_req::{ReqParseError, VersionReq};

// SemVer-compliant versions.
mod version;

// advanced version comparisons
mod version_req;
<commit_msg>remove these extra newlines before the hidden lines<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Semantic version parsing and comparison.
//!
//! Semantic versioning (see http://semver.org/) is a set of rules for
//! assigning version numbers.
//!
//! ## SemVer overview
//!
//! Given a version number MAJOR.MINOR.PATCH, increment the:
//!
//! 1. MAJOR version when you make incompatible API changes,
//! 2. MINOR version when you add functionality in a backwards-compatible
//!    manner, and
//! 3. PATCH version when you make backwards-compatible bug fixes.
//!
//! Additional labels for pre-release and build metadata are available as
//! extensions to the MAJOR.MINOR.PATCH format.
//!
//! Any references to 'the spec' in this documentation refer to [version 2.0 of
//! the SemVer spec](http://semver.org/spec/v2.0.0.html).
//!
//! ## SemVer and the Rust ecosystem
//!
//! Rust itself follows the SemVer specification, as does its standard
//! libraries. The two are not tied together.
//!
//! [Cargo](http://crates.io), Rust's package manager, uses SemVer to determine
//! which versions of packages you need installed.
//!
//! ## Versions
//!
//! At its simplest, the `semver` crate allows you to construct `Version`
//! objects using the `parse` method:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3") == Ok(Version {
//!    major: 1,
//!    minor: 2,
//!    patch: 3,
//!    pre: vec!(),
//!    build: vec!(),
//! }));
//! ```
//!
//! If you have multiple `Version`s, you can use the usual comparison operators
//! to compare them:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta"));
//! assert!(Version::parse("1.2.3-alpha2") >  Version::parse("1.2.0"));
//! ```
//!
//! If you explicitly need to modify a Version, SemVer also allows you to
//! increment the major, minor, and patch numbers in accordance with the spec.
//!
//! Please note that in order to do this, you must use a mutable Version:
//!
//! ```{rust}
//! use semver::Version;
//! use std::error::Error;
//!
//! # fn try_increment_patch() -> Result<(), Box<Error>> {
//! let mut bugfix_release = Version::parse("1.0.0")?;
//! bugfix_release.increment_patch();
//!
//! assert_eq!(Ok(bugfix_release), Version::parse("1.0.1"));
//! #    Ok(())
//! # }
//! # fn main() {
//! #    try_increment_patch().unwrap();
//! # }
//! ```
//!
//! When incrementing the minor version number, the patch number resets to zero
//! (in accordance with section 7 of the spec)
//!
//! ```{rust}
//! use semver::Version;
//! use std::error::Error;
//!
//! # fn try_increment_minor() -> Result<(), Box<Error>> {
//! let mut feature_release = Version::parse("1.4.6")?;
//! feature_release.increment_minor();
//!
//! assert_eq!(Ok(feature_release), Version::parse("1.5.0"));
//! #   Ok(())
//! # }
//! # fn main() {
//! #    try_increment_minor().unwrap();
//! # }
//! ```
//!
//! Similarly, when incrementing the major version number, the patch and minor
//! numbers reset to zero (in accordance with section 8 of the spec)
//!
//! ```{rust}
//! use semver::Version;
//! use std::error::Error;
//!
//! # fn try_increment_major() -> Result<(), Box<Error>> {
//! let mut chrome_release = Version::parse("41.5.5377")?;
//! chrome_release.increment_major();
//!
//! assert_eq!(Ok(chrome_release), Version::parse("42.0.0"));
//! #    Ok(())
//! # }
//! # fn main() {
//! #    try_increment_major().unwrap();
//! # }
//! ```
//!
//! ## Requirements
//!
//! The `semver` crate also provides the ability to compare requirements, which
//! are more complex comparisons.
//!
//! For example, creating a requirement that only matches versions greater than
//! or equal to 1.0.0:
//!
//! ```{rust}
//! # #![allow(unstable)]
//! use semver::Version;
//! use semver::VersionReq;
//! use std::error::Error;
//!
//! # fn try_compare() -> Result<(), Box<Error>> {
//! let r = VersionReq::parse(">= 1.0.0")?;
//! let v = Version::parse("1.0.0")?;
//!
//! assert!(r.to_string() == ">= 1.0.0".to_string());
//! assert!(r.matches(&v));
//! #    Ok(())
//! # }
//! # fn main() {
//! #    try_compare().unwrap();
//! # }
//! ```
//!
//! It also allows parsing of `~x.y.z` and `^x.y.z` requirements as defined at
//! https://www.npmjs.org/doc/misc/semver.html
//!
//! **Tilde requirements** specify a minimal version with some updates:
//!
//! ```notrust
//! ~1.2.3 := >=1.2.3 <1.3.0
//! ~1.2   := >=1.2.0 <1.3.0
//! ~1     := >=1.0.0 <2.0.0
//! ```
//!
//! **Caret requirements** allow SemVer compatible updates to a specified
//! verion, `0.x` and `0.x+1` are not considered compatible, but `1.x` and
//! `1.x+1` are.
//!
//! `0.0.x` is not considered compatible with any other version.
//! Missing minor and patch versions are desugared to `0` but allow flexibility
//! for that value.
//!
//! ```notrust
//! ^1.2.3 := >=1.2.3 <2.0.0
//! ^0.2.3 := >=0.2.3 <0.3.0
//! ^0.0.3 := >=0.0.3 <0.0.4
//! ^0.0   := >=0.0.0 <0.1.0
//! ^0     := >=0.0.0 <1.0.0
//! ```
//!
//! **Wildcard requirements** allows parsing of version requirements of the
//! formats `*`, `x.*` and `x.y.*`.
//!
//! ```notrust
//! *     := >=0.0.0
//! 1.*   := >=1.0.0 <2.0.0
//! 1.2.* := >=1.2.0 <1.3.0
//! ```

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://www.rust-lang.org/favicon.ico",
       html_root_url = "https://docs.rs/semver")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

extern crate semver_parser;

// Serialization and deserialization support for version numbers
#[cfg(feature = "serde")]
extern crate serde;

// We take the common approach of keeping our own module system private, and
// just re-exporting the interface that we want.

pub use version::{Identifier, SemVerError, Version};
pub use version::Identifier::{AlphaNumeric, Numeric};
pub use version_req::{ReqParseError, VersionReq};

// SemVer-compliant versions.
mod version;

// advanced version comparisons
mod version_req;
<|endoftext|>


<commit_before>/*! The main Fastnet module.

This is the low-level API.  If your goal is extremely high-performance usage, this is the API you want.  See the blocking module for a simpler API which is less annoying for common use cases.*/
#![allow(warnings)]

extern crate byteorder;
extern crate mio;
extern crate crc;

mod packets;
mod server;
mod status_translator;

use std::{result, io, net};

///Represents a Fastnet error.
#[derive(Debug, Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
pub enum Error {
    TimedOut,
    HostNotFound,
    PeerNotFound,
    MessageTooLarge,
}

pub type Result<T> = result::Result<T, Error>;

/**A Fastnet server.

Fastnet does not distinguish between clients and servers.  This is used both for connecting to other peers and listening for incoming connections.*/
#[derive(Default)]
pub struct Server;

impl Server {
    pub fn new<H: Handler+Send>(addr: net::SocketAddr, handler: H)->Result<Server> {
        Ok(Server::default())
    }
}

/**An event handler.

The methods in this trait are called in a thread which is running in the background, not on the main thread.  None of them should ever block.*/
pub trait Handler {
    fn connected(&mut self, id: u64, request_id: Option<u64>);
    fn disconnected(&mut self, id: u64, request_id: Option<u64>);
    fn message(&mut self, id: u64, channel: u16, payload: &[u8]);
    fn request_failed(&mut self, request_id: u64, error: Error);
}
<commit_msg>Infrastructure to funnel Handlers down.<commit_after>/*! The main Fastnet module.

This is the low-level API.  If your goal is extremely high-performance usage, this is the API you want.  See the blocking module for a simpler API which is less annoying for common use cases.*/
#![allow(warnings)]

extern crate byteorder;
extern crate mio;
extern crate crc;

mod packets;
mod server;
mod status_translator;

use std::{result, io, net};

///Represents a Fastnet error.
#[derive(Debug, Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
pub enum Error {
    TimedOut,
    HostNotFound,
    PeerNotFound,
    MessageTooLarge,
}

pub type Result<T> = result::Result<T, Error>;

/**A Fastnet server.

Fastnet does not distinguish between clients and servers.  This is used both for connecting to other peers and listening for incoming connections.*/
#[derive(Default)]
pub struct Server;

impl Server {
    pub fn new<H: Handler+Send+'static>(addr: net::SocketAddr, handler: H)->Result<Server> {
        Ok(Server::default())
    }
}

/**An event handler.

The methods in this trait are called in a thread which is running in the background, not on the main thread.  None of them should ever block.*/
pub trait Handler {
    fn connected(&mut self, id: u64, request_id: Option<u64>);
    fn disconnected(&mut self, id: u64, request_id: Option<u64>);
    fn message(&mut self, id: u64, channel: u16, payload: &[u8]);
    fn request_failed(&mut self, request_id: u64, error: Error);
}
<|endoftext|>