<commit_before>#![allow(dead_code)]

use regex::Regex;
use std::collections::HashMap;
use lexer;

pub type Token = lexer::Token;
pub type Lexer = lexer::Lexer;

pub struct Parser {
    lexer: Lexer,
    variables: HashMap<String, f64>,
}

impl Parser {
    pub fn new() -> Self {
        Parser{lexer: Lexer::new(), variables: HashMap::new()}
    }
    pub fn parse(&mut self, input: String) -> Result<f64, String> {
        lazy_static! {
            static ref VAR_ASSIGN_RE: Regex = Regex::new(r"\A(([a-zA-Z]|_)+)=").unwrap();
            static ref VAR_USAGE_RE: Regex = Regex::new(r"([a-zA-Z]|_)+").unwrap();
            // Theoretical function matching might look like [a-zA-Z]+\( etc...
        }
        let mut internal_input = input.clone();
        let mut new_variable: String = String::default();
        if VAR_ASSIGN_RE.is_match(internal_input.as_ref()) {
            new_variable = String::from(VAR_ASSIGN_RE.captures(internal_input.as_ref()).unwrap().at(1).unwrap());
            internal_input = VAR_ASSIGN_RE.replace(internal_input.as_ref(), "");
        }
        while VAR_USAGE_RE.is_match(internal_input.as_ref()) {
            let variable = String::from(VAR_USAGE_RE.captures(internal_input.as_ref()).unwrap().at(0).unwrap());
            if let Some(value) = self.variables.get(&variable) {
                internal_input = VAR_USAGE_RE.replace(internal_input.as_ref(), &(value.to_string())[..]);
            } else {
                let mut msg = String::from("Unknown variable: ");
                msg.push_str(variable.as_ref());
                return Err(msg);
            }
        }
        self.lexer.set_input(internal_input);
        let expression_value: f64 = match self.expression() {
            Ok(v) => v,
            Err(msg) => return Err(msg)
        };
        let token: Token = match self.lexer.get_next_token() {
            Ok(t) => t,
            Err(msg) => return Err(msg)
        };
        match token.get_kind() {
            lexer::SubToken::End => {
                if new_variable != String::default() {
                    self.variables.insert(new_variable, expression_value);
                }
                return Ok(expression_value);
            }
            _ => {
                return Err(String::from("End expected"));
            }
        }
    }
    pub fn expression(&mut self) -> Result<f64, String> {
        let mut component1: f64 = match self.factor() {
            Ok(x) => x,
            Err(msg) => return Err(msg)
        };
        let mut token: Token = match self.lexer.get_next_token() {
            Ok(t) => t,
            Err(msg) => return Err(msg)
        };
        loop {
            match token.get_kind() {
                lexer::SubToken::Plus => {
                    let component2 = match self.factor() {
                        Ok(x) => x,
                        Err(msg) => return Err(msg)
                    };
                    component1 += component2;
                    token = match self.lexer.get_next_token() {
                        Ok(t) => t,
                        Err(msg) => return Err(msg)
                    };
                }
                lexer::SubToken::Minus => {
                    let component2 = match self.factor() {
                        Ok(x) => x,
                        Err(msg) => return Err(msg)
                    };
                    component1 -= component2;
                    token = match self.lexer.get_next_token() {
                        Ok(t) => t,
                        Err(msg) => return Err(msg)
                    };
                }
                _ => {
                    break;
                }
            }
        }
        self.lexer.revert();
        Ok(component1)
    }
    pub fn factor(&mut self) -> Result<f64, String> {
        let mut factor1: f64 = match self.number() {
            Ok(x) => x,
            Err(msg) => return Err(msg)
        };
        let mut token: Token = match self.lexer.get_next_token() {
            Ok(t) => t,
            Err(msg) => return Err(msg)
        };
        loop {
            match token.get_kind() {
                lexer::SubToken::Multiply => {
                    let factor2: f64 = match self.number() {
                        Ok(x) => x,
                        Err(msg) => return Err(msg)
                    };
                    factor1 *= factor2;
                    token = match self.lexer.get_next_token() {
                        Ok(t) => t,
                        Err(msg) => return Err(msg)
                    };
                }
                lexer::SubToken::Divide => {
                    let factor2: f64 = match self.number() {
                        Ok(x) => x,
                        Err(msg) => return Err(msg)
                    };
                    factor1 /= factor2;
                    token = match self.lexer.get_next_token() {
                        Ok(t) => t,
                        Err(msg) => return Err(msg)
                    };
                }
                lexer::SubToken::Power => {
                    let factor2: f64 = match self.number() {
                        Ok(x) => x,
                        Err(msg) => return Err(msg)
                    };
                    factor1 = factor1.powf(factor2);
                    token = match self.lexer.get_next_token() {
                        Ok(t) => t,
                        Err(msg) => return Err(msg)
                    };
                }
                lexer::SubToken::Modulo => {
                    let factor2: f64 = match self.number() {
                        Ok(x) => x,
                        Err(msg) => return Err(msg)
                    };
                    factor1 = factor1 % factor2;
                    token = match self.lexer.get_next_token() {
                        Ok(t) => t,
                        Err(msg) => return Err(msg)
                    };
                }
                _ => {
                    break;
                }
            }
        }
        self.lexer.revert();
        Ok(factor1)
    }
    pub fn number(&mut self) -> Result<f64, String> {
        let token: Token = match self.lexer.get_next_token() {
            Ok(t) => t,
            Err(msg) => return Err(msg)
        };
        let value: f64;
        match token.get_kind() {
            lexer::SubToken::LParen => {
                value = match self.expression() {
                    Ok(v) => v,
                    Err(msg) => return Err(msg)
                };
                match self.lexer.get_next_token() {
                    Err(msg) => return Err(msg),
                    _ => ()
                };
            }
            lexer::SubToken::Number => {
                value = match token.get_value() {
                    Some(v) => v,
                    None => return Err(String::from("No value"))
                };
            }
            lexer::SubToken::Minus => {
                value = match self.factor() {
                    Ok(x) => x*-1.0,
                    Err(msg) => return Err(msg)
                };
            }
            _ => {
                return Err(String::from("Not a number"));
            }
        }
        Ok(value)
    }
}<commit_msg>Added White space stripping to Parser<commit_after>#![allow(dead_code)]

use regex::Regex;
use std::collections::HashMap;
use lexer;

pub type Token = lexer::Token;
pub type Lexer = lexer::Lexer;

pub struct Parser {
    lexer: Lexer,
    variables: HashMap<String, f64>,
}

impl Parser {
    pub fn new() -> Self {
        Parser{lexer: Lexer::new(), variables: HashMap::new()}
    }
    pub fn parse(&mut self, input: String) -> Result<f64, String> {
        lazy_static! {
            static ref VAR_ASSIGN_RE: Regex = Regex::new(r"\A(([a-zA-Z]|_)+)=").unwrap();
            static ref VAR_USAGE_RE: Regex = Regex::new(r"([a-zA-Z]|_)+").unwrap();
            // Theoretical function matching might look like [a-zA-Z]+\( etc...
        }
        let mut internal_input = strip_white_space(input);
        let mut new_variable: String = String::default();
        if VAR_ASSIGN_RE.is_match(internal_input.as_ref()) {
            new_variable = String::from(VAR_ASSIGN_RE.captures(internal_input.as_ref()).unwrap().at(1).unwrap());
            internal_input = VAR_ASSIGN_RE.replace(internal_input.as_ref(), "");
        }
        while VAR_USAGE_RE.is_match(internal_input.as_ref()) {
            let variable = String::from(VAR_USAGE_RE.captures(internal_input.as_ref()).unwrap().at(0).unwrap());
            if let Some(value) = self.variables.get(&variable) {
                internal_input = VAR_USAGE_RE.replace(internal_input.as_ref(), &(value.to_string())[..]);
            } else {
                let mut msg = String::from("Unknown variable: ");
                msg.push_str(variable.as_ref());
                return Err(msg);
            }
        }
        self.lexer.set_input(internal_input);
        let expression_value: f64 = match self.expression() {
            Ok(v) => v,
            Err(msg) => return Err(msg)
        };
        let token: Token = match self.lexer.get_next_token() {
            Ok(t) => t,
            Err(msg) => return Err(msg)
        };
        match token.get_kind() {
            lexer::SubToken::End => {
                if new_variable != String::default() {
                    self.variables.insert(new_variable, expression_value);
                }
                return Ok(expression_value);
            }
            _ => {
                return Err(String::from("End expected"));
            }
        }
    }
    pub fn expression(&mut self) -> Result<f64, String> {
        let mut component1: f64 = match self.factor() {
            Ok(x) => x,
            Err(msg) => return Err(msg)
        };
        let mut token: Token = match self.lexer.get_next_token() {
            Ok(t) => t,
            Err(msg) => return Err(msg)
        };
        loop {
            match token.get_kind() {
                lexer::SubToken::Plus => {
                    let component2 = match self.factor() {
                        Ok(x) => x,
                        Err(msg) => return Err(msg)
                    };
                    component1 += component2;
                    token = match self.lexer.get_next_token() {
                        Ok(t) => t,
                        Err(msg) => return Err(msg)
                    };
                }
                lexer::SubToken::Minus => {
                    let component2 = match self.factor() {
                        Ok(x) => x,
                        Err(msg) => return Err(msg)
                    };
                    component1 -= component2;
                    token = match self.lexer.get_next_token() {
                        Ok(t) => t,
                        Err(msg) => return Err(msg)
                    };
                }
                _ => {
                    break;
                }
            }
        }
        self.lexer.revert();
        Ok(component1)
    }
    pub fn factor(&mut self) -> Result<f64, String> {
        let mut factor1: f64 = match self.number() {
            Ok(x) => x,
            Err(msg) => return Err(msg)
        };
        let mut token: Token = match self.lexer.get_next_token() {
            Ok(t) => t,
            Err(msg) => return Err(msg)
        };
        loop {
            match token.get_kind() {
                lexer::SubToken::Multiply => {
                    let factor2: f64 = match self.number() {
                        Ok(x) => x,
                        Err(msg) => return Err(msg)
                    };
                    factor1 *= factor2;
                    token = match self.lexer.get_next_token() {
                        Ok(t) => t,
                        Err(msg) => return Err(msg)
                    };
                }
                lexer::SubToken::Divide => {
                    let factor2: f64 = match self.number() {
                        Ok(x) => x,
                        Err(msg) => return Err(msg)
                    };
                    factor1 /= factor2;
                    token = match self.lexer.get_next_token() {
                        Ok(t) => t,
                        Err(msg) => return Err(msg)
                    };
                }
                lexer::SubToken::Power => {
                    let factor2: f64 = match self.number() {
                        Ok(x) => x,
                        Err(msg) => return Err(msg)
                    };
                    factor1 = factor1.powf(factor2);
                    token = match self.lexer.get_next_token() {
                        Ok(t) => t,
                        Err(msg) => return Err(msg)
                    };
                }
                lexer::SubToken::Modulo => {
                    let factor2: f64 = match self.number() {
                        Ok(x) => x,
                        Err(msg) => return Err(msg)
                    };
                    factor1 = factor1 % factor2;
                    token = match self.lexer.get_next_token() {
                        Ok(t) => t,
                        Err(msg) => return Err(msg)
                    };
                }
                _ => {
                    break;
                }
            }
        }
        self.lexer.revert();
        Ok(factor1)
    }
    pub fn number(&mut self) -> Result<f64, String> {
        let token: Token = match self.lexer.get_next_token() {
            Ok(t) => t,
            Err(msg) => return Err(msg)
        };
        let value: f64;
        match token.get_kind() {
            lexer::SubToken::LParen => {
                value = match self.expression() {
                    Ok(v) => v,
                    Err(msg) => return Err(msg)
                };
                match self.lexer.get_next_token() {
                    Err(msg) => return Err(msg),
                    _ => ()
                };
            }
            lexer::SubToken::Number => {
                value = match token.get_value() {
                    Some(v) => v,
                    None => return Err(String::from("No value"))
                };
            }
            lexer::SubToken::Minus => {
                value = match self.factor() {
                    Ok(x) => x*-1.0,
                    Err(msg) => return Err(msg)
                };
            }
            _ => {
                return Err(String::from("Not a number"));
            }
        }
        Ok(value)
    }
}

fn strip_white_space(input: String) -> String {
    input.split_whitespace().collect::<Vec<&str>>().join("")
}<|endoftext|>


