<commit_before>extern crate nom;
extern crate num;

use std::mem;
use std::fmt;

use nom::{IResult, ErrorKind};
use num::bigint;
use num::bigint::ToBigInt;
use num::traits::{Zero, One};

static BERT_MAGIC_NUMBER: u8 = 131;
static SMALL_INTEGER_EXT: u8 = 97;
static INTEGER_EXT: u8 = 98;
static FLOAT_EXT: u8 = 99;
static ATOM_EXT: u8 = 100;
static SMALL_TUPLE_EXT: u8 = 104;
static LARGE_TUPLE_EXT: u8 = 105;
static NIL_EXT: u8 = 106;
static STRING_EXT: u8 = 107;
static LIST_EXT: u8 = 108;
static BINARY_EXT: u8 = 109;
static SMALL_BIG_EXT: u8 = 110;
static LARGE_BIG_EXT: u8 = 111;
static ATOM_UTF8_EXT: u8 = 118;
static SMALL_ATOM_UTF8_EXT: u8 = 119;
static NEW_FLOAT_EXT: u8 = 70;

#[derive(Debug, PartialEq)]
pub enum BertTerm {
    Int(i32),
    BigInt(bigint::BigInt),
    Float(f64),
    Atom(String),
    Tuple(Vec<BertTerm>),
    List(Vec<BertTerm>),
    Binary(Vec<u8>)
}

impl fmt::Display for BertTerm {
    #[allow(unused_must_use)]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            BertTerm::Int(n) => { write!(f, "{}", n) }
            BertTerm::BigInt(ref n) => { write!(f, "{}", n) }
            BertTerm::Float(x) => { write!(f, "{}", x) }
            BertTerm::Atom(ref s) => { write!(f, "{}", s) }
            BertTerm::Tuple(ref ts) => {
                write!(f, "{}", '{');
                let mut first = true;
                for t in ts {
                    if !first { write!(f, ", "); }
                    write!(f, "{}", t);
                    first = false;
                }
                write!(f, "{}", '}')
            }
            BertTerm::List(ref ts) => {
                write!(f, "[");
                let mut first = true;
                for t in ts {
                    if !first { write!(f, ", "); }
                    write!(f, "{}", t);
                    first = false;
                }
                write!(f, "]")
            }
            BertTerm::Binary(ref bytes) => {
                write!(f, "<<");
                let mut first = true;
                for b in bytes {
                    if !first { write!(f, ", "); }
                    write!(f, "{}", b);
                    first = false;
                }
                write!(f, ">>")
            }
        }
    }
}

#[derive(Debug)]
pub enum BertError {
    Unknown,
    InvalidMagicNumber
}

named!(bert_magic_number, tag!([BERT_MAGIC_NUMBER]));

fn small_integer(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([SMALL_INTEGER_EXT]));
    let (i, n) = try_parse!(i, nom::be_u8);
    IResult::Done(i, BertTerm::Int(n as i32))
}

fn integer(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([INTEGER_EXT]));
    let (i, n) = try_parse!(i, nom::be_i32);
    IResult::Done(i, BertTerm::Int(n))
}

fn atom(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([ATOM_EXT]));
    let (i, len) = try_parse!(i, nom::be_u16);
    let (i, atom_name) = try_parse!(i, take_str!(len));
    IResult::Done(i, BertTerm::Atom(atom_name.to_string()))
}

fn small_atom_utf8(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([SMALL_ATOM_UTF8_EXT]));
    let (i, len) = try_parse!(i, nom::be_u8);
    let (i, atom_name) = try_parse!(i, take_str!(len));
    IResult::Done(i, BertTerm::Atom(atom_name.to_string()))
}

fn atom_utf8(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([ATOM_UTF8_EXT]));
    let (i, len) = try_parse!(i, nom::be_u16);
    let (i, atom_name) = try_parse!(i, take_str!(len));
    IResult::Done(i, BertTerm::Atom(atom_name.to_string()))
}

fn small_tuple(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([SMALL_TUPLE_EXT]));
    let (i, arity) = try_parse!(i, nom::be_u8);
    let (i, tuple) = try_parse!(i, count!(bert_term, arity as usize));
    IResult::Done(i, BertTerm::Tuple(tuple))
}

fn large_tuple(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([LARGE_TUPLE_EXT]));
    let (i, arity) = try_parse!(i, nom::be_u32);
    let (i, tuple) = try_parse!(i, count!(bert_term, arity as usize));
    IResult::Done(i, BertTerm::Tuple(tuple))
}

fn nil(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([NIL_EXT]));
    IResult::Done(i, BertTerm::List(vec![]))
}

fn string_like_list(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([STRING_EXT]));
    let (i, len) = try_parse!(i, nom::be_u16);
    let (i, nums) = try_parse!(i, take!(len as usize));
    let elements = nums.iter().map(|n| BertTerm::Int(*n as i32)).collect();
    IResult::Done(i, BertTerm::List(elements))
}

fn list(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([LIST_EXT]));
    let (i, len) = try_parse!(i, nom::be_u32);
    let (i, mut elements) = try_parse!(i, count!(bert_term, len as usize));
    let (i, tail) = try_parse!(i, bert_term);
    match tail {
        BertTerm::List(_) => (),
        last_term => { elements.push(last_term); }
    };
    IResult::Done(i, BertTerm::List(elements))
}

fn binary(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([BINARY_EXT]));
    let (i, len) = try_parse!(i, nom::be_u32);
    let (i, elements) = try_parse!(i, count!(nom::be_u8, len as usize));
    IResult::Done(i, BertTerm::Binary(elements))
}

fn is_zero(b: u8) -> bool { b == 0 }
fn is_non_zero(b: u8) -> bool { b != 0 }

fn old_float(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([FLOAT_EXT]));
    let (i, bytes) = try_parse!(i, take_while!(is_non_zero));
    let (i, _) = try_parse!(i, take_while!(is_zero));
    let mut s = String::new();
    for b in bytes { s.push(*b as char); }
    let f = s.parse::<f64>().unwrap();
    IResult::Done(i, BertTerm::Float(f))
}

fn new_float(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([NEW_FLOAT_EXT]));
    let (i, raw_bytes) = try_parse!(i, nom::be_u64);
    let f: f64 = unsafe { mem::transmute(raw_bytes) };
    IResult::Done(i, BertTerm::Float(f))
}

fn compute_big_int(is_negative: bool, digits: &[u8]) -> bigint::BigInt {
    let mut sum: bigint::BigInt = Zero::zero();
    let mut pos: bigint::BigInt = One::one();
    for d in digits {
        let t = &pos * &(d.to_bigint().unwrap());
        sum = sum + &t;
        pos = pos * (256).to_bigint().unwrap();
    }
    if is_negative { sum = -sum; }
    return sum;
}

fn small_big_int(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([SMALL_BIG_EXT]));
    let (i, len) = try_parse!(i, nom::be_u8);
    let (i, sign) = try_parse!(i, nom::be_u8);
    let (i, digits) = try_parse!(i, take!(len as usize));
    let b = compute_big_int(sign == 1, &digits);
    IResult::Done(i, BertTerm::BigInt(b))
}

fn large_big_int(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([LARGE_BIG_EXT]));
    let (i, len) = try_parse!(i, nom::be_u32);
    let (i, sign) = try_parse!(i, nom::be_u8);
    let (i, digits) = try_parse!(i, take!(len as usize));
    let b = compute_big_int(sign == 1, &digits);
    IResult::Done(i, BertTerm::BigInt(b))
}

named!(bert_term<&[u8], BertTerm>,
       alt!(small_integer
            | integer
            | atom
            | small_atom_utf8
            | atom_utf8
            | small_tuple
            | large_tuple
            | nil
            | list
            | string_like_list
            | binary
            | old_float
            | new_float
            | small_big_int
            | large_big_int
       )
);

pub fn parse(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, bert_magic_number);
    let (i, t) = try_parse!(i, bert_term);
    IResult::Done(i, t)
}

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

    #[test]
    fn test_small_integer() {
        for i in 0 .. u8::max_value() {
            let buf = &[SMALL_INTEGER_EXT, i];
            let t = small_integer(buf);
            assert_eq!(t, IResult::Done(&b""[..], BertTerm::Int(i as i32)));
        }
    }

    #[test]
    fn test_integer() {
        let buf0 = &[INTEGER_EXT, 0, 0, 0, 1];
        let buf1 = &[INTEGER_EXT, 0, 0, 1, 0];
        let buf2 = &[INTEGER_EXT, 0, 1, 0, 0];
        let buf3 = &[INTEGER_EXT, 1, 0, 0, 0];

        assert_eq!(integer(buf0), IResult::Done(&b""[..], BertTerm::Int(1)));
        assert_eq!(integer(buf1), IResult::Done(&b""[..], BertTerm::Int(1 << 8)));
        assert_eq!(integer(buf2), IResult::Done(&b""[..], BertTerm::Int(1 << 16)));
        assert_eq!(integer(buf3), IResult::Done(&b""[..], BertTerm::Int(1 << 24)));
    }

    #[test]
    fn test_atom() {
        let buf = &[ATOM_EXT, 0, 2, b'a', b'b'];
        assert_eq!(atom(buf), IResult::Done(&b""[..], BertTerm::Atom("ab".to_string())));
    }

    #[test]
    fn test_small_tuple() {
        let buf = &[SMALL_TUPLE_EXT, 2, ATOM_EXT, 0, 2, b'o', b'k', SMALL_INTEGER_EXT, 42];
        assert_eq!(small_tuple(buf),
                   IResult::Done(&b""[..],
                                 BertTerm::Tuple(vec![BertTerm::Atom("ok".to_string()),
                                                      BertTerm::Int(42)])));
    }

    #[test]
    fn test_nil() {
        let buf = &[NIL_EXT];
        assert_eq!(nil(buf), IResult::Done(&b""[..], BertTerm::List(vec![])));
    }

    #[test]
    fn string_like_list_test() {
        use self::BertTerm::*;
        let buf = &[STRING_EXT, 0, 5, b'h', b'e', b'l', b'l', b'o'];
        assert_eq!(string_like_list(buf),
                   IResult::Done(&b""[..], List(vec![Int(104), Int(101), Int(108), Int(108), Int(111)])));
    }

    #[test]
    fn test_list() {
        use self::BertTerm::*;
        let buf0 = &[
            LIST_EXT, 0, 0, 0, 2,
            SMALL_INTEGER_EXT, 42,
            INTEGER_EXT, 0, 1, 0, 0,
            NIL_EXT
        ];
        let buf1 = &[
            LIST_EXT, 0, 0, 0, 2,
            SMALL_INTEGER_EXT, 42,
            INTEGER_EXT, 0, 1, 0, 0,
            SMALL_INTEGER_EXT, 84
        ];
        assert_eq!(list(buf0), IResult::Done(&b""[..], List(vec![Int(42), Int(65536)])));
        assert_eq!(list(buf1), IResult::Done(&b""[..], List(vec![Int(42), Int(65536), Int(84)])));
    }

    #[test]
    fn binary_test() {
        let buf = &[BINARY_EXT, 0, 0, 0, 4, 1, 3, 3, 7];
        assert_eq!(binary(buf), IResult::Done(&b""[..], BertTerm::Binary(vec![1,3,3,7])));
    }

}
<commit_msg>Add dedicated enum item for strings<commit_after>extern crate nom;
extern crate num;

use std::mem;
use std::fmt;

use nom::{IResult, ErrorKind};
use num::bigint;
use num::bigint::ToBigInt;
use num::traits::{Zero, One};

static BERT_MAGIC_NUMBER: u8 = 131;
static SMALL_INTEGER_EXT: u8 = 97;
static INTEGER_EXT: u8 = 98;
static FLOAT_EXT: u8 = 99;
static ATOM_EXT: u8 = 100;
static SMALL_TUPLE_EXT: u8 = 104;
static LARGE_TUPLE_EXT: u8 = 105;
static NIL_EXT: u8 = 106;
static STRING_EXT: u8 = 107;
static LIST_EXT: u8 = 108;
static BINARY_EXT: u8 = 109;
static SMALL_BIG_EXT: u8 = 110;
static LARGE_BIG_EXT: u8 = 111;
static ATOM_UTF8_EXT: u8 = 118;
static SMALL_ATOM_UTF8_EXT: u8 = 119;
static NEW_FLOAT_EXT: u8 = 70;

#[derive(Debug, PartialEq)]
pub enum BertTerm {
    Int(i32),
    BigInt(bigint::BigInt),
    Float(f64),
    Atom(String),
    Tuple(Vec<BertTerm>),
    List(Vec<BertTerm>),
    String(Vec<u8>),
    Binary(Vec<u8>)
}

impl fmt::Display for BertTerm {
    #[allow(unused_must_use)]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            BertTerm::Int(n) => { write!(f, "{}", n) }
            BertTerm::BigInt(ref n) => { write!(f, "{}", n) }
            BertTerm::Float(x) => { write!(f, "{}", x) }
            BertTerm::Atom(ref s) => { write!(f, "{}", s) }
            BertTerm::Tuple(ref ts) => {
                write!(f, "{}", '{');
                let mut first = true;
                for t in ts {
                    if !first { write!(f, ", "); }
                    write!(f, "{}", t);
                    first = false;
                }
                write!(f, "{}", '}')
            }
            BertTerm::List(ref ts) => {
                write!(f, "[");
                let mut first = true;
                for t in ts {
                    if !first { write!(f, ", "); }
                    write!(f, "{}", t);
                    first = false;
                }
                write!(f, "]")
            }
            BertTerm::String(ref bytes) => {
                write!(f, "\"");
                for &b in bytes {
                    if b >= 0x20 && b <= 0x7e {
                        write!(f, "{}", b as char);
                    } else {
                        write!(f, "\\x{:x}", b);
                    }
                }
                write!(f, "\"")
            }
            BertTerm::Binary(ref bytes) => {
                write!(f, "<<");
                let mut first = true;
                for b in bytes {
                    if !first { write!(f, ", "); }
                    write!(f, "{}", b);
                    first = false;
                }
                write!(f, ">>")
            }
        }
    }
}

#[derive(Debug)]
pub enum BertError {
    Unknown,
    InvalidMagicNumber
}

named!(bert_magic_number, tag!([BERT_MAGIC_NUMBER]));

fn small_integer(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([SMALL_INTEGER_EXT]));
    let (i, n) = try_parse!(i, nom::be_u8);
    IResult::Done(i, BertTerm::Int(n as i32))
}

fn integer(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([INTEGER_EXT]));
    let (i, n) = try_parse!(i, nom::be_i32);
    IResult::Done(i, BertTerm::Int(n))
}

fn atom(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([ATOM_EXT]));
    let (i, len) = try_parse!(i, nom::be_u16);
    let (i, atom_name) = try_parse!(i, take_str!(len));
    IResult::Done(i, BertTerm::Atom(atom_name.to_string()))
}

fn small_atom_utf8(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([SMALL_ATOM_UTF8_EXT]));
    let (i, len) = try_parse!(i, nom::be_u8);
    let (i, atom_name) = try_parse!(i, take_str!(len));
    IResult::Done(i, BertTerm::Atom(atom_name.to_string()))
}

fn atom_utf8(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([ATOM_UTF8_EXT]));
    let (i, len) = try_parse!(i, nom::be_u16);
    let (i, atom_name) = try_parse!(i, take_str!(len));
    IResult::Done(i, BertTerm::Atom(atom_name.to_string()))
}

fn small_tuple(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([SMALL_TUPLE_EXT]));
    let (i, arity) = try_parse!(i, nom::be_u8);
    let (i, tuple) = try_parse!(i, count!(bert_term, arity as usize));
    IResult::Done(i, BertTerm::Tuple(tuple))
}

fn large_tuple(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([LARGE_TUPLE_EXT]));
    let (i, arity) = try_parse!(i, nom::be_u32);
    let (i, tuple) = try_parse!(i, count!(bert_term, arity as usize));
    IResult::Done(i, BertTerm::Tuple(tuple))
}

fn nil(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([NIL_EXT]));
    IResult::Done(i, BertTerm::List(vec![]))
}

fn string(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([STRING_EXT]));
    let (i, len) = try_parse!(i, nom::be_u16);
    let (i, bytes) = try_parse!(i, count!(nom::be_u8, len as usize));
    IResult::Done(i, BertTerm::String(bytes))
}

fn list(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([LIST_EXT]));
    let (i, len) = try_parse!(i, nom::be_u32);
    let (i, mut elements) = try_parse!(i, count!(bert_term, len as usize));
    let (i, tail) = try_parse!(i, bert_term);
    match tail {
        BertTerm::List(_) => (),
        last_term => { elements.push(last_term); }
    };
    IResult::Done(i, BertTerm::List(elements))
}

fn binary(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([BINARY_EXT]));
    let (i, len) = try_parse!(i, nom::be_u32);
    let (i, elements) = try_parse!(i, count!(nom::be_u8, len as usize));
    IResult::Done(i, BertTerm::Binary(elements))
}

fn is_zero(b: u8) -> bool { b == 0 }
fn is_non_zero(b: u8) -> bool { b != 0 }

fn old_float(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([FLOAT_EXT]));
    let (i, bytes) = try_parse!(i, take_while!(is_non_zero));
    let (i, _) = try_parse!(i, take_while!(is_zero));
    let mut s = String::new();
    for b in bytes { s.push(*b as char); }
    let f = s.parse::<f64>().unwrap();
    IResult::Done(i, BertTerm::Float(f))
}

fn new_float(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([NEW_FLOAT_EXT]));
    let (i, raw_bytes) = try_parse!(i, nom::be_u64);
    let f: f64 = unsafe { mem::transmute(raw_bytes) };
    IResult::Done(i, BertTerm::Float(f))
}

fn compute_big_int(is_negative: bool, digits: &[u8]) -> bigint::BigInt {
    let mut sum: bigint::BigInt = Zero::zero();
    let mut pos: bigint::BigInt = One::one();
    for d in digits {
        let t = &pos * &(d.to_bigint().unwrap());
        sum = sum + &t;
        pos = pos * (256).to_bigint().unwrap();
    }
    if is_negative { sum = -sum; }
    return sum;
}

fn small_big_int(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([SMALL_BIG_EXT]));
    let (i, len) = try_parse!(i, nom::be_u8);
    let (i, sign) = try_parse!(i, nom::be_u8);
    let (i, digits) = try_parse!(i, take!(len as usize));
    let b = compute_big_int(sign == 1, &digits);
    IResult::Done(i, BertTerm::BigInt(b))
}

fn large_big_int(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, tag!([LARGE_BIG_EXT]));
    let (i, len) = try_parse!(i, nom::be_u32);
    let (i, sign) = try_parse!(i, nom::be_u8);
    let (i, digits) = try_parse!(i, take!(len as usize));
    let b = compute_big_int(sign == 1, &digits);
    IResult::Done(i, BertTerm::BigInt(b))
}

named!(bert_term<&[u8], BertTerm>,
       alt!(small_integer
            | integer
            | atom
            | small_atom_utf8
            | atom_utf8
            | small_tuple
            | large_tuple
            | nil
            | list
            | string
            | binary
            | old_float
            | new_float
            | small_big_int
            | large_big_int
       )
);

pub fn parse(i: &[u8]) -> IResult<&[u8], BertTerm> {
    let (i, _) = try_parse!(i, bert_magic_number);
    let (i, t) = try_parse!(i, bert_term);
    IResult::Done(i, t)
}

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

    #[test]
    fn test_small_integer() {
        for i in 0 .. u8::max_value() {
            let buf = &[SMALL_INTEGER_EXT, i];
            let t = small_integer(buf);
            assert_eq!(t, IResult::Done(&b""[..], BertTerm::Int(i as i32)));
        }
    }

    #[test]
    fn test_integer() {
        let buf0 = &[INTEGER_EXT, 0, 0, 0, 1];
        let buf1 = &[INTEGER_EXT, 0, 0, 1, 0];
        let buf2 = &[INTEGER_EXT, 0, 1, 0, 0];
        let buf3 = &[INTEGER_EXT, 1, 0, 0, 0];

        assert_eq!(integer(buf0), IResult::Done(&b""[..], BertTerm::Int(1)));
        assert_eq!(integer(buf1), IResult::Done(&b""[..], BertTerm::Int(1 << 8)));
        assert_eq!(integer(buf2), IResult::Done(&b""[..], BertTerm::Int(1 << 16)));
        assert_eq!(integer(buf3), IResult::Done(&b""[..], BertTerm::Int(1 << 24)));
    }

    #[test]
    fn test_atom() {
        let buf = &[ATOM_EXT, 0, 2, b'a', b'b'];
        assert_eq!(atom(buf), IResult::Done(&b""[..], BertTerm::Atom("ab".to_string())));
    }

    #[test]
    fn test_small_tuple() {
        let buf = &[SMALL_TUPLE_EXT, 2, ATOM_EXT, 0, 2, b'o', b'k', SMALL_INTEGER_EXT, 42];
        assert_eq!(small_tuple(buf),
                   IResult::Done(&b""[..],
                                 BertTerm::Tuple(vec![BertTerm::Atom("ok".to_string()),
                                                      BertTerm::Int(42)])));
    }

    #[test]
    fn test_nil() {
        let buf = &[NIL_EXT];
        assert_eq!(nil(buf), IResult::Done(&b""[..], BertTerm::List(vec![])));
    }

    #[test]
    fn string_test() {
        use self::BertTerm::*;
        let buf = &[STRING_EXT, 0, 5, b'h', b'e', b'l', b'l', b'o'];
        assert_eq!(string(buf),
                   IResult::Done(&b""[..], String(vec![104, 101, 108, 108, 111])));
    }

    #[test]
    fn test_list() {
        use self::BertTerm::*;
        let buf0 = &[
            LIST_EXT, 0, 0, 0, 2,
            SMALL_INTEGER_EXT, 42,
            INTEGER_EXT, 0, 1, 0, 0,
            NIL_EXT
        ];
        let buf1 = &[
            LIST_EXT, 0, 0, 0, 2,
            SMALL_INTEGER_EXT, 42,
            INTEGER_EXT, 0, 1, 0, 0,
            SMALL_INTEGER_EXT, 84
        ];
        assert_eq!(list(buf0), IResult::Done(&b""[..], List(vec![Int(42), Int(65536)])));
        assert_eq!(list(buf1), IResult::Done(&b""[..], List(vec![Int(42), Int(65536), Int(84)])));
    }

    #[test]
    fn binary_test() {
        let buf = &[BINARY_EXT, 0, 0, 0, 4, 1, 3, 3, 7];
        assert_eq!(binary(buf), IResult::Done(&b""[..], BertTerm::Binary(vec![1,3,3,7])));
    }

}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(path_ext)]
#![feature(rustc_private)]
#![cfg(not(test))]

#[macro_use]
extern crate log;
extern crate rustfmt;
extern crate toml;

use rustfmt::{WriteMode, run};
use rustfmt::config::Config;