<commit_before>use std::str::from_utf8;
use std::result::Result;
use nom::*;

/*
 * Core structs
 */

#[derive(Debug,PartialEq,Eq)]
pub struct TarEntry<'a> {
    pub header:   PosixHeader<'a>,
    pub contents: &'a [u8]
}

#[derive(Debug,PartialEq,Eq)]
pub struct PosixHeader<'a> {
    pub name:     &'a str,
    pub mode:     &'a str,
    pub uid:      u64,
    pub gid:      u64,
    pub size:     u64,
    pub mtime:    u64,
    pub chksum:   &'a str,
    pub typeflag: TypeFlag,
    pub linkname: &'a str,
    pub ustar:    ExtraHeader<'a>
}

/* TODO: support vendor specific */
#[derive(Debug,PartialEq,Eq)]
pub enum TypeFlag {
    NormalFile,
    HardLink,
    SymbolicLink,
    CharacterSpecial,
    BlockSpecial,
    Directory,
    FIFO,
    ContiguousFile,
    PaxInterexchangeFormat,
    PaxExtendedAttributes,
    VendorSpecific
}

#[derive(Debug,PartialEq,Eq)]
pub enum ExtraHeader<'a> {
    UStar(UStarHeader<'a>),
    Padding
}

#[derive(Debug,PartialEq,Eq)]
pub struct UStarHeader<'a> {
    pub magic:    &'a str,
    pub version:  &'a str,
    pub uname:    &'a str,
    pub gname:    &'a str,
    pub devmajor: u64,
    pub devminor: u64,
    pub extra:    UStarExtraHeader<'a>
}

#[derive(Debug,PartialEq,Eq)]
pub enum UStarExtraHeader<'a> {
    PosixUStar(PosixUStarHeader<'a>),
    Pax(PaxHeader<'a>)
}

#[derive(Debug,PartialEq,Eq)]
pub struct PosixUStarHeader<'a> {
    pub prefix: &'a str
}

#[derive(Debug,PartialEq,Eq)]
pub struct PaxHeader<'a> {
    pub atime:      u64,
    pub ctime:      u64,
    pub offset:     u64,
    pub longnames:  &'a str,
    pub sparses:    Vec<Sparse>,
    pub isextended: bool,
    pub realsize:   u64,
}

#[derive(Debug,PartialEq,Eq)]
pub struct Sparse {
    pub offset:   u64,
    pub numbytes: u64
}

#[derive(Debug,PartialEq,Eq)]
pub struct Padding;

/*
 * Useful macros
 */

macro_rules! take_str_eat_garbage (
    ( $i:expr, $size:expr ) => (
        chain!($i,
            s: map_res!(take_until!("\0"), from_utf8)                  ~
            length: expr_opt!({($size as usize).checked_sub(s.len())}) ~
            take!(length),
            ||{
                s
            }
        )
    );
);

named!(parse_str4<&[u8], &str>, take_str_eat_garbage!(4));
named!(parse_str8<&[u8], &str>, take_str_eat_garbage!(8));
named!(parse_str32<&[u8], &str>, take_str_eat_garbage!(32));
named!(parse_str100<&[u8], &str>, take_str_eat_garbage!(100));
named!(parse_str155<&[u8], &str>, take_str_eat_garbage!(155));

macro_rules! take_until_expr_with_limit_consume(
  ($i:expr, $submac:ident!( $($args:tt)* ), $stop: expr, $limit: expr) => (
    {
      let mut begin = 0;
      let mut remaining = $i.len();
      let mut res = Vec::new();
      let mut cnt = 0;
      let mut err = false;
      let mut append = true;
      loop {
        match $submac!(&$i[begin..], $($args)*) {
          IResult::Done(i,o) => {
            if append {
              if $stop(&o) {
                append = false;
              } else {
                res.push(o);
              }
            }
            begin += remaining - i.len();
            remaining = i.len();
            cnt = cnt + 1;
            if cnt == $limit {
              break
            }
          },
          IResult::Error(_)  => {
            err = true;
            break;
          },
          IResult::Incomplete(_) => {
            break;
          }
        }
      }
      if err {
        IResult::Error(Err::Position(ErrorKind::TakeUntil,$i))
      } else if cnt == $limit {
        IResult::Done(&$i[begin..], res)
      } else {
        IResult::Incomplete(Needed::Unknown)
      }
    }
  );
  ($i:expr, $f:expr, $stop: expr, $limit: expr) => (
    take_until_expr_with_limit_consume!($i, call!($f), $stop, $limit);
  );
);

/*
 * Octal string parsing
 */

pub fn octal_to_u64(s: &str) -> Result<u64, &'static str> {
    let mut u = 0;

    for c in s.chars() {
        if c < '0' || c > '7' {
            return Err("invalid octal string received");
        }
        u *= 8;
        u += (c as u64) - ('0' as u64);
    }

    Ok(u)
}

fn parse_octal(i: &[u8], n: usize) -> IResult<&[u8], u64> {
    map_res!(i, take_str_eat_garbage!(n), octal_to_u64)
}

named!(parse_octal8<&[u8], u64>, apply!(parse_octal, 8));
named!(parse_octal12<&[u8], u64>, apply!(parse_octal, 12));

/*
 * TypeFlag parsing
 */

fn char_to_type_flag(c: char) -> TypeFlag {
    match c {
        '0' | '\0' => TypeFlag::NormalFile,
        '1' => TypeFlag::HardLink,
        '2' => TypeFlag::SymbolicLink,
        '3' => TypeFlag::CharacterSpecial,
        '4' => TypeFlag::BlockSpecial,
        '5' => TypeFlag::Directory,
        '6' => TypeFlag::FIFO,
        '7' => TypeFlag::ContiguousFile,
        'g' => TypeFlag::PaxInterexchangeFormat,
        'x' => TypeFlag::PaxExtendedAttributes,
        'A' ... 'Z' => TypeFlag::VendorSpecific,
        _ => TypeFlag::NormalFile
    }
}

fn bytes_to_type_flag(i: &[u8]) -> TypeFlag {
    char_to_type_flag(i[0] as char)
}

named!(parse_type_flag<&[u8], TypeFlag>, map!(take!(1), bytes_to_type_flag));

/*
 * Sparse parsing
 */

named!(parse_one_sparse<&[u8], Sparse>, map!(pair!(parse_octal12, parse_octal12), |(offset, numbytes)| Sparse { offset: offset, numbytes: numbytes }));

fn parse_sparses_with_limit(i: &[u8], limit: usize) -> IResult<&[u8], Vec<Sparse>> {
    take_until_expr_with_limit_consume!(i, parse_one_sparse, |s: &Sparse| s.offset == 0 && s.numbytes == 0, limit)
}

fn add_to_vec<'a, 'b>(sparses: &'a mut Vec<Sparse>, extra: &'b mut Vec<Sparse>) -> &'a mut Vec<Sparse> {
    while sparses.len() != 0 {
      extra.pop().map(|s| sparses.push(s));
    }
    sparses
}

fn parse_extra_sparses<'a, 'b>(i: &'a [u8], isextended: bool, sparses: &'b mut Vec<Sparse>) -> IResult<&'a [u8], &'b mut Vec<Sparse>> {
    if isextended {
        chain!(i,
            mut sps: apply!(parse_sparses_with_limit, 21) ~
            extended:      parse_bool                     ~
            take!(7) /* padding to 512 */                 ~
            extra_sparses: apply!(parse_extra_sparses, extended, add_to_vec(sparses, &mut sps)),
            ||{
                extra_sparses
            }
        )
    } else {
        IResult::Done(i, sparses)
    }
}

fn parse_pax_extra_sparses<'a, 'b>(i: &'a [u8], h: &'b mut PaxHeader) -> IResult<&'a [u8], &'b mut Vec<Sparse>> {
    parse_extra_sparses(i, h.isextended, &mut h.sparses)
}

/*
 * Boolean parsing
 */

fn to_bool(i: &[u8]) -> bool {
    i[0] != 0
}

named!(parse_bool<&[u8], bool>, map!(take!(1), to_bool));

/*
 * UStar PAX extended parsing
 */

fn parse_ustar00_extra_pax(i: &[u8]) -> IResult<&[u8], PaxHeader> {
    chain!(i,
        atime:       parse_octal12                       ~
        ctime:       parse_octal12                       ~
        offset:      parse_octal12                       ~
        longnames:   parse_str4                          ~
        take!(1)                                         ~
        sparses:     apply!(parse_sparses_with_limit, 4) ~
        isextended:  parse_bool                          ~
        realsize:    parse_octal12                       ~
        take!(17), /* padding to 512 */
        ||{
            PaxHeader {
                atime:         atime,
                ctime:         ctime,
                offset:        offset,
                longnames:     longnames,
                sparses:       sparses,
                isextended:    isextended,
                realsize:      realsize,
            }
        }
    )
}

/*
 * UStar Posix parsing
 */

fn parse_ustar00_extra_posix(i: &[u8]) -> IResult<&[u8], UStarExtraHeader> {
    chain!(i,
        prefix: parse_str155 ~
        take!(12),
        ||{
            UStarExtraHeader::PosixUStar(PosixUStarHeader {
                prefix: prefix
            })
        }
    )
}

fn parse_ustar00_extra<'a, 'b>(i: &'a [u8], flag: &'b TypeFlag) -> IResult<&'a [u8], UStarExtraHeader<'a>> {
    match *flag {
        TypeFlag::PaxInterexchangeFormat => {
            chain!(i,
                mut header: parse_ustar00_extra_pax ~
                apply!(parse_pax_extra_sparses, &mut header),
                ||{
                    UStarExtraHeader::Pax(header)
                }
            )
        },
        _ => parse_ustar00_extra_posix(i)
    }
}

fn parse_ustar00<'a, 'b>(i: &'a [u8], flag: &'b TypeFlag) -> IResult<&'a [u8], ExtraHeader<'a>> {
    chain!(i,
        tag!("00")             ~
        uname:    parse_str32  ~
        gname:    parse_str32  ~
        devmajor: parse_octal8 ~
        devminor: parse_octal8 ~
        extra:    apply!(parse_ustar00_extra, flag),
        ||{
            ExtraHeader::UStar(UStarHeader {
                magic:    "ustar\0",
                version:  "00",
                uname:    uname,
                gname:    gname,
                devmajor: devmajor,
                devminor: devminor,
                extra:    extra
            })
        }
    )
}

fn parse_ustar<'a, 'b>(i: &'a [u8], flag: &'b TypeFlag) -> IResult<&'a [u8], ExtraHeader<'a>> {
    chain!(i,
        tag!("ustar\0") ~
        ustar: apply!(parse_ustar00, flag),
        ||{
            ustar
        }
    )
}

/*
 * Posix tar archive header parsing
 */

fn parse_posix(i: &[u8]) -> IResult<&[u8], ExtraHeader> {
    chain!(i,
        take!(255), /* padding to 512 */
        ||{
            ExtraHeader::Padding
        }
    )
}

fn parse_header(i: &[u8]) -> IResult<&[u8], PosixHeader> {
    chain!(i,
        name:     parse_str100    ~
        mode:     parse_str8      ~
        uid:      parse_octal8    ~
        gid:      parse_octal8    ~
        size:     parse_octal12   ~
        mtime:    parse_octal12   ~
        chksum:   parse_str8      ~
        typeflag: parse_type_flag ~
        linkname: parse_str100    ~
        ustar:    alt!(apply!(parse_ustar, &typeflag) | parse_posix),
        ||{
            PosixHeader {
                name:     name,
                mode:     mode,
                uid:      uid,
                gid:      gid,
                size:     size,
                mtime:    mtime,
                chksum:   chksum,
                typeflag: typeflag,
                linkname: linkname,
                ustar:    ustar
            }
        }
    )
}

/*
 * Contents parsing
 */

fn parse_contents(i: &[u8], size: u64) -> IResult<&[u8], &[u8]> {
    let trailing = size % 512;
    let padding = match trailing {
        0 => 0,
        t => 512 - t
    };
    chain!(i,
        contents: take!(size as usize) ~
        take!(padding as usize),
        ||{
            contents
        }
    )
}

/*
 * Tar entry header + contents parsing
 */

fn parse_entry(i: &[u8]) -> IResult<&[u8], TarEntry> {
    chain!(i,
        header:   parse_header ~
        contents: apply!(parse_contents, header.size),
        ||{
            TarEntry {
                header: header,
                contents: contents
            }
        }
    )
}

/*
 * Tar archive parsing
 */

fn filter_entries(entries: Vec<TarEntry>) -> Vec<TarEntry> {
    /* Filter out empty entries */
    entries.into_iter().filter(|e| e.header.name != "").collect::<Vec<TarEntry>>()
}

pub fn parse_tar(i: &[u8]) -> IResult<&[u8], Vec<TarEntry>> {
    chain!(i,
        entries: map!(many0!(parse_entry), filter_entries) ~
        eof,
        ||{
            entries
        }
    )
}

/*
 * Tests
 */

#[cfg(test)]
mod tests {
    use super::*;
    use std::str::from_utf8;
    use nom::IResult;

    #[test]
    fn octal_to_u64_ok_test() {
        assert_eq!(octal_to_u64("756"), Ok(494));
        assert_eq!(octal_to_u64(""), Ok(0));
    }

    #[test]
    fn octal_to_u64_error_test() {
        assert_eq!(octal_to_u64("1238"), Err("invalid octal string received"));
        assert_eq!(octal_to_u64("a"), Err("invalid octal string received"));
        assert_eq!(octal_to_u64("A"), Err("invalid octal string received"));
    }

    #[test]
    fn take_str_eat_garbage_test() {
        let s = b"foobar\0\0\0\0baz";
        let baz = b"baz";
        assert_eq!(take_str_eat_garbage!(&s[..], 10), IResult::Done(&baz[..], "foobar"));
    }
}
<commit_msg>simplify parse_ustar00_extra_posix<commit_after>use std::str::from_utf8;
use std::result::Result;
use nom::*;

/*
 * Core structs
 */

#[derive(Debug,PartialEq,Eq)]
pub struct TarEntry<'a> {
    pub header:   PosixHeader<'a>,
    pub contents: &'a [u8]
}

#[derive(Debug,PartialEq,Eq)]
pub struct PosixHeader<'a> {
    pub name:     &'a str,
    pub mode:     &'a str,
    pub uid:      u64,
    pub gid:      u64,
    pub size:     u64,
    pub mtime:    u64,
    pub chksum:   &'a str,
    pub typeflag: TypeFlag,
    pub linkname: &'a str,
    pub ustar:    ExtraHeader<'a>
}

/* TODO: support vendor specific */
#[derive(Debug,PartialEq,Eq)]
pub enum TypeFlag {
    NormalFile,
    HardLink,
    SymbolicLink,
    CharacterSpecial,
    BlockSpecial,
    Directory,
    FIFO,
    ContiguousFile,
    PaxInterexchangeFormat,
    PaxExtendedAttributes,
    VendorSpecific
}

#[derive(Debug,PartialEq,Eq)]
pub enum ExtraHeader<'a> {
    UStar(UStarHeader<'a>),
    Padding
}

#[derive(Debug,PartialEq,Eq)]
pub struct UStarHeader<'a> {
    pub magic:    &'a str,
    pub version:  &'a str,
    pub uname:    &'a str,
    pub gname:    &'a str,
    pub devmajor: u64,
    pub devminor: u64,
    pub extra:    UStarExtraHeader<'a>
}

#[derive(Debug,PartialEq,Eq)]
pub enum UStarExtraHeader<'a> {
    PosixUStar(PosixUStarHeader<'a>),
    Pax(PaxHeader<'a>)
}

#[derive(Debug,PartialEq,Eq)]
pub struct PosixUStarHeader<'a> {
    pub prefix: &'a str
}

#[derive(Debug,PartialEq,Eq)]
pub struct PaxHeader<'a> {
    pub atime:      u64,
    pub ctime:      u64,
    pub offset:     u64,
    pub longnames:  &'a str,
    pub sparses:    Vec<Sparse>,
    pub isextended: bool,
    pub realsize:   u64,
}

#[derive(Debug,PartialEq,Eq)]
pub struct Sparse {
    pub offset:   u64,
    pub numbytes: u64
}

#[derive(Debug,PartialEq,Eq)]
pub struct Padding;

/*
 * Useful macros
 */

macro_rules! take_str_eat_garbage (
    ( $i:expr, $size:expr ) => (
        chain!($i,
            s: map_res!(take_until!("\0"), from_utf8)                  ~
            length: expr_opt!({($size as usize).checked_sub(s.len())}) ~
            take!(length),
            ||{
                s
            }
        )
    );
);

named!(parse_str4<&[u8], &str>, take_str_eat_garbage!(4));
named!(parse_str8<&[u8], &str>, take_str_eat_garbage!(8));
named!(parse_str32<&[u8], &str>, take_str_eat_garbage!(32));
named!(parse_str100<&[u8], &str>, take_str_eat_garbage!(100));
named!(parse_str155<&[u8], &str>, take_str_eat_garbage!(155));

macro_rules! take_until_expr_with_limit_consume(
  ($i:expr, $submac:ident!( $($args:tt)* ), $stop: expr, $limit: expr) => (
    {
      let mut begin = 0;
      let mut remaining = $i.len();
      let mut res = Vec::new();
      let mut cnt = 0;
      let mut err = false;
      let mut append = true;
      loop {
        match $submac!(&$i[begin..], $($args)*) {
          IResult::Done(i,o) => {
            if append {
              if $stop(&o) {
                append = false;
              } else {
                res.push(o);
              }
            }
            begin += remaining - i.len();
            remaining = i.len();
            cnt = cnt + 1;
            if cnt == $limit {
              break
            }
          },
          IResult::Error(_)  => {
            err = true;
            break;
          },
          IResult::Incomplete(_) => {
            break;
          }
        }
      }
      if err {
        IResult::Error(Err::Position(ErrorKind::TakeUntil,$i))
      } else if cnt == $limit {
        IResult::Done(&$i[begin..], res)
      } else {
        IResult::Incomplete(Needed::Unknown)
      }
    }
  );
  ($i:expr, $f:expr, $stop: expr, $limit: expr) => (
    take_until_expr_with_limit_consume!($i, call!($f), $stop, $limit);
  );
);

/*
 * Octal string parsing
 */

pub fn octal_to_u64(s: &str) -> Result<u64, &'static str> {
    let mut u = 0;

    for c in s.chars() {
        if c < '0' || c > '7' {
            return Err("invalid octal string received");
        }
        u *= 8;
        u += (c as u64) - ('0' as u64);
    }

    Ok(u)
}

fn parse_octal(i: &[u8], n: usize) -> IResult<&[u8], u64> {
    map_res!(i, take_str_eat_garbage!(n), octal_to_u64)
}

named!(parse_octal8<&[u8], u64>, apply!(parse_octal, 8));
named!(parse_octal12<&[u8], u64>, apply!(parse_octal, 12));

/*
 * TypeFlag parsing
 */

fn char_to_type_flag(c: char) -> TypeFlag {
    match c {
        '0' | '\0' => TypeFlag::NormalFile,
        '1' => TypeFlag::HardLink,
        '2' => TypeFlag::SymbolicLink,
        '3' => TypeFlag::CharacterSpecial,
        '4' => TypeFlag::BlockSpecial,
        '5' => TypeFlag::Directory,
        '6' => TypeFlag::FIFO,
        '7' => TypeFlag::ContiguousFile,
        'g' => TypeFlag::PaxInterexchangeFormat,
        'x' => TypeFlag::PaxExtendedAttributes,
        'A' ... 'Z' => TypeFlag::VendorSpecific,
        _ => TypeFlag::NormalFile
    }
}

fn bytes_to_type_flag(i: &[u8]) -> TypeFlag {
    char_to_type_flag(i[0] as char)
}

named!(parse_type_flag<&[u8], TypeFlag>, map!(take!(1), bytes_to_type_flag));

/*
 * Sparse parsing
 */

named!(parse_one_sparse<&[u8], Sparse>, map!(pair!(parse_octal12, parse_octal12), |(offset, numbytes)| Sparse { offset: offset, numbytes: numbytes }));

fn parse_sparses_with_limit(i: &[u8], limit: usize) -> IResult<&[u8], Vec<Sparse>> {
    take_until_expr_with_limit_consume!(i, parse_one_sparse, |s: &Sparse| s.offset == 0 && s.numbytes == 0, limit)
}

fn add_to_vec<'a, 'b>(sparses: &'a mut Vec<Sparse>, extra: &'b mut Vec<Sparse>) -> &'a mut Vec<Sparse> {
    while sparses.len() != 0 {
      extra.pop().map(|s| sparses.push(s));
    }
    sparses
}

fn parse_extra_sparses<'a, 'b>(i: &'a [u8], isextended: bool, sparses: &'b mut Vec<Sparse>) -> IResult<&'a [u8], &'b mut Vec<Sparse>> {
    if isextended {
        chain!(i,
            mut sps: apply!(parse_sparses_with_limit, 21) ~
            extended:      parse_bool                     ~
            take!(7) /* padding to 512 */                 ~
            extra_sparses: apply!(parse_extra_sparses, extended, add_to_vec(sparses, &mut sps)),
            ||{
                extra_sparses
            }
        )
    } else {
        IResult::Done(i, sparses)
    }
}

fn parse_pax_extra_sparses<'a, 'b>(i: &'a [u8], h: &'b mut PaxHeader) -> IResult<&'a [u8], &'b mut Vec<Sparse>> {
    parse_extra_sparses(i, h.isextended, &mut h.sparses)
}

/*
 * Boolean parsing
 */

fn to_bool(i: &[u8]) -> bool {
    i[0] != 0
}

named!(parse_bool<&[u8], bool>, map!(take!(1), to_bool));

/*
 * UStar PAX extended parsing
 */

fn parse_ustar00_extra_pax(i: &[u8]) -> IResult<&[u8], PaxHeader> {
    chain!(i,
        atime:       parse_octal12                       ~
        ctime:       parse_octal12                       ~
        offset:      parse_octal12                       ~
        longnames:   parse_str4                          ~
        take!(1)                                         ~
        sparses:     apply!(parse_sparses_with_limit, 4) ~
        isextended:  parse_bool                          ~
        realsize:    parse_octal12                       ~
        take!(17), /* padding to 512 */
        ||{
            PaxHeader {
                atime:         atime,
                ctime:         ctime,
                offset:        offset,
                longnames:     longnames,
                sparses:       sparses,
                isextended:    isextended,
                realsize:      realsize,
            }
        }
    )
}

/*
 * UStar Posix parsing
 */

named!(parse_ustar00_extra_posix<&[u8], UStarExtraHeader>, map!(pair!(parse_str155, take!(12)), |(prefix, _)| UStarExtraHeader::PosixUStar(PosixUStarHeader { prefix: prefix })));

fn parse_ustar00_extra<'a, 'b>(i: &'a [u8], flag: &'b TypeFlag) -> IResult<&'a [u8], UStarExtraHeader<'a>> {
    match *flag {
        TypeFlag::PaxInterexchangeFormat => {
            chain!(i,
                mut header: parse_ustar00_extra_pax ~
                apply!(parse_pax_extra_sparses, &mut header),
                ||{
                    UStarExtraHeader::Pax(header)
                }
            )
        },
        _ => parse_ustar00_extra_posix(i)
    }
}

fn parse_ustar00<'a, 'b>(i: &'a [u8], flag: &'b TypeFlag) -> IResult<&'a [u8], ExtraHeader<'a>> {
    chain!(i,
        tag!("00")             ~
        uname:    parse_str32  ~
        gname:    parse_str32  ~
        devmajor: parse_octal8 ~
        devminor: parse_octal8 ~
        extra:    apply!(parse_ustar00_extra, flag),
        ||{
            ExtraHeader::UStar(UStarHeader {
                magic:    "ustar\0",
                version:  "00",
                uname:    uname,
                gname:    gname,
                devmajor: devmajor,
                devminor: devminor,
                extra:    extra
            })
        }
    )
}

fn parse_ustar<'a, 'b>(i: &'a [u8], flag: &'b TypeFlag) -> IResult<&'a [u8], ExtraHeader<'a>> {
    chain!(i,
        tag!("ustar\0") ~
        ustar: apply!(parse_ustar00, flag),
        ||{
            ustar
        }
    )
}

/*
 * Posix tar archive header parsing
 */

fn parse_posix(i: &[u8]) -> IResult<&[u8], ExtraHeader> {
    chain!(i,
        take!(255), /* padding to 512 */
        ||{
            ExtraHeader::Padding
        }
    )
}