use std::env;
use std::fs::{File, PathExt};
use std::io::{self, Read};
use std::path::PathBuf;
use std::str::FromStr;

// Try to find a project file in the current directory and its parents.
fn lookup_project_file() -> io::Result<PathBuf> {
    let mut current = try!(env::current_dir());
    loop {
        let config_file = current.join("rustfmt.toml");
        if config_file.exists() {
            return Ok(config_file);
        } else {
            current = match current.parent() {
                // if the current directory has no parent, we're done searching
                None => return Err(io::Error::new(io::ErrorKind::NotFound, "config not found")),
                Some(path) => path.to_path_buf(),
            };
        }
    }
}

// Try to find a project file. If it's found, read it.
fn lookup_and_read_project_file() -> io::Result<(PathBuf, String)> {
    let path = try!(lookup_project_file());
    let mut file = try!(File::open(&path));
    let mut toml = String::new();
    try!(file.read_to_string(&mut toml));
    Ok((path, toml))
}

fn execute() -> i32 {
    let (args, write_mode) = match determine_params(std::env::args()) {
        Some(params) => params,
        None => return 1,
    };

    let config = match lookup_and_read_project_file() {
        Ok((path, toml)) => {
            println!("Project config file: {}", path.display());
            Config::from_toml(&toml)
        }
        Err(_) => Default::default(),
    };

    run(args, write_mode, Box::new(config));
    0
}

fn main() {
    use std::io::Write;
    let exit_code = execute();
    // Make sure standard output is flushed before we exit
    std::io::stdout().flush().unwrap();
    // Exit with given exit code.
    //
    // NOTE: This immediately terminates the process without doing any cleanup,
    // so make sure to finish all necessary cleanup before this is called.
    std::process::exit(exit_code);
}

fn print_usage<S: Into<String>>(reason: S) {
    println!("{}\n\r usage: rustfmt [-h Help] [--write-mode=[true/false]] <file_name>", reason.into());
}

fn determine_params<I>(args: I) -> Option<(Vec<String>, WriteMode)>
    where I: Iterator<Item = String>
{
    let arg_prefix = "-";
    let write_mode_prefix = "--write-mode=";
    let help_mode = "-h";
    let long_help_mode = "--help";
    let mut write_mode = WriteMode::Replace;
    let mut rustc_args = Vec::new();

    // The NewFile option currently isn't supported because it requires another
    // parameter, but it can be added later.
    for arg in args {
        if arg.starts_with(write_mode_prefix) {
            match FromStr::from_str(&arg[write_mode_prefix.len()..]) {
                Ok(mode) => write_mode = mode,
                Err(_) => {
                    print_usage("Unrecognized write mode");
                    return None;
                }
            }
        } else if arg.starts_with(help_mode) || arg.starts_with(long_help_mode) {
            print_usage("");
            return None;
        } else if arg.starts_with(arg_prefix) {
            print_usage("Invalid argument");
            return None;
        } else {
            // Pass everything else to rustc
            rustc_args.push(arg);
        }
    }

    if rustc_args.len() < 2 {
        print_usage("Please provide a file to be formatted");
        return None;
    }

    Some((rustc_args, write_mode))
}
<commit_msg>fix outdated help text<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(path_ext)]
#![feature(rustc_private)]
#![cfg(not(test))]

#[macro_use]
extern crate log;
extern crate rustfmt;
extern crate toml;

use rustfmt::{WriteMode, run};
use rustfmt::config::Config;

use std::env;
use std::fs::{File, PathExt};
use std::io::{self, Read};
use std::path::PathBuf;
use std::str::FromStr;

// Try to find a project file in the current directory and its parents.
fn lookup_project_file() -> io::Result<PathBuf> {
    let mut current = try!(env::current_dir());
    loop {
        let config_file = current.join("rustfmt.toml");
        if config_file.exists() {
            return Ok(config_file);
        } else {
            current = match current.parent() {
                // if the current directory has no parent, we're done searching
                None => return Err(io::Error::new(io::ErrorKind::NotFound, "config not found")),
                Some(path) => path.to_path_buf(),
            };
        }
    }
}

// Try to find a project file. If it's found, read it.
fn lookup_and_read_project_file() -> io::Result<(PathBuf, String)> {
    let path = try!(lookup_project_file());
    let mut file = try!(File::open(&path));
    let mut toml = String::new();
    try!(file.read_to_string(&mut toml));
    Ok((path, toml))
}

fn execute() -> i32 {
    let (args, write_mode) = match determine_params(std::env::args()) {
        Some(params) => params,
        None => return 1,
    };

    let config = match lookup_and_read_project_file() {
        Ok((path, toml)) => {
            println!("Project config file: {}", path.display());
            Config::from_toml(&toml)
        }
        Err(_) => Default::default(),
    };

    run(args, write_mode, Box::new(config));
    0
}

fn main() {
    use std::io::Write;
    let exit_code = execute();
    // Make sure standard output is flushed before we exit
    std::io::stdout().flush().unwrap();
    // Exit with given exit code.
    //
    // NOTE: This immediately terminates the process without doing any cleanup,
    // so make sure to finish all necessary cleanup before this is called.
    std::process::exit(exit_code);
}

fn print_usage<S: Into<String>>(reason: S) {
    println!("{}\n\r usage: rustfmt [-h Help] [--write-mode=[replace|overwrite|display]] <file_name>", reason.into());
}

fn determine_params<I>(args: I) -> Option<(Vec<String>, WriteMode)>
    where I: Iterator<Item = String>
{
    let arg_prefix = "-";
    let write_mode_prefix = "--write-mode=";
    let help_mode = "-h";
    let long_help_mode = "--help";
    let mut write_mode = WriteMode::Replace;
    let mut rustc_args = Vec::new();

    // The NewFile option currently isn't supported because it requires another
    // parameter, but it can be added later.
    for arg in args {
        if arg.starts_with(write_mode_prefix) {
            match FromStr::from_str(&arg[write_mode_prefix.len()..]) {
                Ok(mode) => write_mode = mode,
                Err(_) => {
                    print_usage("Unrecognized write mode");
                    return None;
                }
            }
        } else if arg.starts_with(help_mode) || arg.starts_with(long_help_mode) {
            print_usage("");
            return None;
        } else if arg.starts_with(arg_prefix) {
            print_usage("Invalid argument");
            return None;
        } else {
            // Pass everything else to rustc
            rustc_args.push(arg);
        }
    }

    if rustc_args.len() < 2 {
        print_usage("Please provide a file to be formatted");
        return None;
    }

    Some((rustc_args, write_mode))
}
<|endoftext|>


<commit_before>// Cymbalum, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license
use toml::{Parser, Table, Value};

use std::io::prelude::*;
use std::io;
use std::result;
use std::fs::File;
use std::path::Path;

use system::System;
use units::UnitParsingError;
use potentials::{PairPotential, PairRestriction};

mod toml;
mod pairs;
mod angles;
mod coulomb;

#[cfg(test)]
pub mod testing;

use self::pairs::{TwoBody, read_2body};
use self::angles::{read_angles, read_dihedrals};
use self::coulomb::{read_coulomb, set_charges};

#[derive(Debug)]
/// Possible causes of error when reading potential files
pub enum Error {
    /// Error in the TOML input file
    TOML(String),
    /// IO error
    File(io::Error),
    /// File content error: missing sections, bad data types
    Config{
        /// Error message
        msg: String,
    },
    /// Unit parsing error
    UnitParsing(UnitParsingError),
}

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

impl<'a> From<&'a str> for Error {
    fn from(err: &'a str) -> Error {
        Error::Config{msg: String::from(err)}
    }
}

impl From<String> for Error {
    fn from(err: String) -> Error {
        Error::Config{msg: err}
    }
}

impl From<UnitParsingError> for Error {
    fn from(err: UnitParsingError) -> Error {Error::UnitParsing(err)}
}

/// Custom `Result` for input files
pub type Result<T> = result::Result<T, Error>;

/// Convert a TOML table to a Rust type. This is the trait to implement in order
/// to use the input files.
pub trait FromToml: Sized {
    /// Do the conversion from `table` to Self.
    fn from_toml(table: &Table) -> Result<Self>;
}

/// Convert a TOML table and a PairPotential to a Rust type. This is intended
/// to be used by potential computation mainly.
pub trait FromTomlWithPairs where Self: Sized {
    /// Do the conversion from `table` and `potential` to Self.
    fn from_toml(table: &Table, potential: Box<PairPotential>) -> Result<Self>;
}

/// Read interactions from the TOML file at `path`, and add them to the
/// `system`. For a full documentation of the input files syntax, see the user
/// manual.
pub fn read_interactions<P: AsRef<Path>>(system: &mut System, path: P) -> Result<()> {
    let mut file = try!(File::open(path));
    let mut buffer = String::new();
    let _ = try!(file.read_to_string(&mut buffer));
    return read_interactions_string(system, &buffer);
}

/// This is the same as `read_interactions`, but directly read a TOML formated
/// string.
pub fn read_interactions_string(system: &mut System, string: &str) -> Result<()> {
    let mut parser = Parser::new(string);
    let config = match parser.parse() {
        Some(config) => config,
        None => {
            let errors = toml_error_to_string(&parser);
            return Err(Error::TOML(errors));
        }
    };

    try!(validate(&config));
    if let Some(pairs) = config.get("pairs") {
        let pairs = try!(pairs.as_slice().ok_or(
            Error::from("The 'pairs' section must be an array")
        ));
        try!(read_2body(system, pairs, TwoBody::Pairs));
    }

    if let Some(bonds) = config.get("bonds") {
        let bonds = try!(bonds.as_slice().ok_or(
            Error::from("The 'bonds' section must be an array")
        ));
        try!(read_2body(system, bonds, TwoBody::Bonds));
    }

    if let Some(angles) = config.get("angles") {
        let angles = try!(angles.as_slice().ok_or(
            Error::from("The 'angles' section must be an array")
        ));
        try!(read_angles(system, angles));
    }

    if let Some(dihedrals) = config.get("dihedrals") {
        let dihedrals = try!(dihedrals.as_slice().ok_or(
            Error::from("The 'dihedrals' section must be an array")
        ));
        try!(read_dihedrals(system, dihedrals));
    }

    if let Some(coulomb) = config.get("coulomb") {
        let coulomb = try!(coulomb.as_table().ok_or(
            Error::from("The 'coulomb' section must be a table")
        ));
        try!(read_coulomb(system, coulomb));
    }

    if let Some(charges) = config.get("charges") {
        let charges = try!(charges.as_table().ok_or(
            Error::from("The 'charges' section must be a table")
        ));
        try!(set_charges(system, charges));
    }

    Ok(())
}

fn validate(config: &Table) -> Result<()> {
    let input = try!(config.get("input").ok_or(
        Error::from("Missing 'input' table")
    ));

    let version = try!(input.lookup("potentials.version").ok_or(
        Error::from("Missing 'potentials.version' key in 'input' table")
    ));

    let version = try!(version.as_integer().ok_or(
        Error::from("'input.potentials.version' must be an integer")
    ));

    if version != 1 {
        return Err(Error::from(
            format!("Only version 1 of input can be read, got {}", version)
        ))
    }

    Ok(())
}

fn read_restriction(config: &Table) -> Result<Option<PairRestriction>> {
    let restriction = match config.get("restriction") {
        Some(restriction) => restriction,
        None => {return Ok(None)}
    };

    match restriction.clone() {
        Value::String(name) => {
            match &*name {
                "none" => Ok(Some(PairRestriction::None)),
                "intramolecular" | "IntraMolecular" | "intra-molecular"
                    => Ok(Some(PairRestriction::IntraMolecular)),
                "intermolecular" | "InterMolecular" | "inter-molecular"
                    => Ok(Some(PairRestriction::InterMolecular)),
                "exclude12" => Ok(Some(PairRestriction::Exclude12)),
                "exclude13" => Ok(Some(PairRestriction::Exclude13)),
                "exclude14" => Ok(Some(PairRestriction::Exclude14)),
                "scale14" => Err(
                    Error::from("'scale14' restriction must be a table")
                ),
                other => Err(
                    Error::from(format!("Unknown restriction '{}'", other))
                ),
            }
        },
        Value::Table(ref restriction) => {
            if restriction.keys().len() != 1 || restriction.get("scale14").is_none() {
                return Err(Error::from("Restriction table must be 'scale14'"));
            }
            let scale = try!(restriction["scale14"].as_float().ok_or(
                Error::from("'scale14' parameter must be a float")
            ));
            Ok(Some(PairRestriction::Scale14{scaling: scale}))
        }
        _ => Err(Error::from("Restriction must be a table or a string"))
    }
}

fn toml_error_to_string(parser: &Parser) -> String {
    let nerrors = parser.errors.len();
    assert!(nerrors > 0);

    let errors = parser.errors.iter().map(|error|{
        let (line, _) = parser.to_linecol(error.lo);
        format!("{} at line {}", error.desc, line + 1)
    }).collect::<Vec<_>>().join("\n    ");

    let plural = if nerrors != 1 {"s"} else {""};
    return format!("TOML parsing error{}: {}", plural, errors);
}

#[cfg(test)]
mod tests {
    use system::System;
    use input::read_interactions;
    use input::interactions::testing::bad_interactions;

    #[test]
    fn bad_input() {
        for path in bad_interactions("generic") {
            let mut system = System::new();
            assert!(read_interactions(&mut system, path).is_err());
        }
    }
}
<commit_msg>Implement Error for InteractionsError<commit_after>// Cymbalum, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license
use toml::{Parser, Table, Value};

use std::io::prelude::*;
use std::io;
use std::result;
use std::fs::File;
use std::path::Path;
use std::error;
use std::fmt;

use system::System;
use units::UnitParsingError;
use potentials::{PairPotential, PairRestriction};

mod toml;
mod pairs;
mod angles;
mod coulomb;

#[cfg(test)]
pub mod testing;

use self::pairs::{TwoBody, read_2body};
use self::angles::{read_angles, read_dihedrals};
use self::coulomb::{read_coulomb, set_charges};

#[derive(Debug)]
/// Possible causes of error when reading potential files
pub enum Error {
    /// Error in the TOML input file
    TOML(String),
    /// IO error
    File(io::Error),
    /// File content error: missing sections, bad data types
    Config{
        /// Error message
        msg: String,
    },
    /// Unit parsing error
    UnitParsing(UnitParsingError),
}

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

impl<'a> From<&'a str> for Error {
    fn from(err: &'a str) -> Error {
        Error::Config{msg: String::from(err)}
    }
}

impl From<String> for Error {
    fn from(err: String) -> Error {
        Error::Config{msg: err}
    }
}

impl From<UnitParsingError> for Error {
    fn from(err: UnitParsingError) -> Error {Error::UnitParsing(err)}
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        use std::error::Error as StdError;
        try!(write!(fmt, "{}", self.description()));
        Ok(())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::TOML(ref err) => err,
            Error::Config{ref msg} => msg,
            Error::File(ref err) => err.description(),
            Error::UnitParsing(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::TOML(..) => None,
            Error::Config{..} => None,
            Error::File(ref err) => Some(err),
            Error::UnitParsing(ref err) => Some(err),
        }
    }
}

/// Custom `Result` for input files
pub type Result<T> = result::Result<T, Error>;

/// Convert a TOML table to a Rust type. This is the trait to implement in order
/// to use the input files.
pub trait FromToml: Sized {
    /// Do the conversion from `table` to Self.
    fn from_toml(table: &Table) -> Result<Self>;
}

/// Convert a TOML table and a PairPotential to a Rust type. This is intended
/// to be used by potential computation mainly.
pub trait FromTomlWithPairs where Self: Sized {
    /// Do the conversion from `table` and `potential` to Self.
    fn from_toml(table: &Table, potential: Box<PairPotential>) -> Result<Self>;
}

/// Read interactions from the TOML file at `path`, and add them to the
/// `system`. For a full documentation of the input files syntax, see the user
/// manual.
pub fn read_interactions<P: AsRef<Path>>(system: &mut System, path: P) -> Result<()> {
    let mut file = try!(File::open(path));
    let mut buffer = String::new();
    let _ = try!(file.read_to_string(&mut buffer));
    return read_interactions_string(system, &buffer);
}

/// This is the same as `read_interactions`, but directly read a TOML formated
/// string.
pub fn read_interactions_string(system: &mut System, string: &str) -> Result<()> {
    let mut parser = Parser::new(string);
    let config = match parser.parse() {
        Some(config) => config,
        None => {
            let errors = toml_error_to_string(&parser);
            return Err(Error::TOML(errors));
        }
    };

    try!(validate(&config));
    if let Some(pairs) = config.get("pairs") {
        let pairs = try!(pairs.as_slice().ok_or(
            Error::from("The 'pairs' section must be an array")
        ));
        try!(read_2body(system, pairs, TwoBody::Pairs));
    }

    if let Some(bonds) = config.get("bonds") {
        let bonds = try!(bonds.as_slice().ok_or(
            Error::from("The 'bonds' section must be an array")
        ));
        try!(read_2body(system, bonds, TwoBody::Bonds));
    }

    if let Some(angles) = config.get("angles") {
        let angles = try!(angles.as_slice().ok_or(
            Error::from("The 'angles' section must be an array")
        ));
        try!(read_angles(system, angles));
    }

    if let Some(dihedrals) = config.get("dihedrals") {
        let dihedrals = try!(dihedrals.as_slice().ok_or(
            Error::from("The 'dihedrals' section must be an array")
        ));
        try!(read_dihedrals(system, dihedrals));
    }

    if let Some(coulomb) = config.get("coulomb") {
        let coulomb = try!(coulomb.as_table().ok_or(
            Error::from("The 'coulomb' section must be a table")
        ));
        try!(read_coulomb(system, coulomb));
    }

    if let Some(charges) = config.get("charges") {
        let charges = try!(charges.as_table().ok_or(
            Error::from("The 'charges' section must be a table")
        ));
        try!(set_charges(system, charges));
    }

    Ok(())
}

fn validate(config: &Table) -> Result<()> {
    let input = try!(config.get("input").ok_or(
        Error::from("Missing 'input' table")
    ));

    let version = try!(input.lookup("potentials.version").ok_or(
        Error::from("Missing 'potentials.version' key in 'input' table")
    ));

    let version = try!(version.as_integer().ok_or(
        Error::from("'input.potentials.version' must be an integer")
    ));

    if version != 1 {
        return Err(Error::from(
            format!("Only version 1 of input can be read, got {}", version)
        ))
    }

    Ok(())
}

fn read_restriction(config: &Table) -> Result<Option<PairRestriction>> {
    let restriction = match config.get("restriction") {
        Some(restriction) => restriction,
        None => {return Ok(None)}
    };

    match restriction.clone() {
        Value::String(name) => {
            match &*name {
                "none" => Ok(Some(PairRestriction::None)),
                "intramolecular" | "IntraMolecular" | "intra-molecular"
                    => Ok(Some(PairRestriction::IntraMolecular)),
                "intermolecular" | "InterMolecular" | "inter-molecular"
                    => Ok(Some(PairRestriction::InterMolecular)),
                "exclude12" => Ok(Some(PairRestriction::Exclude12)),
                "exclude13" => Ok(Some(PairRestriction::Exclude13)),
                "exclude14" => Ok(Some(PairRestriction::Exclude14)),
                "scale14" => Err(
                    Error::from("'scale14' restriction must be a table")
                ),
                other => Err(
                    Error::from(format!("Unknown restriction '{}'", other))
                ),
            }
        },
        Value::Table(ref restriction) => {
            if restriction.keys().len() != 1 || restriction.get("scale14").is_none() {
                return Err(Error::from("Restriction table must be 'scale14'"));
            }
            let scale = try!(restriction["scale14"].as_float().ok_or(
                Error::from("'scale14' parameter must be a float")
            ));
            Ok(Some(PairRestriction::Scale14{scaling: scale}))
        }
        _ => Err(Error::from("Restriction must be a table or a string"))
    }
}

fn toml_error_to_string(parser: &Parser) -> String {
    let nerrors = parser.errors.len();
    assert!(nerrors > 0);

    let errors = parser.errors.iter().map(|error|{
        let (line, _) = parser.to_linecol(error.lo);
        format!("{} at line {}", error.desc, line + 1)
    }).collect::<Vec<_>>().join("\n    ");

    let plural = if nerrors != 1 {"s"} else {""};
    return format!("TOML parsing error{}: {}", plural, errors);
}

#[cfg(test)]
mod tests {
    use system::System;
    use input::read_interactions;
    use input::interactions::testing::bad_interactions;