fn parse_header(i: &[u8]) -> IResult<&[u8], PosixHeader> {
    chain!(i,
        name:     parse_str100    ~
        mode:     parse_str8      ~
        uid:      parse_octal8    ~
        gid:      parse_octal8    ~
        size:     parse_octal12   ~
        mtime:    parse_octal12   ~
        chksum:   parse_str8      ~
        typeflag: parse_type_flag ~
        linkname: parse_str100    ~
        ustar:    alt!(apply!(parse_ustar, &typeflag) | parse_posix),
        ||{
            PosixHeader {
                name:     name,
                mode:     mode,
                uid:      uid,
                gid:      gid,
                size:     size,
                mtime:    mtime,
                chksum:   chksum,
                typeflag: typeflag,
                linkname: linkname,
                ustar:    ustar
            }
        }
    )
}

/*
 * Contents parsing
 */

fn parse_contents(i: &[u8], size: u64) -> IResult<&[u8], &[u8]> {
    let trailing = size % 512;
    let padding = match trailing {
        0 => 0,
        t => 512 - t
    };
    chain!(i,
        contents: take!(size as usize) ~
        take!(padding as usize),
        ||{
            contents
        }
    )
}

/*
 * Tar entry header + contents parsing
 */

fn parse_entry(i: &[u8]) -> IResult<&[u8], TarEntry> {
    chain!(i,
        header:   parse_header ~
        contents: apply!(parse_contents, header.size),
        ||{
            TarEntry {
                header: header,
                contents: contents
            }
        }
    )
}

/*
 * Tar archive parsing
 */

fn filter_entries(entries: Vec<TarEntry>) -> Vec<TarEntry> {
    /* Filter out empty entries */
    entries.into_iter().filter(|e| e.header.name != "").collect::<Vec<TarEntry>>()
}

pub fn parse_tar(i: &[u8]) -> IResult<&[u8], Vec<TarEntry>> {
    chain!(i,
        entries: map!(many0!(parse_entry), filter_entries) ~
        eof,
        ||{
            entries
        }
    )
}

/*
 * Tests
 */

#[cfg(test)]
mod tests {
    use super::*;
    use std::str::from_utf8;
    use nom::IResult;

    #[test]
    fn octal_to_u64_ok_test() {
        assert_eq!(octal_to_u64("756"), Ok(494));
        assert_eq!(octal_to_u64(""), Ok(0));
    }

    #[test]
    fn octal_to_u64_error_test() {
        assert_eq!(octal_to_u64("1238"), Err("invalid octal string received"));
        assert_eq!(octal_to_u64("a"), Err("invalid octal string received"));
        assert_eq!(octal_to_u64("A"), Err("invalid octal string received"));
    }

    #[test]
    fn take_str_eat_garbage_test() {
        let s = b"foobar\0\0\0\0baz";
        let baz = b"baz";
        assert_eq!(take_str_eat_garbage!(&s[..], 10), IResult::Done(&baz[..], "foobar"));
    }
}
<|endoftext|>


<commit_before>use expr::{Expr, BinOp};

#[derive(Clone, Debug, PartialEq)]
enum Token {
  Plus,
  Minus,
  Times,
  Div,
  RParen,
  LParen,
  Integer(isize),
}

struct Lexer {
  text: String,
}

impl Lexer {
  pub fn new(text: String) -> Lexer {
    Lexer {
      text: text,
    }
  }

  fn cut_input_by(&mut self, n: usize) {
    let text = self.text.clone();
    let (_, t) = text.split_at(n);
    self.text = t.to_string();
  }

  pub fn lex_integer(&mut self) -> Option<Token> {
    let int_str: String = self.text
      .chars()
      .take_while(|c| c.is_digit(10))
      .collect();

    match int_str.parse::<isize>() {
      Ok(n) => {
        self.cut_input_by(int_str.len());
        return Some(Token::Integer(n));
      }
      Err(_) => panic!()
    }
  }

  fn skip_whitespace(&mut self) {
    let mut c = self.text.chars().next();

    loop {
      debug!("skipping whitespace... {:?}", c);
      self.cut_input_by(1);
      c = self.text.chars().next();

      if c == None || !c.unwrap().is_whitespace() {
        break;
      }
    }
  }

  pub fn get_next_token(&mut self) -> Option<Token> {
    while self.text.chars().next() != None {
      debug!("get_next_token: {}", self.text);
      match self.text.chars().next() {
        Some('+') => {
          self.cut_input_by(1);
          return Some(Token::Plus)
        },
        Some('-') => {
          self.cut_input_by(1);
          return Some(Token::Minus)
        },
        Some('*') => {
          self.cut_input_by(1);
          return Some(Token::Times)
        },
        Some('/') => {
          self.cut_input_by(1);
          return Some(Token::Div)
        },
        Some('(') => {
          self.cut_input_by(1);
          return Some(Token::LParen)
        },
        Some(')') => {
          self.cut_input_by(1);
          return Some(Token::RParen)
        },
        Some(x) if x.is_digit(10) => return self.lex_integer(),
        Some(x) if x.is_whitespace() => {
          self.skip_whitespace();
          continue;
        }
        None => {
          debug!("Lex'd none! EOF!");
          return None
        }
        _ => panic!()
      }
    }

    None
  }
}

struct Parser {
  lexer: Lexer,
  current_token: Option<Token>,
}

impl Parser {
  pub fn new(text: String) -> Parser {
    let mut lexer = Lexer::new(text);

    let token = lexer.get_next_token();

    Parser {
      lexer: lexer,
      current_token: token,
    }
  }

  fn eat(&mut self) {
    self.current_token = self.lexer.get_next_token();
    debug!("new current token: {:?}", self.current_token);
  }

  fn plus(&mut self, e1: Option<Expr>, e2: Option<Expr>) -> Option<Expr> {
    match (e1, e2) {
      (Some(e1), Some(e2)) => Some(Expr::BinOp(BinOp::Plus,Box::new(e1), Box::new(e2))),
      _ => panic!()
    }
  }

  fn minus (&mut self, e1: Option<Expr>, e2: Option<Expr>) -> Option<Expr> {
    match (e1, e2) {
      (Some(e1), Some(e2)) => Some(Expr::BinOp(BinOp::Minus,Box::new(e1), Box::new(e2))),
      _ => panic!()
    }
  }

  fn times (&mut self, e1: Option<Expr>, e2: Option<Expr>) -> Option<Expr> {
    match (e1, e2) {
      (Some(e1), Some(e2)) => Some(Expr::BinOp(BinOp::Times,Box::new(e1), Box::new(e2))),
      _ => panic!()
    }
  }

  fn div (&mut self, e1: Option<Expr>, e2: Option<Expr>) -> Option<Expr> {
    match (e1, e2) {
      (Some(e1), Some(e2)) => Some(Expr::BinOp(BinOp::Div,Box::new(e1), Box::new(e2))),
      _ => panic!()
    }
  }

  fn factor(&mut self) -> Option<Expr> {
    match self.current_token {
      Some(Token::Integer(n)) => {
        debug!("factor::Integer({})", n);
        self.eat();
        return Some(Expr::Int(n));
      },
      Some(Token::LParen) => {
        debug!("factor::LParen)");
        self.eat();
        let node = self.expr();
        self.eat();
        return node;
      },
      _ => {
        debug!("invalid factor: {:?}", self.current_token);
        panic!();
      },
    }
  }

  pub fn term(&mut self) -> Option<Expr> {
    let mut node = self.factor();

    while self.current_token == Some(Token::Times) || self.current_token == Some(Token::Div) {
      let op = self.current_token.clone();

      self.eat();
      let right_node = self.term();

      node = match op {
        Some(Token::Times) => self.times(node, right_node),
        Some(Token::Div) => self.div(node, right_node),
        _ => panic!(),
      };
    }

    node
  }

  pub fn expr(&mut self) -> Option<Expr> {
    debug!("");
    debug!("left_node: (");
    let mut node = self.term();
    debug!(") // left_node");
    debug!("");

    while self.current_token == Some(Token::Plus) || self.current_token == Some(Token::Minus) {
      debug!("expr::Op({:?})", self.current_token);

      let op = self.current_token.clone();

      self.eat();
      debug!("");
      debug!("right_node: (");
      let right_node = self.term();
      debug!(") // right_node");
      debug!("");

      node = match op {
        Some(Token::Plus) => self.plus(node, right_node),
        Some(Token::Minus) => self.minus(node, right_node),
        _ => panic!(),
      };

      debug!("");
      debug!("node: {:?}", node);
      debug!("");
    }

    node
  }
}