    #[test]
    fn bad_input() {
        for path in bad_interactions("generic") {
            let mut system = System::new();
            assert!(read_interactions(&mut system, path).is_err());
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std;
use std::fmt;
use std::iter::{Iterator, Zip};
use std::mem;
use std::mem::ManuallyDrop;
use std::ptr;
use std::slice;
use std::sync::Arc;

use node;
use node::Node;
use str_utils::nearest_internal_grapheme_boundary;
use text_info::TextInfo;

const MAX_LEN: usize = node::MAX_CHILDREN;

pub(crate) struct ChildArray {
    nodes: ManuallyDrop<[Arc<Node>; MAX_LEN]>,
    info: [TextInfo; MAX_LEN],
    len: u8,
}

impl ChildArray {
    /// Creates a new empty array.
    pub fn new() -> ChildArray {
        ChildArray {
            nodes: ManuallyDrop::new(unsafe { std::mem::uninitialized() }),
            info: unsafe { std::mem::uninitialized() },
            len: 0,
        }
    }

    /// Current length of the array.
    pub fn len(&self) -> usize {
        self.len as usize
    }

    /// Returns whether the array is full or not.
    pub fn is_full(&self) -> bool {
        (self.len as usize) == MAX_LEN
    }

    /// Returns a slice to the nodes array.
    pub fn nodes(&self) -> &[Arc<Node>] {
        &self.nodes[..(self.len as usize)]
    }

    /// Returns a mutable slice to the nodes array.
    pub fn nodes_mut(&mut self) -> &mut [Arc<Node>] {
        &mut self.nodes[..(self.len as usize)]
    }

    /// Returns a slice to the info array.
    pub fn info(&self) -> &[TextInfo] {
        &self.info[..(self.len as usize)]
    }

    /// Returns a mutable slice to the info array.
    pub fn info_mut(&mut self) -> &mut [TextInfo] {
        &mut self.info[..(self.len as usize)]
    }

    /// Returns mutable slices to both the nodes and info arrays.
    pub fn info_and_nodes_mut(&mut self) -> (&mut [TextInfo], &mut [Arc<Node>]) {
        (
            &mut self.info[..(self.len as usize)],
            &mut self.nodes[..(self.len as usize)],
        )
    }

    /// Pushes an item into the end of the array.
    ///
    /// Increases length by one.  Panics if already full.
    pub fn push(&mut self, item: (TextInfo, Arc<Node>)) {
        assert!(self.len() < MAX_LEN);
        self.info[self.len as usize] = item.0;
        mem::forget(mem::replace(&mut self.nodes[self.len as usize], item.1));
        self.len += 1;
    }

    /// Pushes an element onto the end of the array, and then splits it in half,
    /// returning the right half.
    ///
    /// This works even when the array is full.
    pub fn push_split(&mut self, new_child: (TextInfo, Arc<Node>)) -> ChildArray {
        let r_count = (self.len() + 1) / 2;
        let l_count = (self.len() + 1) - r_count;

        let mut right = self.split_off(l_count);
        right.push(new_child);
        right
    }

    /// Attempts to merge two nodes, and if it's too much data to merge
    /// equi-distributes it between the two.
    ///
    /// Returns:
    ///
    /// - True: merge was successful.
    /// - False: merge failed, equidistributed instead.
    pub fn merge_distribute(&mut self, idx1: usize, idx2: usize) -> bool {
        assert!(idx1 < idx2);
        assert!(idx2 < self.len());
        let remove_right = {
            let ((_, mut node1), (_, mut node2)) = self.get_two_mut(idx1, idx2);
            let node1 = Arc::make_mut(&mut node1);
            let node2 = Arc::make_mut(&mut node2);
            match node1 {
                &mut Node::Leaf(ref mut text1) => {
                    if let &mut Node::Leaf(ref mut text2) = node2 {
                        text1.push_str(text2);

                        if text1.len() <= node::MAX_BYTES {
                            true
                        } else {
                            let split_pos = {
                                let pos = text1.len() - (text1.len() / 2);
                                nearest_internal_grapheme_boundary(&text1, pos)
                            };
                            *text2 = text1.split_off(split_pos);
                            if text2.len() > 0 {
                                text1.shrink_to_fit();
                                false
                            } else {
                                true
                            }
                        }
                    } else {
                        panic!("Siblings have different node types");
                    }
                }

                &mut Node::Internal(ref mut children1) => {
                    if let &mut Node::Internal(ref mut children2) = node2 {
                        if (children1.len() + children2.len()) < MAX_LEN {
                            for _ in 0..children2.len() {
                                children1.push(children2.remove(0));
                            }
                            true
                        } else {
                            let r_target_len = (children1.len() + children2.len()) / 2;
                            while children2.len() < r_target_len {
                                children2.insert(0, children1.pop());
                            }
                            while children2.len() > r_target_len {
                                children1.push(children2.remove(0));
                            }
                            false
                        }
                    } else {
                        panic!("Siblings have different node types");
                    }
                }
            }
        };

        if remove_right {
            self.remove(idx2);
            self.info[idx1] = self.nodes[idx1].text_info();
            return true;
        } else {
            self.info[idx1] = self.nodes[idx1].text_info();
            self.info[idx2] = self.nodes[idx2].text_info();
            return false;
        }
    }

    /// Pops an item off the end of the array and returns it.
    ///
    /// Decreases length by one.  Panics if already empty.
    pub fn pop(&mut self) -> (TextInfo, Arc<Node>) {
        assert!(self.len() > 0);
        self.len -= 1;
        let item = (self.info[self.len as usize], unsafe {
            ptr::read(&self.nodes[self.len as usize])
        });
        item
    }

    /// Inserts an item into the the array at the given index.
    ///
    /// Increases length by one.  Panics if already full.  Preserves ordering
    /// of the other items.
    pub fn insert(&mut self, idx: usize, item: (TextInfo, Arc<Node>)) {
        assert!(idx <= self.len());
        assert!(self.len() < MAX_LEN);

        let len = self.len as usize;
        unsafe {
            ptr::copy(
                self.nodes.as_ptr().offset(idx as isize),
                self.nodes.as_mut_ptr().offset((idx + 1) as isize),
                len - idx,
            );
            ptr::copy(
                self.info.as_ptr().offset(idx as isize),
                self.info.as_mut_ptr().offset((idx + 1) as isize),
                len - idx,
            );
        }

        self.info[idx] = item.0;
        mem::forget(mem::replace(&mut self.nodes[idx], item.1));

        self.len += 1;
    }

    /// Inserts an element into a the array, and then splits it in half, returning
    /// the right half.
    ///
    /// This works even when the array is full.
    pub fn insert_split(&mut self, idx: usize, item: (TextInfo, Arc<Node>)) -> ChildArray {
        assert!(self.len() > 0);
        assert!(idx <= self.len());
        let extra = if idx < self.len() {
            let extra = self.pop();
            self.insert(idx, item);
            extra
        } else {
            item
        };

        self.push_split(extra)
    }

    /// Removes the item at the given index from the the array.
    ///
    /// Decreases length by one.  Preserves ordering of the other items.
    pub fn remove(&mut self, idx: usize) -> (TextInfo, Arc<Node>) {
        assert!(self.len() > 0);
        assert!(idx < self.len());

        let item = (self.info[idx], unsafe { ptr::read(&self.nodes[idx]) });

        let len = self.len as usize;
        unsafe {
            ptr::copy(
                self.nodes.as_ptr().offset(idx as isize + 1),
                self.nodes.as_mut_ptr().offset(idx as isize),
                len - idx - 1,
            );
            ptr::copy(
                self.info.as_ptr().offset(idx as isize + 1),
                self.info.as_mut_ptr().offset(idx as isize),
                len - idx - 1,
            );
        }

        self.len -= 1;
        return item;
    }

    /// Splits the array in two at `idx`, returning the right part of the split.
    ///
    /// TODO: implement this more efficiently.
    pub fn split_off(&mut self, idx: usize) -> ChildArray {
        assert!(idx <= self.len());

        let mut other = ChildArray::new();
        let count = self.len() - idx;
        for _ in 0..count {
            other.push(self.remove(idx));
        }

        assert!(self.len() <= self.nodes.len());
        assert!(other.len() <= self.nodes.len());
        other
    }

    /// Gets references to the nth item's node and info.
    pub fn i(&self, n: usize) -> (&TextInfo, &Arc<Node>) {
        assert!(n < self.len());
        (
            &self.info[self.len as usize],
            &self.nodes[self.len as usize],
        )
    }

    /// Gets mut references to the nth item's node and info.
    pub fn i_mut(&mut self, n: usize) -> (&mut TextInfo, &mut Arc<Node>) {
        assert!(n < self.len());
        (
            &mut self.info[self.len as usize],
            &mut self.nodes[self.len as usize],
        )
    }

    /// Fetches two children simultaneously, returning mutable references
    /// to their info and nodes.
    ///
    /// `idx1` must be less than `idx2`.
    pub fn get_two_mut(
        &mut self,
        idx1: usize,
        idx2: usize,
    ) -> ((&mut TextInfo, &mut Arc<Node>), (&mut TextInfo, &mut Arc<Node>)) {
        assert!(idx1 < idx2);
        assert!(idx2 < self.len());

        let (info1, info2) = self.info.split_at_mut(idx1 + 1);
        let (nodes1, nodes2) = self.nodes.split_at_mut(idx1 + 1);

        ((info1.last_mut().unwrap(), nodes1.last_mut().unwrap()), (
            &mut info2[idx2 - idx1],
            &mut nodes2[idx2 - idx1],
        ))
    }

    /// Creates an iterator over the array's items.
    pub fn iter(&self) -> Zip<slice::Iter<TextInfo>, slice::Iter<Arc<Node>>> {
        Iterator::zip(
            (&self.info[..(self.len as usize)]).iter(),
            (&self.nodes[..(self.len as usize)]).iter(),
        )
    }

    /// Creates an iterator over the array's items.
    pub fn iter_mut(&mut self) -> Zip<slice::IterMut<TextInfo>, slice::IterMut<Arc<Node>>> {
        Iterator::zip(
            (&mut self.info[..(self.len as usize)]).iter_mut(),
            (&mut self.nodes[..(self.len as usize)]).iter_mut(),
        )
    }

    pub fn combined_info(&self) -> TextInfo {
        self.info[..self.len()].iter().fold(
            TextInfo::new(),
            |a, b| a.combine(b),
        )
    }

    pub fn search_combine_info<F: Fn(&TextInfo) -> bool>(&self, pred: F) -> (usize, TextInfo) {
        let mut accum = TextInfo::new();
        for (idx, inf) in self.info[..self.len()].iter().enumerate() {
            if pred(&accum.combine(inf)) {
                return (idx, accum);
            } else {
                accum = accum.combine(inf);
            }
        }
        panic!("Predicate is mal-formed and never evaluated true.")
    }
}

impl fmt::Debug for ChildArray {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ChildArray")
            .field("nodes", &&self.nodes[0..self.len()])
            .field("info", &&self.info[0..self.len()])
            .field("len", &self.len)
            .finish()
    }
}

impl Drop for ChildArray {
    fn drop(&mut self) {
        for node in &mut self.nodes[..self.len as usize] {
            let mptr: *mut Arc<Node> = node; // Make sure we have the right dereference
            unsafe { ptr::drop_in_place(mptr) };
        }
    }
}

impl Clone for ChildArray {
    fn clone(&self) -> ChildArray {
        let mut clone_array = ChildArray::new();

        // Copy nodes... carefully.
        for (clone_arc, arc) in Iterator::zip(
            clone_array.nodes[..self.len()].iter_mut(),
            self.nodes[..self.len()].iter(),
        )
        {
            mem::forget(mem::replace(clone_arc, arc.clone()));
        }

        // Copy TextInfo
        for (clone_info, info) in
            Iterator::zip(
                clone_array.info[..self.len()].iter_mut(),
                self.info[..self.len()].iter(),
            )
        {
            *clone_info = *info;
        }

        // Set length
        clone_array.len = self.len;

        // Some sanity checks for debug builds
        #[cfg(debug_assertions)]
        {
            for (a, b) in Iterator::zip(clone_array.iter(), self.iter()) {
                assert_eq!(a.0, b.0);
                assert!(Arc::ptr_eq(a.1, b.1));
            }
        }

        clone_array
    }
}
<commit_msg>Fixed bug in ChildArray::get_mut_two().<commit_after>#![allow(dead_code)]

use std;
use std::fmt;
use std::iter::{Iterator, Zip};
use std::mem;
use std::mem::ManuallyDrop;
use std::ptr;
use std::slice;
use std::sync::Arc;

use node;
use node::Node;
use str_utils::nearest_internal_grapheme_boundary;
use text_info::TextInfo;

const MAX_LEN: usize = node::MAX_CHILDREN;

pub(crate) struct ChildArray {
    nodes: ManuallyDrop<[Arc<Node>; MAX_LEN]>,
    info: [TextInfo; MAX_LEN],
    len: u8,
}

impl ChildArray {
    /// Creates a new empty array.
    pub fn new() -> ChildArray {
        ChildArray {
            nodes: ManuallyDrop::new(unsafe { std::mem::uninitialized() }),
            info: unsafe { std::mem::uninitialized() },
            len: 0,
        }
    }

    /// Current length of the array.
    pub fn len(&self) -> usize {
        self.len as usize
    }

    /// Returns whether the array is full or not.
    pub fn is_full(&self) -> bool {
        (self.len as usize) == MAX_LEN
    }

    /// Returns a slice to the nodes array.
    pub fn nodes(&self) -> &[Arc<Node>] {
        &self.nodes[..(self.len as usize)]
    }

    /// Returns a mutable slice to the nodes array.
    pub fn nodes_mut(&mut self) -> &mut [Arc<Node>] {
        &mut self.nodes[..(self.len as usize)]
    }

    /// Returns a slice to the info array.
    pub fn info(&self) -> &[TextInfo] {
        &self.info[..(self.len as usize)]
    }

    /// Returns a mutable slice to the info array.
    pub fn info_mut(&mut self) -> &mut [TextInfo] {
        &mut self.info[..(self.len as usize)]
    }

    /// Returns mutable slices to both the nodes and info arrays.
    pub fn info_and_nodes_mut(&mut self) -> (&mut [TextInfo], &mut [Arc<Node>]) {
        (
            &mut self.info[..(self.len as usize)],
            &mut self.nodes[..(self.len as usize)],
        )
    }

    /// Pushes an item into the end of the array.
    ///
    /// Increases length by one.  Panics if already full.
    pub fn push(&mut self, item: (TextInfo, Arc<Node>)) {
        assert!(self.len() < MAX_LEN);
        self.info[self.len as usize] = item.0;
        mem::forget(mem::replace(&mut self.nodes[self.len as usize], item.1));
        self.len += 1;
    }

    /// Pushes an element onto the end of the array, and then splits it in half,
    /// returning the right half.
    ///
    /// This works even when the array is full.
    pub fn push_split(&mut self, new_child: (TextInfo, Arc<Node>)) -> ChildArray {
        let r_count = (self.len() + 1) / 2;
        let l_count = (self.len() + 1) - r_count;

        let mut right = self.split_off(l_count);
        right.push(new_child);
        right
    }

    /// Attempts to merge two nodes, and if it's too much data to merge
    /// equi-distributes it between the two.
    ///
    /// Returns:
    ///
    /// - True: merge was successful.
    /// - False: merge failed, equidistributed instead.
    pub fn merge_distribute(&mut self, idx1: usize, idx2: usize) -> bool {
        assert!(idx1 < idx2);
        assert!(idx2 < self.len());
        let remove_right = {
            let ((_, node1), (_, node2)) = self.get_two_mut(idx1, idx2);
            let node1 = Arc::make_mut(node1);
            let node2 = Arc::make_mut(node2);
            match node1 {
                &mut Node::Leaf(ref mut text1) => {
                    if let &mut Node::Leaf(ref mut text2) = node2 {
                        text1.push_str(text2);

                        if text1.len() <= node::MAX_BYTES {
                            true
                        } else {
                            let split_pos = {
                                let pos = text1.len() - (text1.len() / 2);
                                nearest_internal_grapheme_boundary(&text1, pos)
                            };
                            *text2 = text1.split_off(split_pos);
                            if text2.len() > 0 {
                                text1.shrink_to_fit();
                                false
                            } else {
                                true
                            }
                        }
                    } else {
                        panic!("Siblings have different node types");
                    }
                }

                &mut Node::Internal(ref mut children1) => {
                    if let &mut Node::Internal(ref mut children2) = node2 {
                        if (children1.len() + children2.len()) < MAX_LEN {
                            for _ in 0..children2.len() {
                                children1.push(children2.remove(0));
                            }
                            true
                        } else {
                            let r_target_len = (children1.len() + children2.len()) / 2;
                            while children2.len() < r_target_len {
                                children2.insert(0, children1.pop());
                            }
                            while children2.len() > r_target_len {
                                children1.push(children2.remove(0));
                            }
                            false
                        }
                    } else {
                        panic!("Siblings have different node types");
                    }
                }
            }
        };

        if remove_right {
            self.remove(idx2);
            self.info[idx1] = self.nodes[idx1].text_info();
            return true;
        } else {
            self.info[idx1] = self.nodes[idx1].text_info();
            self.info[idx2] = self.nodes[idx2].text_info();
            return false;
        }
    }

    /// Pops an item off the end of the array and returns it.
    ///
    /// Decreases length by one.  Panics if already empty.
    pub fn pop(&mut self) -> (TextInfo, Arc<Node>) {
        assert!(self.len() > 0);
        self.len -= 1;
        let item = (self.info[self.len as usize], unsafe {
            ptr::read(&self.nodes[self.len as usize])
        });
        item
    }

    /// Inserts an item into the the array at the given index.
    ///
    /// Increases length by one.  Panics if already full.  Preserves ordering
    /// of the other items.
    pub fn insert(&mut self, idx: usize, item: (TextInfo, Arc<Node>)) {
        assert!(idx <= self.len());
        assert!(self.len() < MAX_LEN);

        let len = self.len as usize;
        unsafe {
            ptr::copy(
                self.nodes.as_ptr().offset(idx as isize),
                self.nodes.as_mut_ptr().offset((idx + 1) as isize),
                len - idx,
            );
            ptr::copy(
                self.info.as_ptr().offset(idx as isize),
                self.info.as_mut_ptr().offset((idx + 1) as isize),
                len - idx,
            );
        }

        self.info[idx] = item.0;
        mem::forget(mem::replace(&mut self.nodes[idx], item.1));

        self.len += 1;
    }

    /// Inserts an element into a the array, and then splits it in half, returning
    /// the right half.
    ///
    /// This works even when the array is full.
    pub fn insert_split(&mut self, idx: usize, item: (TextInfo, Arc<Node>)) -> ChildArray {
        assert!(self.len() > 0);
        assert!(idx <= self.len());
        let extra = if idx < self.len() {
            let extra = self.pop();
            self.insert(idx, item);
            extra
        } else {
            item
        };

        self.push_split(extra)
    }

    /// Removes the item at the given index from the the array.
    ///
    /// Decreases length by one.  Preserves ordering of the other items.
    pub fn remove(&mut self, idx: usize) -> (TextInfo, Arc<Node>) {
        assert!(self.len() > 0);
        assert!(idx < self.len());

        let item = (self.info[idx], unsafe { ptr::read(&self.nodes[idx]) });

        let len = self.len as usize;
        unsafe {
            ptr::copy(
                self.nodes.as_ptr().offset(idx as isize + 1),
                self.nodes.as_mut_ptr().offset(idx as isize),
                len - idx - 1,
            );
            ptr::copy(
                self.info.as_ptr().offset(idx as isize + 1),
                self.info.as_mut_ptr().offset(idx as isize),
                len - idx - 1,
            );
        }

        self.len -= 1;
        return item;
    }

    /// Splits the array in two at `idx`, returning the right part of the split.
    ///
    /// TODO: implement this more efficiently.
    pub fn split_off(&mut self, idx: usize) -> ChildArray {
        assert!(idx <= self.len());

        let mut other = ChildArray::new();
        let count = self.len() - idx;
        for _ in 0..count {
            other.push(self.remove(idx));
        }

        other
    }

    /// Gets references to the nth item's node and info.
    pub fn i(&self, n: usize) -> (&TextInfo, &Arc<Node>) {
        assert!(n < self.len());
        (
            &self.info[self.len as usize],
            &self.nodes[self.len as usize],
        )
    }

    /// Gets mut references to the nth item's node and info.
    pub fn i_mut(&mut self, n: usize) -> (&mut TextInfo, &mut Arc<Node>) {
        assert!(n < self.len());
        (
            &mut self.info[self.len as usize],
            &mut self.nodes[self.len as usize],
        )
    }

    /// Fetches two children simultaneously, returning mutable references
    /// to their info and nodes.
    ///
    /// `idx1` must be less than `idx2`.
    pub fn get_two_mut(
        &mut self,
        idx1: usize,
        idx2: usize,
    ) -> ((&mut TextInfo, &mut Arc<Node>), (&mut TextInfo, &mut Arc<Node>)) {
        assert!(idx1 < idx2);
        assert!(idx2 < self.len());

        let split_idx = idx1 + 1;
        let (info1, info2) = self.info.split_at_mut(split_idx);
        let (nodes1, nodes2) = self.nodes.split_at_mut(split_idx);

        ((&mut info1[idx1], &mut nodes1[idx1]), (
            &mut info2
                [idx2 - split_idx],
            &mut nodes2
                [idx2 - split_idx],
        ))
    }

    /// Creates an iterator over the array's items.
    pub fn iter(&self) -> Zip<slice::Iter<TextInfo>, slice::Iter<Arc<Node>>> {
        Iterator::zip(
            (&self.info[..(self.len as usize)]).iter(),
            (&self.nodes[..(self.len as usize)]).iter(),
        )
    }

    /// Creates an iterator over the array's items.
    pub fn iter_mut(&mut self) -> Zip<slice::IterMut<TextInfo>, slice::IterMut<Arc<Node>>> {
        Iterator::zip(
            (&mut self.info[..(self.len as usize)]).iter_mut(),
            (&mut self.nodes[..(self.len as usize)]).iter_mut(),
        )
    }

    pub fn combined_info(&self) -> TextInfo {
        self.info[..self.len()].iter().fold(
            TextInfo::new(),
            |a, b| a.combine(b),
        )
    }

    pub fn search_combine_info<F: Fn(&TextInfo) -> bool>(&self, pred: F) -> (usize, TextInfo) {
        let mut accum = TextInfo::new();
        for (idx, inf) in self.info[..self.len()].iter().enumerate() {
            if pred(&accum.combine(inf)) {
                return (idx, accum);
            } else {
                accum = accum.combine(inf);
            }
        }
        panic!("Predicate is mal-formed and never evaluated true.")
    }
}

impl fmt::Debug for ChildArray {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ChildArray")
            .field("nodes", &&self.nodes[0..self.len()])
            .field("info", &&self.info[0..self.len()])
            .field("len", &self.len)
            .finish()
    }
}

impl Drop for ChildArray {
    fn drop(&mut self) {
        for node in &mut self.nodes[..self.len as usize] {
            let mptr: *mut Arc<Node> = node; // Make sure we have the right dereference
            unsafe { ptr::drop_in_place(mptr) };
        }
    }
}

impl Clone for ChildArray {
    fn clone(&self) -> ChildArray {
        let mut clone_array = ChildArray::new();

        // Copy nodes... carefully.
        for (clone_arc, arc) in Iterator::zip(
            clone_array.nodes[..self.len()].iter_mut(),
            self.nodes[..self.len()].iter(),
        )
        {
            mem::forget(mem::replace(clone_arc, arc.clone()));
        }

        // Copy TextInfo
        for (clone_info, info) in
            Iterator::zip(
                clone_array.info[..self.len()].iter_mut(),
                self.info[..self.len()].iter(),
            )
        {
            *clone_info = *info;
        }

        // Set length
        clone_array.len = self.len;

        // Some sanity checks for debug builds
        #[cfg(debug_assertions)]
        {
            for (a, b) in Iterator::zip(clone_array.iter(), self.iter()) {
                assert_eq!(a.0, b.0);
                assert!(Arc::ptr_eq(a.1, b.1));
            }
        }

        clone_array
    }
}
<|endoftext|>


<commit_before>#![crate_name = "uu_cksum"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#[macro_use]
extern crate uucore;

use std::fs::File;
use std::io::{self, stdin, BufReader, Read};
#[cfg(not(windows))]
use std::mem;
use std::path::Path;

include!(concat!(env!("OUT_DIR"), "/crc_table.rs"));

static SYNTAX: &str = "[OPTIONS] [FILE]...";
static SUMMARY: &str = "Print CRC and size for each file";
static LONG_HELP: &str = "";

#[inline]
fn crc_update(crc: u32, input: u8) -> u32 {
    (crc << 8) ^ CRC_TABLE[((crc >> 24) as usize ^ input as usize) & 0xFF]
}

#[inline]
fn crc_final(mut crc: u32, mut length: usize) -> u32 {
    while length != 0 {
        crc = crc_update(crc, length as u8);
        length >>= 8;
    }

    !crc
}

#[cfg(windows)]
fn init_byte_array() -> Vec<u8> {
    vec![0; 1024 * 1024]
}

#[cfg(not(windows))]
fn init_byte_array() -> [u8; 1024 * 1024] {
    unsafe { mem::uninitialized() }
}

#[inline]
fn cksum(fname: &str) -> io::Result<(u32, usize)> {
    let mut crc = 0u32;
    let mut size = 0usize;

    let file;
    let mut rd: Box<dyn Read> = match fname {
        "-" => Box::new(stdin()),
        _ => {
            file = File::open(&Path::new(fname))?;
            Box::new(BufReader::new(file))
        }
    };

    let mut bytes = init_byte_array();
    loop {
        match rd.read(&mut bytes) {
            Ok(num_bytes) => {
                if num_bytes == 0 {
                    return Ok((crc_final(crc, size), size));
                }
                for &b in bytes[..num_bytes].iter() {
                    crc = crc_update(crc, b);
                }
                size += num_bytes;
            }
            Err(err) => return Err(err),
        }
    }
    //Ok((0 as u32,0 as usize))
}

pub fn uumain(args: Vec<String>) -> i32 {
    let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP).parse(args);