pub fn parse(input: &str) -> Expr {
  let mut parser = Parser::new(input.to_string());

  match parser.expr() {
    Some(e) => e,
    None => panic!(),
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use expr::{Expr, BinOp};
  extern crate env_logger;

  #[test]
  fn test_mult_div() {
    //let _ = env_logger::init();
    assert_eq!(
      Expr::BinOp(
        BinOp::Times,
        Box::new(Expr::Int(3)),
        Box::new(Expr::Int(4)),
      ),
      parse("3*4")
    );

    assert_eq!(
      Expr::BinOp(
        BinOp::Div,
        Box::new(Expr::Int(3)),
        Box::new(Expr::Int(4)),
      ),
      parse("3/4")
    );
  }

  #[test]
  fn test_parse_add_subtract_parens() {
    //let _ = env_logger::init();
    assert_eq!(
      Expr::BinOp(
        BinOp::Plus,
        Box::new(Expr::Int(3)),
        Box::new(Expr::Int(4)),
      ),
      parse("3+4")
    );

    assert_eq!(
      Expr::BinOp(
        BinOp::Plus,
        Box::new(
          Expr::BinOp(
            BinOp::Plus,
            Box::new(Expr::Int(3)),
            Box::new(Expr::Int(4)),
          ),
        ),
        Box::new(Expr::Int(5)),
      ),
      parse("3+4+5")
    );

    assert_eq!(
      Expr::BinOp(BinOp::Plus,
        Box::new(Expr::Int(3)),
        Box::new(
          Expr::BinOp(
            BinOp::Plus,
            Box::new(Expr::Int(4)),
            Box::new(Expr::Int(5)),
          ),
        ),
      ),
      parse("3+(4+5)")
    );

    assert_eq!(
      Expr::BinOp(
        BinOp::Minus,
        Box::new(Expr::Int(3)),
        Box::new(Expr::Int(4)),
      ),
      parse("3-4")
    );

    assert_eq!(
      Expr::BinOp(
        BinOp::Minus,
        Box::new(
          Expr::BinOp(
            BinOp::Minus,
            Box::new(Expr::Int(3)),
            Box::new(Expr::Int(4)),
          ),
        ),
        Box::new(Expr::Int(5)),
      ),
      parse("3-4-5")
    );

    assert_eq!(
      Expr::BinOp(
        BinOp::Minus,
        Box::new(Expr::Int(3)),
        Box::new(
          Expr::BinOp(
            BinOp::Minus,
            Box::new(Expr::Int(4)),
            Box::new(Expr::Int(5)),
          ),
        ),
      ),
      parse("3-(4-5)")
    );

    assert_eq!(
      Expr::BinOp(
        BinOp::Minus,
        Box::new(
          Expr::BinOp(
            BinOp::Plus,
            Box::new(Expr::Int(4)),
            Box::new(Expr::Int(7)),
          ),
        ),
        Box::new(Expr::Int(3)),
      ),
      parse("(4+7)-3")
    );
  }
}
<commit_msg>cleaning up<commit_after>use expr::{Expr, BinOp};

#[derive(Clone, Debug, PartialEq)]
enum Token {
  Plus,
  Minus,
  Times,
  Div,
  RParen,
  LParen,
  Int(isize),
}

struct Lexer {
  text: String,
}

impl Lexer {
  pub fn new(text: String) -> Lexer {
    Lexer {
      text: text,
    }
  }

  fn advance(&mut self, n: usize) {
    let text = self.text.clone();
    let (_, t) = text.split_at(n);
    self.text = t.to_string();
  }

  pub fn lex_integer(&mut self) -> Option<Token> {
    let int_str: String = self.text
      .chars()
      .take_while(|c| c.is_digit(10))
      .collect();

    match int_str.parse::<isize>() {
      Ok(n) => {
        self.advance(int_str.len());
        return Some(Token::Int(n));
      }
      Err(_) => panic!()
    }
  }

  fn skip_whitespace(&mut self) {
    let spaces_str: String = self.text
      .chars()
      .take_while(|c| c.is_whitespace())
      .collect();

    self.advance(spaces_str.len());
  }

  pub fn get_next_token(&mut self) -> Option<Token> {
    while self.text.chars().next() != None {
      debug!("get_next_token: {}", self.text);
      match self.text.chars().next() {
        Some('+') => {
          self.advance(1);
          return Some(Token::Plus)
        },
        Some('-') => {
          self.advance(1);
          return Some(Token::Minus)
        },
        Some('*') => {
          self.advance(1);
          return Some(Token::Times)
        },
        Some('/') => {
          self.advance(1);
          return Some(Token::Div)
        },
        Some('(') => {
          self.advance(1);
          return Some(Token::LParen)
        },
        Some(')') => {
          self.advance(1);
          return Some(Token::RParen)
        },
        Some(x) if x.is_digit(10) => return self.lex_integer(),
        Some(x) if x.is_whitespace() => {
          self.skip_whitespace();
          continue;
        }
        None => return None,
        _ => panic!()
      }
    }

    None
  }
}

struct Parser {
  lexer: Lexer,
  current_token: Option<Token>,
}

impl Parser {
  pub fn new(text: String) -> Parser {
    let mut lexer = Lexer::new(text);

    let token = lexer.get_next_token();

    Parser {
      lexer: lexer,
      current_token: token,
    }
  }

  fn eat(&mut self) {
    self.current_token = self.lexer.get_next_token();
    debug!("new current token: {:?}", self.current_token);
  }

  fn binop(&mut self, bop: BinOp, e1: Option<Expr>, e2: Option<Expr>) -> Option<Expr> {
    Some(Expr::BinOp(bop, Box::new(e1.unwrap()), Box::new(e2.unwrap())))
  }

  fn factor(&mut self) -> Option<Expr> {
    match self.current_token {
      Some(Token::Int(n)) => {
        self.eat();
        return Some(Expr::Int(n));
      },
      Some(Token::LParen) => {
        self.eat();
        let node = self.expr();
        self.eat();
        return node;
      },
      _ => {
        debug!("invalid factor: {:?}", self.current_token);
        panic!();
      },
    }
  }

  pub fn term(&mut self) -> Option<Expr> {
    let mut node = self.factor();

    while self.current_token == Some(Token::Times) || self.current_token == Some(Token::Div) {
      let op = self.current_token.clone();

      self.eat();
      let right_node = self.term();

      node = match op {
        Some(Token::Times) => self.binop(BinOp::Times, node, right_node),
        Some(Token::Div) => self.binop(BinOp::Div, node, right_node),
        _ => panic!(),
      };
    }

    node
  }

  pub fn expr(&mut self) -> Option<Expr> {
    let mut node = self.term();

    while self.current_token == Some(Token::Plus) || self.current_token == Some(Token::Minus) {
      let op = self.current_token.clone();

      self.eat();
      let right_node = self.term();

      node = match op {
        Some(Token::Plus) => self.binop(BinOp::Plus, node, right_node),
        Some(Token::Minus) => self.binop(BinOp::Minus, node, right_node),
        _ => panic!(),
      };
    }

    node
  }
}

pub fn parse(input: &str) -> Expr {
  let mut parser = Parser::new(input.to_string());

  parser.expr().unwrap()
}

#[cfg(test)]
mod tests {
  use super::*;
  use expr::{Expr, BinOp};
  extern crate env_logger;

  #[test]
  fn test_mult_div() {
    //let _ = env_logger::init();
    assert_eq!(
      Expr::BinOp(
        BinOp::Times,
        Box::new(Expr::Int(3)),
        Box::new(Expr::Int(4)),
      ),
      parse("3*4")
    );

    assert_eq!(
      Expr::BinOp(
        BinOp::Div,
        Box::new(Expr::Int(3)),
        Box::new(Expr::Int(4)),
      ),
      parse("3/4")
    );
  }

  #[test]
  fn test_parse_add_subtract_parens() {
    assert_eq!(
      Expr::BinOp(
        BinOp::Plus,
        Box::new(Expr::Int(3)),
        Box::new(Expr::Int(4)),
      ),
      parse("3+4")
    );

    assert_eq!(
      Expr::BinOp(
        BinOp::Plus,
        Box::new(
          Expr::BinOp(
            BinOp::Plus,
            Box::new(Expr::Int(3)),
            Box::new(Expr::Int(4)),
          ),
        ),
        Box::new(Expr::Int(5)),
      ),
      parse("3+4+5")
    );

    assert_eq!(
      Expr::BinOp(BinOp::Plus,
        Box::new(Expr::Int(3)),
        Box::new(
          Expr::BinOp(
            BinOp::Plus,
            Box::new(Expr::Int(4)),
            Box::new(Expr::Int(5)),
          ),
        ),
      ),
      parse("3+(4+5)")
    );

    assert_eq!(
      Expr::BinOp(
        BinOp::Minus,
        Box::new(Expr::Int(3)),
        Box::new(Expr::Int(4)),
      ),
      parse("3-4")
    );

    assert_eq!(
      Expr::BinOp(
        BinOp::Minus,
        Box::new(
          Expr::BinOp(
            BinOp::Minus,
            Box::new(Expr::Int(3)),
            Box::new(Expr::Int(4)),
          ),
        ),
        Box::new(Expr::Int(5)),
      ),
      parse("3-4-5")
    );

    assert_eq!(
      Expr::BinOp(
        BinOp::Minus,
        Box::new(Expr::Int(3)),
        Box::new(
          Expr::BinOp(
            BinOp::Minus,
            Box::new(Expr::Int(4)),
            Box::new(Expr::Int(5)),
          ),
        ),
      ),
      parse("3-(4-5)")
    );

    assert_eq!(
      Expr::BinOp(
        BinOp::Minus,
        Box::new(
          Expr::BinOp(
            BinOp::Plus,
            Box::new(Expr::Int(4)),
            Box::new(Expr::Int(7)),
          ),
        ),
        Box::new(Expr::Int(3)),
      ),
      parse("(4+7)-3")
    );
  }
}
<|endoftext|>


<commit_before>use camera;
use id_allocator::IdAllocator;
use lod_map::{LOD, OwnerId};
use nalgebra::{Pnt3, Vec3};
use ncollide_entities::bounding_volume::AABB;
use ncollide_queries::ray::{Ray, Ray3};
use opencl_context::CL;
use physics::Physics;
use view::View;
use world::EntityId;
use std::f32::consts::PI;
use std::iter::range_inclusive;
use std::num;
use stopwatch::TimerSet;
use surroundings_loader::SurroundingsLoader;
use terrain::terrain;
use terrain::terrain_block::BlockPosition;
use terrain::terrain_game_loader::TerrainGameLoader;

const LOD_THRESHOLDS: [i32; 3] = [1, 8, 32];

const MAX_JUMP_FUEL: u32 = 4;
const MAX_STEP_HEIGHT: f32 = 1.0;

pub struct Player<'a> {
  pub position: Pnt3<f32>,
  // speed; units are world coordinates
  pub speed: Vec3<f32>,
  // acceleration; units are world coordinates
  pub accel: Vec3<f32>,
  // acceleration; x/z units are relative to player facing
  pub walk_accel: Vec3<f32>,
  // this is depleted as we jump and replenished as we stand.
  pub jump_fuel: u32,
  // are we currently trying to jump? (e.g. holding the key).
  pub is_jumping: bool,
  pub id: EntityId,

  // rotation around the y-axis, in radians
  pub lateral_rotation: f32,
  // "pitch", in radians
  pub vertical_rotation: f32,

  pub surroundings_loader: SurroundingsLoader<'a>,
  // Nearby blocks should be made solid if they aren't loaded yet.
  pub solid_boundary: SurroundingsLoader<'a>,
}

impl<'a> Player<'a> {
  pub fn new(
    id_allocator: &mut IdAllocator<EntityId>,
    owner_allocator: &mut IdAllocator<OwnerId>,
    load_distance: i32,
  ) -> Player<'a> {
    Player {
      position: Pnt3::new(0.0, 0.0, 0.0),
      speed: Vec3::new(0.0, 0.0, 0.0),
      accel: Vec3::new(0.0, -0.1, 0.0),
      walk_accel: Vec3::new(0.0, 0.0, 0.0),
      jump_fuel: 0,
      is_jumping: false,
      id: id_allocator.allocate(),
      lateral_rotation: 0.0,
      vertical_rotation: 0.0,
      surroundings_loader:
        SurroundingsLoader::new(
          owner_allocator.allocate(),
          load_distance,
          Box::new(|d| LOD::LodIndex(Player::lod_index(d))),
        ),
      solid_boundary:
        SurroundingsLoader::new(
          owner_allocator.allocate(),
          1,
          Box::new(|_| LOD::Placeholder),
        ),
    }
  }

  /// Translates the player/camera by a vector.
  /// If the player collides with something with a small height jump, the player will shift upward.
  pub fn translate(
    &mut self,
    physics: &mut Physics,
    v: Vec3<f32>,
  ) {
    let bounds = physics.bounds.get_mut(&self.id).unwrap();
    let init_bounds =
      AABB::new(
        *bounds.mins() + v,
        *bounds.maxs() + v,
      );
    let mut new_bounds = init_bounds.clone();
    // The height of the player's "step".
    let mut step = 0.0;
    let mut collided = false;
    loop {
      match physics.terrain_octree.intersect(&new_bounds, None) {
        None => {
          Physics::reinsert(&mut physics.misc_octree, self.id, bounds, new_bounds);
          break;
        },
        Some((collision_bounds, _)) => {
          collided = true;
          // Step to the top of whatever we hit.
          step = collision_bounds.maxs().y - init_bounds.mins().y;
          assert!(step > 0.0);

          if step > MAX_STEP_HEIGHT {
            // Step is too big; we just ran into something.
            break;
          }

          new_bounds =
            AABB::new(
              *init_bounds.mins() + Vec3::new(0.0, step, 0.0),
              *init_bounds.maxs() + Vec3::new(0.0, step, 0.0),
            );
        },
      }
    }

    let dp = v + Vec3::new(0.0, step, 0.0);
    self.position = self.position + dp;

    if collided {
      if v.y < 0.0 {
        self.jump_fuel = MAX_JUMP_FUEL;
      }

      self.speed = self.speed - v;
    } else {
      if v.y < 0.0 {
        self.jump_fuel = 0;
      }
    }
  }

  pub fn update(
    &mut self,
    timers: &TimerSet,
    view: &mut View,
    cl: &CL,
    terrain_game_loader: &mut TerrainGameLoader,
    id_allocator: &mut IdAllocator<EntityId>,
    physics: &mut Physics,
  ) {
    let block_position = BlockPosition::from_world_position(&self.position);

    timers.time("update.player.surroundings", || {
      self.surroundings_loader.update(
        timers,
        view,
        cl,
        terrain_game_loader,
        id_allocator,
        physics,
        block_position,
      );

      self.solid_boundary.update(
        timers,
        view,
        cl,
        terrain_game_loader,
        id_allocator,
        physics,
        block_position,
      );
    });

    if self.is_jumping {
      if self.jump_fuel > 0 {
        self.jump_fuel -= 1;
      } else {
        // this code is duplicated in a few places
        self.is_jumping = false;
        self.accel.y = self.accel.y - 0.3;
      }
    }

    let delta_p = self.speed;
    if delta_p.x != 0.0 {
      self.translate(physics, Vec3::new(delta_p.x, 0.0, 0.0));
    }
    if delta_p.y != 0.0 {
      self.translate(physics, Vec3::new(0.0, delta_p.y, 0.0));
    }
    if delta_p.z != 0.0 {
      self.translate(physics, Vec3::new(0.0, 0.0, delta_p.z));
    }

    let y_axis = Vec3::new(0.0, 1.0, 0.0);
    let walk_v =
        camera::from_axis_angle3(y_axis, self.lateral_rotation) * self.walk_accel;
    self.speed = self.speed + walk_v + self.accel;
    // friction
    self.speed = self.speed * Vec3::new(0.7, 0.99, 0.7 as f32);
  }

  /// Changes the camera's acceleration by the given `da`.
  pub fn walk(&mut self, da: Vec3<f32>) {
    self.walk_accel = self.walk_accel + da * 0.2 as f32;
  }

  /// Rotate the camera around the y axis, by `r` radians. Positive is counterclockwise.
  pub fn rotate_lateral(&mut self, r: f32) {
    self.lateral_rotation = self.lateral_rotation + r;
  }

  /// Changes the camera pitch by `r` radians. Positive is up.
  /// Angles that "flip around" (i.e. looking too far up or down)
  /// are sliently rejected.
  pub fn rotate_vertical(&mut self, r: f32) {
    let new_rotation = self.vertical_rotation + r;

    if new_rotation < -PI / 2.0
    || new_rotation >  PI / 2.0 {
      return
    }

    self.vertical_rotation = new_rotation;
  }

  // axes

  /// Return the "right" axis (i.e. the x-axis rotated to match you).
  pub fn right(&self) -> Vec3<f32> {
    return
      camera::from_axis_angle3(Vec3::new(0.0, 1.0, 0.0), self.lateral_rotation) *
      Vec3::new(1.0, 0.0, 0.0)
  }

  /// Return the "Ray axis (i.e. the z-axis rotated to match you).
  pub fn forward(&self) -> Vec3<f32> {
    let y_axis = Vec3::new(0.0, 1.0, 0.0);
    let transform =
      camera::from_axis_angle3(self.right(), self.vertical_rotation) *
      camera::from_axis_angle3(y_axis, self.lateral_rotation);
    let forward_orig = Vec3::new(0.0, 0.0, -1.0);

    transform * forward_orig
  }

  #[allow(dead_code)]
  pub fn forward_ray(&self) -> Ray3<f32> {
    Ray::new(self.position, self.forward())
  }

  pub fn lod_index(distance: i32) -> u32 {
    assert!(distance >= 0);
    let mut lod = 0;
    while
      lod < LOD_THRESHOLDS.len()
      && LOD_THRESHOLDS[lod] < distance
    {
      lod += 1;
    }
    num::cast(lod).unwrap()
  }

  pub fn load_distance(mut polygon_budget: i32) -> i32 {
    // TODO: This should try to account for VRAM not used on a per-poly basis.

    let mut load_distance = 0;
    let mut prev_threshold = 0;
    let mut prev_square = 0;
    for (&threshold, &quality) in
      LOD_THRESHOLDS.iter()
        .zip(terrain::LOD_QUALITY.iter()) {
      let polygons_per_block = (quality * quality * 4) as i32;
      for i in range_inclusive(prev_threshold, threshold) {
        let i = 2 * i + 1;
        let square = i * i;
        let polygons_in_layer = (square - prev_square) * polygons_per_block;
        polygon_budget -= polygons_in_layer;
        if polygon_budget < 0 {
          break;
        }

        load_distance += 1;
        prev_square = square;
      }
      prev_threshold = threshold + 1;
    }

    let mut width = 2 * prev_threshold + 1;
    loop {
      let square = width * width;
      // The "to infinity and beyond" quality.
      let quality = terrain::LOD_QUALITY[LOD_THRESHOLDS.len()];
      let polygons_per_block = (quality * quality * 4) as i32;
      let polygons_in_layer = (square - prev_square) * polygons_per_block;
      polygon_budget -= polygons_in_layer;

      if polygon_budget < 0 {
        break;
      }

      width += 2;
      load_distance += 1;
      prev_square = square;
    }

    load_distance
  }
}
<commit_msg>Fix previous commit.<commit_after>use camera;
use id_allocator::IdAllocator;
use lod_map::{LOD, OwnerId};
use nalgebra::{Pnt3, Vec3};
use ncollide_entities::bounding_volume::AABB;
use ncollide_queries::ray::{Ray, Ray3};
use opencl_context::CL;
use physics::Physics;
use view::View;
use world::EntityId;
use std::f32::consts::PI;
use std::iter::range_inclusive;
use std::num;
use stopwatch::TimerSet;
use surroundings_loader::SurroundingsLoader;
use terrain::terrain;
use terrain::terrain_block::BlockPosition;
use terrain::terrain_game_loader::TerrainGameLoader;