    let files = matches.free;

    if files.is_empty() {
        match cksum("-") {
            Ok((crc, size)) => println!("{} {}", crc, size),
            Err(err) => {
                show_error!("{}", err);
                return 2;
            }
        }
        return 0;
    }

    let mut exit_code = 0;
    for fname in &files {
        match cksum(fname.as_ref()) {
            Ok((crc, size)) => println!("{} {} {}", crc, size, fname),
            Err(err) => {
                show_error!("'{}' {}", fname, err);
                exit_code = 2;
            }
        }
    }

    exit_code
}
<commit_msg>refactor ~ remove unneeded mem::uninitialized() code<commit_after>#![crate_name = "uu_cksum"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#[macro_use]
extern crate uucore;

use std::fs::File;
use std::io::{self, stdin, BufReader, Read};
use std::path::Path;

include!(concat!(env!("OUT_DIR"), "/crc_table.rs"));

static SYNTAX: &str = "[OPTIONS] [FILE]...";
static SUMMARY: &str = "Print CRC and size for each file";
static LONG_HELP: &str = "";

#[inline]
fn crc_update(crc: u32, input: u8) -> u32 {
    (crc << 8) ^ CRC_TABLE[((crc >> 24) as usize ^ input as usize) & 0xFF]
}

#[inline]
fn crc_final(mut crc: u32, mut length: usize) -> u32 {
    while length != 0 {
        crc = crc_update(crc, length as u8);
        length >>= 8;
    }

    !crc
}