const LOD_THRESHOLDS: [i32; 3] = [1, 8, 32];

const MAX_JUMP_FUEL: u32 = 4;
const MAX_STEP_HEIGHT: f32 = 1.0;

pub struct Player<'a> {
  pub position: Pnt3<f32>,
  // speed; units are world coordinates
  pub speed: Vec3<f32>,
  // acceleration; units are world coordinates
  pub accel: Vec3<f32>,
  // acceleration; x/z units are relative to player facing
  pub walk_accel: Vec3<f32>,
  // this is depleted as we jump and replenished as we stand.
  pub jump_fuel: u32,
  // are we currently trying to jump? (e.g. holding the key).
  pub is_jumping: bool,
  pub id: EntityId,

  // rotation around the y-axis, in radians
  pub lateral_rotation: f32,
  // "pitch", in radians
  pub vertical_rotation: f32,

  pub surroundings_loader: SurroundingsLoader<'a>,
  // Nearby blocks should be made solid if they aren't loaded yet.
  pub solid_boundary: SurroundingsLoader<'a>,
}

impl<'a> Player<'a> {
  pub fn new(
    id_allocator: &mut IdAllocator<EntityId>,
    owner_allocator: &mut IdAllocator<OwnerId>,
    load_distance: i32,
  ) -> Player<'a> {
    Player {
      position: Pnt3::new(0.0, 0.0, 0.0),
      speed: Vec3::new(0.0, 0.0, 0.0),
      accel: Vec3::new(0.0, -0.1, 0.0),
      walk_accel: Vec3::new(0.0, 0.0, 0.0),
      jump_fuel: 0,
      is_jumping: false,
      id: id_allocator.allocate(),
      lateral_rotation: 0.0,
      vertical_rotation: 0.0,
      surroundings_loader:
        SurroundingsLoader::new(
          owner_allocator.allocate(),
          load_distance,
          Box::new(|d| LOD::LodIndex(Player::lod_index(d))),
        ),
      solid_boundary:
        SurroundingsLoader::new(
          owner_allocator.allocate(),
          1,
          Box::new(|_| LOD::Placeholder),
        ),
    }
  }

  /// Translates the player/camera by a vector.
  /// If the player collides with something with a small height jump, the player will shift upward.
  pub fn translate(
    &mut self,
    physics: &mut Physics,
    v: Vec3<f32>,
  ) {
    let bounds = physics.bounds.get_mut(&self.id).unwrap();
    let init_bounds =
      AABB::new(
        *bounds.mins() + v,
        *bounds.maxs() + v,
      );
    let mut new_bounds = init_bounds.clone();
    // The height of the player's "step".
    let mut step_height = 0.0;
    let mut collided = false;
    loop {
      match physics.terrain_octree.intersect(&new_bounds, None) {
        None => {
          Physics::reinsert(&mut physics.misc_octree, self.id, bounds, new_bounds);
          self.position = self.position + v + Vec3::new(0.0, step_height, 0.0);
          break;
        },
        Some((collision_bounds, _)) => {
          collided = true;
          // Step to the top of whatever we hit.
          step_height = collision_bounds.maxs().y - init_bounds.mins().y;
          assert!(step_height > 0.0);

          if step_height > MAX_STEP_HEIGHT {
            // Step is too big; we just ran into something.
            break;
          }

          new_bounds =
            AABB::new(
              *init_bounds.mins() + Vec3::new(0.0, step_height, 0.0),
              *init_bounds.maxs() + Vec3::new(0.0, step_height, 0.0),
            );
        },
      }
    }

    if collided {
      if v.y < 0.0 {
        self.jump_fuel = MAX_JUMP_FUEL;
      }

      self.speed = self.speed - v;
    } else {
      if v.y < 0.0 {
        self.jump_fuel = 0;
      }
    }
  }

  pub fn update(
    &mut self,
    timers: &TimerSet,
    view: &mut View,
    cl: &CL,
    terrain_game_loader: &mut TerrainGameLoader,
    id_allocator: &mut IdAllocator<EntityId>,
    physics: &mut Physics,
  ) {
    let block_position = BlockPosition::from_world_position(&self.position);

    timers.time("update.player.surroundings", || {
      self.surroundings_loader.update(
        timers,
        view,
        cl,
        terrain_game_loader,
        id_allocator,
        physics,
        block_position,
      );

      self.solid_boundary.update(
        timers,
        view,
        cl,
        terrain_game_loader,
        id_allocator,
        physics,
        block_position,
      );
    });

    if self.is_jumping {
      if self.jump_fuel > 0 {
        self.jump_fuel -= 1;
      } else {
        // this code is duplicated in a few places
        self.is_jumping = false;
        self.accel.y = self.accel.y - 0.3;
      }
    }

    let delta_p = self.speed;
    if delta_p.x != 0.0 {
      self.translate(physics, Vec3::new(delta_p.x, 0.0, 0.0));
    }
    if delta_p.y != 0.0 {
      self.translate(physics, Vec3::new(0.0, delta_p.y, 0.0));
    }
    if delta_p.z != 0.0 {
      self.translate(physics, Vec3::new(0.0, 0.0, delta_p.z));
    }

    let y_axis = Vec3::new(0.0, 1.0, 0.0);
    let walk_v =
        camera::from_axis_angle3(y_axis, self.lateral_rotation) * self.walk_accel;
    self.speed = self.speed + walk_v + self.accel;
    // friction
    self.speed = self.speed * Vec3::new(0.7, 0.99, 0.7 as f32);
  }

  /// Changes the camera's acceleration by the given `da`.
  pub fn walk(&mut self, da: Vec3<f32>) {
    self.walk_accel = self.walk_accel + da * 0.2 as f32;
  }

  /// Rotate the camera around the y axis, by `r` radians. Positive is counterclockwise.
  pub fn rotate_lateral(&mut self, r: f32) {
    self.lateral_rotation = self.lateral_rotation + r;
  }

  /// Changes the camera pitch by `r` radians. Positive is up.
  /// Angles that "flip around" (i.e. looking too far up or down)
  /// are sliently rejected.
  pub fn rotate_vertical(&mut self, r: f32) {
    let new_rotation = self.vertical_rotation + r;

    if new_rotation < -PI / 2.0
    || new_rotation >  PI / 2.0 {
      return
    }

    self.vertical_rotation = new_rotation;
  }

  // axes

  /// Return the "right" axis (i.e. the x-axis rotated to match you).
  pub fn right(&self) -> Vec3<f32> {
    return
      camera::from_axis_angle3(Vec3::new(0.0, 1.0, 0.0), self.lateral_rotation) *
      Vec3::new(1.0, 0.0, 0.0)
  }

  /// Return the "Ray axis (i.e. the z-axis rotated to match you).
  pub fn forward(&self) -> Vec3<f32> {
    let y_axis = Vec3::new(0.0, 1.0, 0.0);
    let transform =
      camera::from_axis_angle3(self.right(), self.vertical_rotation) *
      camera::from_axis_angle3(y_axis, self.lateral_rotation);
    let forward_orig = Vec3::new(0.0, 0.0, -1.0);

    transform * forward_orig
  }

  #[allow(dead_code)]
  pub fn forward_ray(&self) -> Ray3<f32> {
    Ray::new(self.position, self.forward())
  }

  pub fn lod_index(distance: i32) -> u32 {
    assert!(distance >= 0);
    let mut lod = 0;
    while
      lod < LOD_THRESHOLDS.len()
      && LOD_THRESHOLDS[lod] < distance
    {
      lod += 1;
    }
    num::cast(lod).unwrap()
  }

  pub fn load_distance(mut polygon_budget: i32) -> i32 {
    // TODO: This should try to account for VRAM not used on a per-poly basis.

    let mut load_distance = 0;
    let mut prev_threshold = 0;
    let mut prev_square = 0;
    for (&threshold, &quality) in
      LOD_THRESHOLDS.iter()
        .zip(terrain::LOD_QUALITY.iter()) {
      let polygons_per_block = (quality * quality * 4) as i32;
      for i in range_inclusive(prev_threshold, threshold) {
        let i = 2 * i + 1;
        let square = i * i;
        let polygons_in_layer = (square - prev_square) * polygons_per_block;
        polygon_budget -= polygons_in_layer;
        if polygon_budget < 0 {
          break;
        }

        load_distance += 1;
        prev_square = square;
      }
      prev_threshold = threshold + 1;
    }

    let mut width = 2 * prev_threshold + 1;
    loop {
      let square = width * width;
      // The "to infinity and beyond" quality.
      let quality = terrain::LOD_QUALITY[LOD_THRESHOLDS.len()];
      let polygons_per_block = (quality * quality * 4) as i32;
      let polygons_in_layer = (square - prev_square) * polygons_per_block;
      polygon_budget -= polygons_in_layer;

      if polygon_budget < 0 {
        break;
      }

      width += 2;
      load_distance += 1;
      prev_square = square;
    }

    load_distance
  }
}
<|endoftext|>


<commit_before>//! The `random` module creates random `ast::structure::Program`.
//!
//! It implements `rand::Rand` for all important structures. It does this by
//! making use of a macro `pick` that can choose an expression according to
//! weight.
//!
//! # Examples
//!
//! ```
//! #[macro_use]
//! extern crate ast;
//! extern crate rand;
//! extern crate rustc_serialize;
//!
//! pub use rand::Rng;
//!
//! use ast::structure::Program;
//! use ast::source::Source;
//!
//! fn main() {
//!     let generated: Program = rand::random();
//!     println!("{}", generated.source());
//! }
//! ```

extern crate rand;

pub use self::rand::Rng;

use super::structure::{Program,Condition,Command,Expression,Sensor};

#[macro_export]
macro_rules! pick {
    ($( $weight: expr, $expression: expr),+) => {{
        let total = 0 $(+ $weight)+;
        let mut bound = 0;

        let mut rng = rand::thread_rng();
        let random_number = rng.gen_range(0, total);
        let result = $( if bound <= random_number && random_number < { bound += $weight; bound } {
            $expression
        } else )+ {
           panic!();
        };
        result
    }}
}

impl rand::Rand for Program {
	  fn rand<R: rand::Rng>(rng: &mut R) -> Self {
        pick![
            1, Program::If(Condition::rand(rng), Box::new(Program::rand(rng)), Box::new(Program::rand(rng))),
            1, Program::Command(Command::rand(rng))
        ]
	  }
}

impl rand::Rand for Condition {
	  fn rand<R: rand::Rng>(rng: &mut R) -> Self {
        pick![
            8, Condition::True,
			      8, Condition::False,
			      2, Condition::Not(Box::new(Condition::rand(rng))),
			      1, Condition::Or(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			      1, Condition::And(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			      1, Condition::Less(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			      1, Condition::LessEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			      1, Condition::Equal(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			      1, Condition::GreaterEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			      1, Condition::Greater(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng)))
		    ]
	  }
}

impl rand::Rand for Command {
	fn rand<R: rand::Rng>(_: &mut R) -> Self {
		  pick![1, Command::Skip, 1, Command::Left, 1, Command::Right, 1, Command::Up]
  }
}

impl rand::Rand for Expression {
	  fn rand<R: rand::Rng>(rng: &mut R) -> Self {
        pick![
            5, Expression::Constant(rng.next_f32()),
            5, Expression::Sensor(Sensor::rand(rng)),
            1, Expression::Plus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
            1, Expression::Minus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
            1, Expression::Multiply(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
            1, Expression::Divide(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng)))
        ]
	  }
}

impl rand::Rand for Sensor {
	  fn rand<R: rand::Rng>(_: &mut R) -> Self {
        pick![1, Sensor::X, 1, Sensor::Y, 1, Sensor::Vx, 1, Sensor::Vy, 1, Sensor::O, 1, Sensor::W]
	}
}
<commit_msg>Document pick macro<commit_after>//! The `random` module creates random `ast::structure::Program`.
//!
//! It implements `rand::Rand` for all important structures. It does this by
//! making use of a macro `pick` that can choose an expression according to
//! weight.
//!
//! # Examples
//!
//! ```
//! #[macro_use]
//! extern crate ast;
//! extern crate rand;
//! extern crate rustc_serialize;
//!
//! pub use rand::Rng;
//!
//! use ast::structure::Program;
//! use ast::source::Source;
//!
//! fn main() {
//!     let generated: Program = rand::random();
//!     println!("{}", generated.source());
//! }
//! ```

extern crate rand;

pub use self::rand::Rng;

use super::structure::{Program,Condition,Command,Expression,Sensor};

/// The `pick` macro allows to randomly select one expression from a sequence of
/// expressions according to associated weights.
#[macro_export]
macro_rules! pick {
    ($( $weight: expr, $expression: expr),+) => {{
        let total = 0 $(+ $weight)+;
        let mut bound = 0;

        let mut rng = rand::thread_rng();
        let random_number = rng.gen_range(0, total);
        let result = $( if bound <= random_number && random_number < { bound += $weight; bound } {
            $expression
        } else )+ {
           panic!();
        };
        result
    }}
}

impl rand::Rand for Program {
	  fn rand<R: rand::Rng>(rng: &mut R) -> Self {
        pick![
            1, Program::If(Condition::rand(rng), Box::new(Program::rand(rng)), Box::new(Program::rand(rng))),
            1, Program::Command(Command::rand(rng))
        ]
	  }
}

impl rand::Rand for Condition {
	  fn rand<R: rand::Rng>(rng: &mut R) -> Self {
        pick![
            8, Condition::True,
			      8, Condition::False,
			      2, Condition::Not(Box::new(Condition::rand(rng))),
			      1, Condition::Or(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			      1, Condition::And(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			      1, Condition::Less(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			      1, Condition::LessEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			      1, Condition::Equal(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			      1, Condition::GreaterEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			      1, Condition::Greater(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng)))
		    ]
	  }
}

impl rand::Rand for Command {
	fn rand<R: rand::Rng>(_: &mut R) -> Self {
		  pick![1, Command::Skip, 1, Command::Left, 1, Command::Right, 1, Command::Up]
  }
}

impl rand::Rand for Expression {
	  fn rand<R: rand::Rng>(rng: &mut R) -> Self {
        pick![
            5, Expression::Constant(rng.next_f32()),
            5, Expression::Sensor(Sensor::rand(rng)),
            1, Expression::Plus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
            1, Expression::Minus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
            1, Expression::Multiply(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
            1, Expression::Divide(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng)))
        ]
	  }
}

impl rand::Rand for Sensor {
	  fn rand<R: rand::Rng>(_: &mut R) -> Self {
        pick![1, Sensor::X, 1, Sensor::Y, 1, Sensor::Vx, 1, Sensor::Vy, 1, Sensor::O, 1, Sensor::W]
	}
}
<|endoftext|>


<commit_before>#![allow(unused_imports)]
#![allow(non_snake_case)]

use procon::*;
use std::cmp::{max, min};
use std::collections::*;
use std::ops::*;
use std::*;

pub fn main() {
    return;
}

pub mod procon {
    use std;
    use std::cmp::*;
    use std::collections::*;
    use std::io;
    use std::mem;
    use std::str::FromStr;

    pub fn read_line() -> String {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.trim_right().to_owned()
    }

    pub fn read_words<T>() -> Vec<T>
    where
        T: std::str::FromStr,
        T::Err: std::fmt::Debug,
    {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.split_whitespace()
            .map(|word| T::from_str(word).unwrap())
            .collect()
    }

    pub fn read_vec(len: usize) -> Vec<String> {
        let mut vec = Vec::new();
        while vec.len() < len {
            let line = read_line();
            for word in line.split_whitespace() {
                vec.push(word.to_owned());
            }
        }
        assert!(vec.len() == len);
        vec
    }

    // Polyfill
    #[derive(PartialEq, Eq, Clone, Debug)]
    pub struct Rev<T>(pub T);

    impl<T: PartialOrd> PartialOrd for Rev<T> {
        fn partial_cmp(&self, other: &Rev<T>) -> Option<Ordering> {
            other.0.partial_cmp(&self.0)
        }
    }

    impl<T: Ord> Ord for Rev<T> {
        fn cmp(&self, other: &Rev<T>) -> Ordering {
            other.0.cmp(&self.0)
        }
    }
}

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

    #[test]
    pub fn test_ok() {
        assert_eq!(7, 1 + 2 * 3);
    }
}
<commit_msg>Remove read_vec (because infrequently used)<commit_after>#![allow(unused_imports)]
#![allow(non_snake_case)]

use procon::*;
use std::cmp::{max, min};
use std::collections::*;
use std::ops::*;
use std::*;

pub fn main() {
    return;
}

pub mod procon {
    use std;
    use std::cmp::*;
    use std::collections::*;
    use std::io;
    use std::mem;
    use std::str::FromStr;

    pub fn read_line() -> String {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.trim_right().to_owned()
    }

    pub fn read_words<T>() -> Vec<T>
    where
        T: std::str::FromStr,
        T::Err: std::fmt::Debug,
    {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.split_whitespace()
            .map(|word| T::from_str(word).unwrap())
            .collect()
    }

    // Polyfill
    #[derive(PartialEq, Eq, Clone, Debug)]
    pub struct Rev<T>(pub T);

    impl<T: PartialOrd> PartialOrd for Rev<T> {
        fn partial_cmp(&self, other: &Rev<T>) -> Option<Ordering> {
            other.0.partial_cmp(&self.0)
        }
    }

    impl<T: Ord> Ord for Rev<T> {
        fn cmp(&self, other: &Rev<T>) -> Ordering {
            other.0.cmp(&self.0)
        }
    }
}

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

    #[test]
    pub fn test_ok() {
        assert_eq!(7, 1 + 2 * 3);
    }
}
<|endoftext|>


<commit_before>use std::fmt;

pub type NSSResult<T> = Result<T, NSSError>;

pub enum NSSError
{
    /// An error generated by NSPR or NSS
    NSS(i32),
}

impl fmt::Show for NSSError
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::FormatError>
    {
        match *self
        {
            NSSError::NSS(code) => {
                match ::ffi::nspr::get_error_message(code)
                {
                    Some(message) => formatter.write(message.as_bytes()),
                    None => write!(formatter, "Unknown error {}", code),
                }
            },
        }
    }
}
<commit_msg>fmt::FormatError is now fmt::Error<commit_after>use std::fmt;

pub type NSSResult<T> = Result<T, NSSError>;

pub enum NSSError
{
    /// An error generated by NSPR or NSS
    NSS(i32),
}

impl fmt::Show for NSSError
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error>
    {
        match *self
        {
            NSSError::NSS(code) => {
                match ::ffi::nspr::get_error_message(code)
                {
                    Some(message) => formatter.write(message.as_bytes()),
                    None => write!(formatter, "Unknown error {}", code),
                }
            },
        }
    }
}
<|endoftext|>


<commit_before>use super::{AssertionFailure, Spec};

use std::fmt::Debug;

pub trait ResultAssertions<'s, T, E>
    where T: Debug,
          E: Debug
{
    fn is_ok(&mut self) -> Spec<'s, T>;
    fn is_error(&mut self) -> Spec<'s, E>;
}

pub trait ContainingResultAssertions<T, E>
    where T: Debug + PartialEq,
          E: Debug + PartialEq
{
    fn is_ok_containing(&mut self, expected_value: &T);
    fn is_err_containing(&mut self, expected_value: &E);
}

impl<'s, T, E> ContainingResultAssertions<T, E> for Spec<'s, Result<T, E>>
    where T: Debug + PartialEq,
          E: Debug + PartialEq
{
    /// Asserts that the subject is an `Ok` Result containing the expected value.
    /// The subject type must be a `Result`.
    ///
    /// ```rust,ignore
    /// assert_that(&Result::Ok::<usize, usize>(1)).is_ok_containing(&1);
    /// ```
    fn is_ok_containing(&mut self, expected_value: &T) {
        match self.subject {
            &Ok(ref val) => {
                if !val.eq(expected_value) {
                    AssertionFailure::from_spec(self)
                        .with_expected(build_detail_message("ok", expected_value))
                        .with_actual(build_detail_message("ok", val))
                        .fail();
                }
            }
            &Err(ref val) => {
                AssertionFailure::from_spec(self)
                    .with_expected(build_detail_message("ok", expected_value))
                    .with_actual(build_detail_message("err", val))
                    .fail();
            }
        }
    }

    /// Asserts that the subject is an `Err` Result containing the expected value.
    /// The subject type must be a `Result`.
    ///
    /// ```rust,ignore
    /// assert_that(&Result::Err::<usize, usize>(1)).is_err_containing(&1);
    /// ```
    fn is_err_containing(&mut self, expected_value: &E) {
        match self.subject {
            &Err(ref val) => {
                if !val.eq(expected_value) {
                    AssertionFailure::from_spec(self)
                        .with_expected(build_detail_message("err", expected_value))
                        .with_actual(build_detail_message("err", val))
                        .fail();
                }
            }
            &Ok(ref val) => {
                AssertionFailure::from_spec(self)
                    .with_expected(build_detail_message("err", expected_value))
                    .with_actual(build_detail_message("ok", val))
                    .fail();
            }
        }
    }
}