fn init_byte_array() -> Vec<u8> {
    vec![0; 1024 * 1024]
}

#[inline]
fn cksum(fname: &str) -> io::Result<(u32, usize)> {
    let mut crc = 0u32;
    let mut size = 0usize;

    let file;
    let mut rd: Box<dyn Read> = match fname {
        "-" => Box::new(stdin()),
        _ => {
            file = File::open(&Path::new(fname))?;
            Box::new(BufReader::new(file))
        }
    };

    let mut bytes = init_byte_array();
    loop {
        match rd.read(&mut bytes) {
            Ok(num_bytes) => {
                if num_bytes == 0 {
                    return Ok((crc_final(crc, size), size));
                }
                for &b in bytes[..num_bytes].iter() {
                    crc = crc_update(crc, b);
                }
                size += num_bytes;
            }
            Err(err) => return Err(err),
        }
    }
    //Ok((0 as u32,0 as usize))
}

pub fn uumain(args: Vec<String>) -> i32 {
    let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP).parse(args);

    let files = matches.free;

    if files.is_empty() {
        match cksum("-") {
            Ok((crc, size)) => println!("{} {}", crc, size),
            Err(err) => {
                show_error!("{}", err);
                return 2;
            }
        }
        return 0;
    }

    let mut exit_code = 0;
    for fname in &files {
        match cksum(fname.as_ref()) {
            Ok((crc, size)) => println!("{} {} {}", crc, size, fname),
            Err(err) => {
                show_error!("'{}' {}", fname, err);
                exit_code = 2;
            }
        }
    }

    exit_code
}
<|endoftext|>


<commit_before>#![cfg(feature = "serde")]

extern crate serde;

use EnumMap;
use Internal;

use self::serde::ser::{Serialize, Serializer, SerializeMap};
use self::serde::de::{self, Deserialize, Deserializer, Error, MapAccess};

use core::fmt;
use core::marker::PhantomData;

/// Requires crate feature `"serde"`
impl<K: Internal<V> + Serialize, V: Serialize> Serialize for EnumMap<K, V> {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        let mut map = serializer.serialize_map(Some(self.len()))?;
        for (key, value) in self {
            map.serialize_entry(&key, value)?;
        }
        map.end()
    }
}

/// Requires crate feature `"serde"`
impl<'de, K, V> Deserialize<'de> for EnumMap<K, V>
where
    K: Internal<V>
        + Internal<Option<V>>
        + Deserialize<'de>,
    V: Deserialize<'de>,
{
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        deserializer.deserialize_map(Visitor(PhantomData))
    }
}

struct Visitor<K, V>(PhantomData<(K, V)>);

impl<'de, K, V> de::Visitor<'de> for Visitor<K, V>
where
    K: Internal<V>
        + Internal<Option<V>>
        + Deserialize<'de>,
    V: Deserialize<'de>,
{
    type Value = EnumMap<K, V>;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "a map")
    }

    fn visit_map<M: MapAccess<'de>>(self, mut access: M) -> Result<Self::Value, M::Error> {
        let mut entries = EnumMap::new();
        while let Some((key, value)) = access.next_entry()? {
            entries[key] = Some(value);
        }
        for value in entries.values() {
            value.ok_or_else(|| M::Error::custom("key not specified"))?;
        }
        Ok(enum_map! { key => entries[key].take().unwrap() })
    }
}
<commit_msg>Revert "Can use EnumMap::new instead of enum_map! macro in visit_map"<commit_after>#![cfg(feature = "serde")]

extern crate serde;

use EnumMap;
use Internal;

use self::serde::ser::{Serialize, Serializer, SerializeMap};
use self::serde::de::{self, Deserialize, Deserializer, Error, MapAccess};

use core::fmt;
use core::marker::PhantomData;

/// Requires crate feature `"serde"`
impl<K: Internal<V> + Serialize, V: Serialize> Serialize for EnumMap<K, V> {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        let mut map = serializer.serialize_map(Some(self.len()))?;
        for (key, value) in self {
            map.serialize_entry(&key, value)?;
        }
        map.end()
    }
}

/// Requires crate feature `"serde"`
impl<'de, K, V> Deserialize<'de> for EnumMap<K, V>
where
    K: Internal<V>
        + Internal<Option<V>>
        + Deserialize<'de>,
    V: Deserialize<'de>,
{
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        deserializer.deserialize_map(Visitor(PhantomData))
    }
}

struct Visitor<K, V>(PhantomData<(K, V)>);

impl<'de, K, V> de::Visitor<'de> for Visitor<K, V>
where
    K: Internal<V>
        + Internal<Option<V>>
        + Deserialize<'de>,
    V: Deserialize<'de>,
{
    type Value = EnumMap<K, V>;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "a map")
    }

    fn visit_map<M: MapAccess<'de>>(self, mut access: M) -> Result<Self::Value, M::Error> {
        let mut entries = enum_map! { _ => None };
        while let Some((key, value)) = access.next_entry()? {
            entries[key] = Some(value);
        }
        for value in entries.values() {
            value.ok_or_else(|| M::Error::custom("key not specified"))?;
        }
        Ok(enum_map! { key => entries[key].take().unwrap() })
    }
}
<|endoftext|>


<commit_before>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use std::fmt;
use std::hash::{Hash, Hasher};
use std::ptr;
use std::rc::Rc;
use std::str;

use super::flat_pairs::{self, FlatPairs};
use super::pair::{self, Pair};
use super::queueable_token::QueueableToken;
use super::tokens::{self, Tokens};
use RuleType;

/// A `struct` containing `Pairs`. It is created by [`pest::state`](../fn.state.html) and
/// [`Pair::into_inner`](struct.Pair.html#method.into_inner).
#[derive(Clone)]
pub struct Pairs<'i, R> {
    queue: Rc<Vec<QueueableToken<R>>>,
    input: &'i [u8],
    start: usize,
    end: usize
}

pub fn new<R: RuleType>(
    queue: Rc<Vec<QueueableToken<R>>>,
    input: &[u8],
    start: usize,
    end: usize
) -> Pairs<R> {
    Pairs {
        queue,
        input,
        start,
        end
    }
}

impl<'i, R: RuleType> Pairs<'i, R> {
    /// Captures a slice from the `&str` defined by the starting position of the first token `Pair`
    /// and the ending position of the last token `Pair` of the `Pairs`. This also captures
    /// the input between those two token `Pair`s.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::rc::Rc;
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {
    ///     a,
    ///     b
    /// }
    ///
    /// let input = "a b";
    /// let pairs = pest::state(input, |state| {
    ///     // generating Token pairs with Rule::a and Rule::b ...
    /// #     state.rule(Rule::a, |s| s.match_string("a")).and_then(|s| s.skip(1))
    /// #         .and_then(|s| s.rule(Rule::b, |s| s.match_string("b")))
    /// }).unwrap();
    ///
    /// assert_eq!(pairs.as_str(), "a b");
    /// ```
    #[inline]
    pub fn as_str(&self) -> &'i str {
        let start = self.pos(self.start);
        let end = self.pos(self.end - 1);

        // Generated positions always come from Positions and are UTF-8 borders.
        unsafe { str::from_utf8_unchecked(&self.input[start..end]) }
    }

    /// Captures inner token `Pair`s and concatenates resulting `&str`s. This does not capture
    /// the input between token `Pair`s.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::rc::Rc;
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {
    ///     a,
    ///     b
    /// }
    ///
    /// let input = "a b";
    /// let pairs = pest::state(input, |state| {
    ///     // generating Token pairs with Rule::a and Rule::b ...
    /// #     state.rule(Rule::a, |s| s.match_string("a")).and_then(|s| s.skip(1))
    /// #         .and_then(|s| s.rule(Rule::b, |s| s.match_string("b")))
    /// }).unwrap();
    ///
    /// assert_eq!(pairs.concat(), "ab");
    /// ```
    #[inline]
    pub fn concat(&self) -> String {
        self.clone().into_iter().fold(String::new(), |string, pair| string + pair.as_str())
    }

    /// Flattens the `Pairs`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::rc::Rc;
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {
    ///     a,
    ///     b
    /// }
    ///
    /// let input = "";
    /// let pairs = pest::state(input, |state| {
    ///     // generating nested Token pair with Rule::b inside Rule::a
    /// #     state.rule(Rule::a, |state| {
    /// #         state.rule(Rule::b, |s| Ok(s))
    /// #     })
    /// }).unwrap();
    /// let tokens: Vec<_> = pairs.flatten().tokens().collect();
    ///
    /// assert_eq!(tokens.len(), 4);
    /// ```
    #[inline]
    pub fn flatten(self) -> FlatPairs<'i, R> {
        flat_pairs::new(self.queue, self.input, self.start, self.end)
    }

    /// Converts the `Pairs` into a `TokenIterator`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::rc::Rc;
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {
    ///     a
    /// }
    ///
    /// let input = "";
    /// let pairs = pest::state(input, |state| {
    ///     // generating Token pair with Rule::a ...
    /// #     state.rule(Rule::a, |s| Ok(s))
    /// }).unwrap();
    /// let tokens: Vec<_> = pairs.tokens().collect();
    ///
    /// assert_eq!(tokens.len(), 2);
    /// ```
    #[inline]
    pub fn tokens(self) -> Tokens<'i, R> {
        tokens::new(self.queue, self.input, self.start, self.end)
    }

    fn pair(&self) -> usize {
        match self.queue[self.start] {
            QueueableToken::Start {
                end_token_index, ..
            } => end_token_index,
            _ => unreachable!()
        }
    }

    fn pair_from_end(&self) -> usize {
        match self.queue[self.end - 1] {
            QueueableToken::End {
                start_token_index, ..
            } => start_token_index,
            _ => unreachable!()
        }
    }

    fn pos(&self, index: usize) -> usize {
        match self.queue[index] {
            QueueableToken::Start { input_pos, .. } | QueueableToken::End { input_pos, .. } => {
                input_pos
            }
        }
    }
}

impl<'i, R: RuleType> Iterator for Pairs<'i, R> {
    type Item = Pair<'i, R>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.start >= self.end {
            return None;
        }