fn build_detail_message<T: Debug>(variant: &'static str, value: T) -> String {
    format!("Result[{}] containing <{:?}>", variant, value)
}

impl<'s, T, E> ResultAssertions<'s, T, E> for Spec<'s, Result<T, E>>
    where T: Debug,
          E: Debug
{
    /// Asserts that the subject is `Ok`. The value type must be a `Result`.
    ///
    /// This will return a new `Spec` containing the unwrapped value if it is `Ok`.
    ///
    /// ```rust,ignore
    /// assert_that(&Result::Ok::<usize, usize>(1)).is_ok();
    /// ```
    fn is_ok(&mut self) -> Spec<'s, T> {
        return match self.subject {
            &Ok(ref val) => {
                Spec {
                    subject: val,
                    subject_name: self.subject_name,
                    location: self.location.clone(),
                    description: self.description,
                }
            }
            &Err(ref err) => {
                AssertionFailure::from_spec(self)
                    .with_expected(format!("result[ok]"))
                    .with_actual(format!("result[error]<{:?}>", err))
                    .fail();

                unreachable!();
            }
        };
    }

    /// Asserts that the subject is `Err`. The value type must be a `Result`.
    ///
    /// This will return a new `Spec` containing the unwrapped value if it is `Err`.
    ///
    /// ```rust,ignore
    /// assert_that(&Result::Err::<usize, usize>(1)).is_error();
    /// ```
    fn is_error(&mut self) -> Spec<'s, E> {
        return match self.subject {
            &Err(ref val) => {
                Spec {
                    subject: val,
                    subject_name: self.subject_name,
                    location: self.location.clone(),
                    description: self.description,
                }
            }
            &Ok(ref val) => {
                AssertionFailure::from_spec(self)
                    .with_expected(format!("result[error]"))
                    .with_actual(format!("result[ok]<{:?}>", val))
                    .fail();

                unreachable!();
            }
        };
    }
}

#[cfg(test)]
mod tests {

    use super::super::prelude::*;

    #[test]
    fn should_not_panic_if_result_is_expected_to_be_ok_and_is() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_ok();
    }

    #[test]
    #[should_panic(expected = "\n\texpected: result[ok]\n\t but was: result[error]<\"Oh no\">")]
    fn should_panic_if_result_is_expected_to_be_ok_and_is_not() {
        let result: Result<&str, &str> = Err("Oh no");
        assert_that(&result).is_ok();
    }

    #[test]
    fn should_return_unwrapped_value_if_subject_is_ok() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_ok().is_equal_to(&"Hello");
    }

    #[test]
    fn should_not_panic_if_result_is_expected_to_be_error_and_is() {
        let result: Result<&str, &str> = Err("Oh no");
        assert_that(&result).is_error();
    }

    #[test]
    #[should_panic(expected = "\n\texpected: result[error]\n\t but was: result[ok]<\"Hello\">")]
    fn should_panic_if_result_is_expected_to_be_error_and_is_not() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_error();
    }

    #[test]
    fn should_return_unwrapped_value_if_subject_is_err() {
        let result: Result<&str, &str> = Err("Hello");
        assert_that(&result).is_error().is_equal_to(&"Hello");
    }

    #[test]
    fn should_not_panic_if_result_is_ok_with_expected_value() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_ok_containing(&"Hello");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Result[ok] containing <\"Hi\">\
                   \n\t but was: Result[ok] containing <\"Hello\">")]
    fn should_panic_if_result_is_ok_without_expected_value() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_ok_containing(&"Hi");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Result[ok] containing <\"Hi\">\
                   \n\t but was: Result[err] containing <\"Hi\">")]
    fn should_panic_if_result_is_err_if_ok_with_value_expected() {
        let result: Result<&str, &str> = Err("Hi");
        assert_that(&result).is_ok_containing(&"Hi");
    }

    #[test]
    fn should_not_panic_if_result_is_err_with_expected_value() {
        let result: Result<&str, &str> = Err("Oh no");
        assert_that(&result).is_err_containing(&"Oh no");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Result[err] containing <\"Oh no\">\
                   \n\t but was: Result[err] containing <\"Whoops\">")]
    fn should_panic_if_result_is_err_without_expected_value() {
        let result: Result<&str, &str> = Err("Whoops");
        assert_that(&result).is_err_containing(&"Oh no");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Result[err] containing <\"Oh no\">\
                   \n\t but was: Result[ok] containing <\"Oh no\">")]
    fn should_panic_if_result_is_ok_if_err_with_value_expected() {
        let result: Result<&str, &str> = Ok("Oh no");
        assert_that(&result).is_err_containing(&"Oh no");
    }

}
<commit_msg>Refine the bounds on ContainingResultAssertions<commit_after>use super::{AssertionFailure, Spec};

use std::fmt::Debug;

pub trait ResultAssertions<'s, T, E>
    where T: Debug,
          E: Debug
{
    fn is_ok(&mut self) -> Spec<'s, T>;
    fn is_error(&mut self) -> Spec<'s, E>;
}

pub trait ContainingResultAssertions<T, E>
    where T: Debug,
          E: Debug
{
    fn is_ok_containing(&mut self, expected_value: &T)
        where T: PartialEq;
    fn is_err_containing(&mut self, expected_value: &E)
        where E: PartialEq;
}

impl<'s, T, E> ContainingResultAssertions<T, E> for Spec<'s, Result<T, E>>
    where T: Debug,
          E: Debug
{
    /// Asserts that the subject is an `Ok` Result containing the expected value.
    /// The subject type must be a `Result`.
    ///
    /// ```rust,ignore
    /// assert_that(&Result::Ok::<usize, usize>(1)).is_ok_containing(&1);
    /// ```
    fn is_ok_containing(&mut self, expected_value: &T)
        where T: PartialEq
    {
        match self.subject {
            &Ok(ref val) => {
                if !val.eq(expected_value) {
                    AssertionFailure::from_spec(self)
                        .with_expected(build_detail_message("ok", expected_value))
                        .with_actual(build_detail_message("ok", val))
                        .fail();
                }
            }
            &Err(ref val) => {
                AssertionFailure::from_spec(self)
                    .with_expected(build_detail_message("ok", expected_value))
                    .with_actual(build_detail_message("err", val))
                    .fail();
            }
        }
    }

    /// Asserts that the subject is an `Err` Result containing the expected value.
    /// The subject type must be a `Result`.
    ///
    /// ```rust,ignore
    /// assert_that(&Result::Err::<usize, usize>(1)).is_err_containing(&1);
    /// ```
    fn is_err_containing(&mut self, expected_value: &E)
        where E: PartialEq
    {
        match self.subject {
            &Err(ref val) => {
                if !val.eq(expected_value) {
                    AssertionFailure::from_spec(self)
                        .with_expected(build_detail_message("err", expected_value))
                        .with_actual(build_detail_message("err", val))
                        .fail();
                }
            }
            &Ok(ref val) => {
                AssertionFailure::from_spec(self)
                    .with_expected(build_detail_message("err", expected_value))
                    .with_actual(build_detail_message("ok", val))
                    .fail();
            }
        }
    }
}

fn build_detail_message<T: Debug>(variant: &'static str, value: T) -> String {
    format!("Result[{}] containing <{:?}>", variant, value)
}

impl<'s, T, E> ResultAssertions<'s, T, E> for Spec<'s, Result<T, E>>
    where T: Debug,
          E: Debug
{
    /// Asserts that the subject is `Ok`. The value type must be a `Result`.
    ///
    /// This will return a new `Spec` containing the unwrapped value if it is `Ok`.
    ///
    /// ```rust,ignore
    /// assert_that(&Result::Ok::<usize, usize>(1)).is_ok();
    /// ```
    fn is_ok(&mut self) -> Spec<'s, T> {
        return match self.subject {
            &Ok(ref val) => {
                Spec {
                    subject: val,
                    subject_name: self.subject_name,
                    location: self.location.clone(),
                    description: self.description,
                }
            }
            &Err(ref err) => {
                AssertionFailure::from_spec(self)
                    .with_expected(format!("result[ok]"))
                    .with_actual(format!("result[error]<{:?}>", err))
                    .fail();

                unreachable!();
            }
        };
    }

    /// Asserts that the subject is `Err`. The value type must be a `Result`.
    ///
    /// This will return a new `Spec` containing the unwrapped value if it is `Err`.
    ///
    /// ```rust,ignore
    /// assert_that(&Result::Err::<usize, usize>(1)).is_error();
    /// ```
    fn is_error(&mut self) -> Spec<'s, E> {
        return match self.subject {
            &Err(ref val) => {
                Spec {
                    subject: val,
                    subject_name: self.subject_name,
                    location: self.location.clone(),
                    description: self.description,
                }
            }
            &Ok(ref val) => {
                AssertionFailure::from_spec(self)
                    .with_expected(format!("result[error]"))
                    .with_actual(format!("result[ok]<{:?}>", val))
                    .fail();

                unreachable!();
            }
        };
    }
}

#[cfg(test)]
mod tests {

    use super::super::prelude::*;

    #[test]
    fn should_not_panic_if_result_is_expected_to_be_ok_and_is() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_ok();
    }

    #[test]
    #[should_panic(expected = "\n\texpected: result[ok]\n\t but was: result[error]<\"Oh no\">")]
    fn should_panic_if_result_is_expected_to_be_ok_and_is_not() {
        let result: Result<&str, &str> = Err("Oh no");
        assert_that(&result).is_ok();
    }

    #[test]
    fn should_return_unwrapped_value_if_subject_is_ok() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_ok().is_equal_to(&"Hello");
    }

    #[test]
    fn should_not_panic_if_result_is_expected_to_be_error_and_is() {
        let result: Result<&str, &str> = Err("Oh no");
        assert_that(&result).is_error();
    }

    #[test]
    #[should_panic(expected = "\n\texpected: result[error]\n\t but was: result[ok]<\"Hello\">")]
    fn should_panic_if_result_is_expected_to_be_error_and_is_not() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_error();
    }

    #[test]
    fn should_return_unwrapped_value_if_subject_is_err() {
        let result: Result<&str, &str> = Err("Hello");
        assert_that(&result).is_error().is_equal_to(&"Hello");
    }

    #[test]
    fn should_not_panic_if_result_is_ok_with_expected_value() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_ok_containing(&"Hello");
    }

    #[test]
    fn should_not_panic_if_result_is_ok_with_uncomparable_ok() {
        #[derive(Debug)]
        struct Incomporable;
        let result: Result<&str, Incomporable> = Ok("Hello");
        assert_that(&result).is_ok_containing(&"Hello");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Result[ok] containing <\"Hi\">\
                   \n\t but was: Result[ok] containing <\"Hello\">")]
    fn should_panic_if_result_is_ok_without_expected_value() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_ok_containing(&"Hi");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Result[ok] containing <\"Hi\">\
                   \n\t but was: Result[err] containing <\"Hi\">")]
    fn should_panic_if_result_is_err_if_ok_with_value_expected() {
        let result: Result<&str, &str> = Err("Hi");
        assert_that(&result).is_ok_containing(&"Hi");
    }

    #[test]
    fn should_not_panic_if_result_is_err_with_expected_value() {
        let result: Result<&str, &str> = Err("Oh no");
        assert_that(&result).is_err_containing(&"Oh no");
    }

    #[test]
    fn should_not_panic_if_result_is_err_with_uncomparable_ok() {
        #[derive(Debug)]
        struct Incomporable;
        let result: Result<Incomporable, &str> = Err("Oh no");
        assert_that(&result).is_err_containing(&"Oh no");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Result[err] containing <\"Oh no\">\
                   \n\t but was: Result[err] containing <\"Whoops\">")]
    fn should_panic_if_result_is_err_without_expected_value() {
        let result: Result<&str, &str> = Err("Whoops");
        assert_that(&result).is_err_containing(&"Oh no");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Result[err] containing <\"Oh no\">\
                   \n\t but was: Result[ok] containing <\"Oh no\">")]
    fn should_panic_if_result_is_ok_if_err_with_value_expected() {
        let result: Result<&str, &str> = Ok("Oh no");
        assert_that(&result).is_err_containing(&"Oh no");
    }

}
<|endoftext|>