        let pair = pair::new(Rc::clone(&self.queue), self.input, self.start);

        self.start = self.pair() + 1;

        Some(pair)
    }
}

impl<'i, R: RuleType> DoubleEndedIterator for Pairs<'i, R> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.end <= self.start {
            return None;
        }

        self.end = self.pair_from_end();

        let pair = pair::new(Rc::clone(&self.queue), self.input, self.end);

        Some(pair)
    }
}

impl<'i, R: RuleType> fmt::Debug for Pairs<'i, R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_list().entries(self.clone()).finish()
    }
}

impl<'i, R: RuleType> fmt::Display for Pairs<'i, R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "[{}]",
            self.clone()
                .map(|pair| format!("{}", pair))
                .collect::<Vec<_>>()
                .join(", ")
        )
    }
}

impl<'i, R: PartialEq> PartialEq for Pairs<'i, R> {
    fn eq(&self, other: &Pairs<'i, R>) -> bool {
        Rc::ptr_eq(&self.queue, &other.queue) && ptr::eq(self.input, other.input)
            && self.start == other.start && self.end == other.end
    }
}

impl<'i, R: Eq> Eq for Pairs<'i, R> {}

impl<'i, R: Hash> Hash for Pairs<'i, R> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        (&*self.queue as *const Vec<QueueableToken<R>>).hash(state);
        (self.input as *const [u8]).hash(state);
        self.start.hash(state);
        self.end.hash(state);
    }
}

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

    #[test]
    fn pairs_debug() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();

        assert_eq!(
            format!("{:?}", pairs),
            "[\
                Pair { rule: a, span: Span { str: \"abc\", start: 0, end: 3 }, inner: [\
                    Pair { rule: b, span: Span { str: \"b\", start: 1, end: 2 }, inner: [] }\
                ] }, \
                Pair { rule: c, span: Span { str: \"e\", start: 4, end: 5 }, inner: [] }\
            ]"
        .to_owned()
        );
    }

    #[test]
    fn pairs_display() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();

        assert_eq!(
            format!("{}", pairs),
            "[a(0, 3, [b(1, 2)]), c(4, 5)]".to_owned()
        );
    }

    #[test]
    fn iter_for_pairs() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();
        assert_eq!(
            pairs.map(|p| p.as_rule()).collect::<Vec<Rule>>(),
            vec![Rule::a, Rule::c]
        );
    }

    #[test]
    fn double_ended_iter_for_pairs() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();
        assert_eq!(
            pairs.rev().map(|p| p.as_rule()).collect::<Vec<Rule>>(),
            vec![Rule::c, Rule::a]
        );
    }
}
<commit_msg>Added a couple of tests.<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use std::fmt;
use std::hash::{Hash, Hasher};
use std::ptr;
use std::rc::Rc;
use std::str;

use super::flat_pairs::{self, FlatPairs};
use super::pair::{self, Pair};
use super::queueable_token::QueueableToken;
use super::tokens::{self, Tokens};
use RuleType;

/// A `struct` containing `Pairs`. It is created by [`pest::state`](../fn.state.html) and
/// [`Pair::into_inner`](struct.Pair.html#method.into_inner).
#[derive(Clone)]
pub struct Pairs<'i, R> {
    queue: Rc<Vec<QueueableToken<R>>>,
    input: &'i [u8],
    start: usize,
    end: usize
}

pub fn new<R: RuleType>(
    queue: Rc<Vec<QueueableToken<R>>>,
    input: &[u8],
    start: usize,
    end: usize
) -> Pairs<R> {
    Pairs {
        queue,
        input,
        start,
        end
    }
}

impl<'i, R: RuleType> Pairs<'i, R> {
    /// Captures a slice from the `&str` defined by the starting position of the first token `Pair`
    /// and the ending position of the last token `Pair` of the `Pairs`. This also captures
    /// the input between those two token `Pair`s.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::rc::Rc;
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {
    ///     a,
    ///     b
    /// }
    ///
    /// let input = "a b";
    /// let pairs = pest::state(input, |state| {
    ///     // generating Token pairs with Rule::a and Rule::b ...
    /// #     state.rule(Rule::a, |s| s.match_string("a")).and_then(|s| s.skip(1))
    /// #         .and_then(|s| s.rule(Rule::b, |s| s.match_string("b")))
    /// }).unwrap();
    ///
    /// assert_eq!(pairs.as_str(), "a b");
    /// ```
    #[inline]
    pub fn as_str(&self) -> &'i str {
        let start = self.pos(self.start);
        let end = self.pos(self.end - 1);

        // Generated positions always come from Positions and are UTF-8 borders.
        unsafe { str::from_utf8_unchecked(&self.input[start..end]) }
    }

    /// Captures inner token `Pair`s and concatenates resulting `&str`s. This does not capture
    /// the input between token `Pair`s.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::rc::Rc;
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {
    ///     a,
    ///     b
    /// }
    ///
    /// let input = "a b";
    /// let pairs = pest::state(input, |state| {
    ///     // generating Token pairs with Rule::a and Rule::b ...
    /// #     state.rule(Rule::a, |s| s.match_string("a")).and_then(|s| s.skip(1))
    /// #         .and_then(|s| s.rule(Rule::b, |s| s.match_string("b")))
    /// }).unwrap();
    ///
    /// assert_eq!(pairs.concat(), "ab");
    /// ```
    #[inline]
    pub fn concat(&self) -> String {
        self.clone().into_iter().fold(String::new(), |string, pair| string + pair.as_str())
    }

    /// Flattens the `Pairs`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::rc::Rc;
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {
    ///     a,
    ///     b
    /// }
    ///
    /// let input = "";
    /// let pairs = pest::state(input, |state| {
    ///     // generating nested Token pair with Rule::b inside Rule::a
    /// #     state.rule(Rule::a, |state| {
    /// #         state.rule(Rule::b, |s| Ok(s))
    /// #     })
    /// }).unwrap();
    /// let tokens: Vec<_> = pairs.flatten().tokens().collect();
    ///
    /// assert_eq!(tokens.len(), 4);
    /// ```
    #[inline]
    pub fn flatten(self) -> FlatPairs<'i, R> {
        flat_pairs::new(self.queue, self.input, self.start, self.end)
    }

    /// Converts the `Pairs` into a `TokenIterator`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::rc::Rc;
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {
    ///     a
    /// }
    ///
    /// let input = "";
    /// let pairs = pest::state(input, |state| {
    ///     // generating Token pair with Rule::a ...
    /// #     state.rule(Rule::a, |s| Ok(s))
    /// }).unwrap();
    /// let tokens: Vec<_> = pairs.tokens().collect();
    ///
    /// assert_eq!(tokens.len(), 2);
    /// ```
    #[inline]
    pub fn tokens(self) -> Tokens<'i, R> {
        tokens::new(self.queue, self.input, self.start, self.end)
    }

    fn pair(&self) -> usize {
        match self.queue[self.start] {
            QueueableToken::Start {
                end_token_index, ..
            } => end_token_index,
            _ => unreachable!()
        }
    }

    fn pair_from_end(&self) -> usize {
        match self.queue[self.end - 1] {
            QueueableToken::End {
                start_token_index, ..
            } => start_token_index,
            _ => unreachable!()
        }
    }

    fn pos(&self, index: usize) -> usize {
        match self.queue[index] {
            QueueableToken::Start { input_pos, .. } | QueueableToken::End { input_pos, .. } => {
                input_pos
            }
        }
    }
}

impl<'i, R: RuleType> Iterator for Pairs<'i, R> {
    type Item = Pair<'i, R>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.start >= self.end {
            return None;
        }

        let pair = pair::new(Rc::clone(&self.queue), self.input, self.start);

        self.start = self.pair() + 1;

        Some(pair)
    }
}

impl<'i, R: RuleType> DoubleEndedIterator for Pairs<'i, R> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.end <= self.start {
            return None;
        }

        self.end = self.pair_from_end();

        let pair = pair::new(Rc::clone(&self.queue), self.input, self.end);

        Some(pair)
    }
}

impl<'i, R: RuleType> fmt::Debug for Pairs<'i, R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_list().entries(self.clone()).finish()
    }
}

impl<'i, R: RuleType> fmt::Display for Pairs<'i, R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "[{}]",
            self.clone()
                .map(|pair| format!("{}", pair))
                .collect::<Vec<_>>()
                .join(", ")
        )
    }
}

impl<'i, R: PartialEq> PartialEq for Pairs<'i, R> {
    fn eq(&self, other: &Pairs<'i, R>) -> bool {
        Rc::ptr_eq(&self.queue, &other.queue) && ptr::eq(self.input, other.input)
            && self.start == other.start && self.end == other.end
    }
}

impl<'i, R: Eq> Eq for Pairs<'i, R> {}

impl<'i, R: Hash> Hash for Pairs<'i, R> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        (&*self.queue as *const Vec<QueueableToken<R>>).hash(state);
        (self.input as *const [u8]).hash(state);
        self.start.hash(state);
        self.end.hash(state);
    }
}

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

    #[test]
    fn as_str() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();

        assert_eq!(pairs.as_str(), "abcde");
    }

    #[test]
    fn concat() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();

        assert_eq!(pairs.concat(), "abce");
    }

    #[test]
    fn pairs_debug() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();

        assert_eq!(
            format!("{:?}", pairs),
            "[\
                Pair { rule: a, span: Span { str: \"abc\", start: 0, end: 3 }, inner: [\
                    Pair { rule: b, span: Span { str: \"b\", start: 1, end: 2 }, inner: [] }\
                ] }, \
                Pair { rule: c, span: Span { str: \"e\", start: 4, end: 5 }, inner: [] }\
            ]"
        .to_owned()
        );
    }

    #[test]
    fn pairs_display() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();

        assert_eq!(
            format!("{}", pairs),
            "[a(0, 3, [b(1, 2)]), c(4, 5)]".to_owned()
        );
    }

    #[test]
    fn iter_for_pairs() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();
        assert_eq!(
            pairs.map(|p| p.as_rule()).collect::<Vec<Rule>>(),
            vec![Rule::a, Rule::c]
        );
    }

    #[test]
    fn double_ended_iter_for_pairs() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();
        assert_eq!(
            pairs.rev().map(|p| p.as_rule()).collect::<Vec<Rule>>(),
            vec![Rule::c, Rule::a]
        );
    }
}
<|endoftext|>


<commit_before><commit_msg>test passing in validator_record.rs<commit_after><|endoftext|>