<commit_before>#[macro_use]
extern crate nom;

use std::str;
use std::str::FromStr;
use std::fmt;
use std::fs::File;
use std::io::prelude::*;

// like Into trait but works from a ref avoiding consumption or expensive clone
pub trait IntoSexp {
    fn into_sexp(&self) -> Sexp;
}

pub trait FromSexp {
   fn from(&Sexp) -> Self;
}

#[derive(Debug, Clone)]
pub struct Sexp {
    pub element:Element,
    pub meta:Meta,
}

pub struct Compact<'a> {
    what:&'a Sexp,
}

pub fn compact<'a>(e:&'a Sexp) -> Compact<'a> {
    Compact { what:e }
}

#[derive(Debug, Clone)]
pub enum Element {
    String(String),
    List(Vec<Sexp>),
    Empty,
}

#[derive(Debug, Clone)]
pub struct Meta {
    indent:String,
    nl:usize,
    after_list:String,
}

pub type ERes<T> = Result<T, String>;

impl Sexp {

    pub fn new_empty() -> Sexp {
        Sexp { element:Element::Empty, meta:Meta { indent:String::from(""), nl:0, after_list:String::from(""), } }
    }

    pub fn new(element:Element, indent:String, nl:usize, after_list:String) -> Sexp {
        Sexp { element:element, meta:Meta { indent:indent, nl:nl, after_list:after_list, }, }
    }

    pub fn from<T:IntoSexp>(t:&T) -> Sexp {
        t.into_sexp()
    }

    pub fn list(&self) -> ERes<&Vec<Sexp> > {
        match self.element {
            Element::List(ref v) => Ok(v),
            _ => Err(format!("not a list: {}", self))
        }
    }

    pub fn string(&self) -> ERes<&String> {
        match self.element {
            Element::String(ref s) => Ok(s),
            _ => Err(format!("not a string: {}", self))
        }
    }

    pub fn f(&self) -> ERes<f64> {
        let s = try!(self.string());
        match f64::from_str(&s) {
            Ok(f) => Ok(f),
            _ => Err(format!("Error parsing float"))
        }
    }

    pub fn i(&self) -> ERes<i64> {
        let s = try!(self.string());
        match i64::from_str(&s) {
            Ok(f) => Ok(f),
            _ => Err(format!("Error parsing int"))
        }
    }

    pub fn list_name(&self) -> ERes<&String> {
        let l = try!(self.list());
        let l = &l[..];
        let a = try!(l[0].string());
        Ok(a)
    }

    pub fn slice_atom(&self, s:&str) -> ERes<&[Sexp]> {
        let v = try!(self.list());
        let v2 =&v[..];
        let st = try!(v2[0].string());
        if st != s {
            return Err(format!("list doesn't start with {}, but with {}", s, st))
        };
        Ok(&v[1..])
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "{}", self.meta.indent));
        try!(match self.element {
            Element::String(ref s) => {
                if s.contains("(") || s.contains(" ") {
                    write!(f,"\"{}\"", s)
                } else {
                    write!(f,"{}", s)
                }
            },
            Element::List(ref v) => {
                try!(write!(f, "("));
                let mut prev_nl = 0;
                for (i, x) in v.iter().enumerate() {
                    let s = if i == 0 || x.meta.indent.len() > 0 || prev_nl > 0 { "" } else { " " };
                    try!(write!(f, "{}{}", s, x));
                    prev_nl = x.meta.nl;
                }
                write!(f, "{})", self.meta.after_list)
            },
            Element::Empty => Ok(())
        });
        for _ in 0..self.meta.nl {
            try!(writeln!(f,""));
        }
        Ok(())
    }
}

impl<'a> fmt::Display for Compact<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self.what.element {
            Element::String(ref s) => {
                if s.contains("(") || s.contains(" ") {
                    write!(f,"\"{}\"", s)
                } else {
                    write!(f,"{}", s)
                }
            },
            Element::List(ref v) => {
                try!(write!(f, "("));
                for (i, x) in v.iter().enumerate() {
                    let s = if i == 0 { "" } else { " " };
                    try!(write!(f, "{}{}", s, compact(x)));
                }
                write!(f, ")")
            },
            Element::Empty => Ok(())
        }
    }
}

pub fn display_string(s:&String) -> String {
    if s.contains("(") || s.contains(" ") || s.len() == 0 {
        format!("\"{}\"", s)
    } else {
        s.clone()
    }
}

pub fn parse_str(sexp: &str) -> Result<Sexp, String> {
    if sexp.len() == 0 {
        return Ok(Sexp::new_empty())
    }
    match parse_sexp(&sexp.as_bytes()[..]) {
        nom::IResult::Done(_, c) => Ok(c),
        nom::IResult::Error(err) => {
            match err {
                nom::Err::Position(kind,p) =>
                    Err(format!("parse error: {:?} |{}|", kind, str::from_utf8(p).unwrap())),
                _ => Err(format!("parse error"))
            }
        },
        nom::IResult::Incomplete(x) => Err(format!("incomplete: {:?}", x)),
    }
}

fn read_file(name: &str) -> Result<String, std::io::Error> {
    let mut f = try!(File::open(name));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}

pub fn parse_file(name: &str) -> ERes<Sexp> {
    let s = try!(match read_file(name) {
        Ok(s) => Ok(s),
        Err(x) => Err(format!("{:?}", x))
    });
    parse_str(&s[..])
}

named!(parse_qstring<String>,
       map_res!(
           map_res!(
               delimited!(char!('\"'), is_not!("\""), char!('\"')),
               str::from_utf8),
           FromStr::from_str)
       );

named!(parse_bare_string<String>,
       map_res!(
           map_res!(
               is_not!(b")( \r\n"),
               str::from_utf8),
           FromStr::from_str)
       );

named!(parse_string<(Element,Option<&[u8]>) >,
       map!(alt!(parse_qstring | parse_bare_string), |x| (Element::String(x), None))
       );

named!(parse_list<(Element,Option<&[u8]>) >,
       chain!(
           char!('(') ~
               v: many0!(parse_sexp) ~
               after_list: opt!(nom::multispace) ~ // sometimes there is space after a closing bracket, this would not be caught by parse_sexp
               char!(')'),
           || (Element::List(v), after_list) )
       );

// TODO: consider lines with just spaces and a nl as also nl
named!(line_ending<usize>,
       chain!(
           opt!(nom::space) ~
               c: opt!(is_a!(b"\r\n"))
               , || match c { None => 0, Some(ref x) => x.len(), }
               )
       );

named!(parse_sexp<Sexp>,
           chain!(
               indent: opt!(nom::space) ~
                   s_after_list: alt!(parse_list | parse_string) ~
                   nl: line_ending
                   ,
               || {
                   let s = s_after_list.0.clone();
                   let after_list = s_after_list.1;
                   let indent = match indent {
                       None => String::new(),
                       Some(x) => String::from(str::from_utf8(x).unwrap()),
                   };
                   let after_list = match after_list {
                       None => String::new(),
                       Some(x) => String::from(str::from_utf8(x).unwrap()),
                   };
                   Sexp::new(s, indent, nl, after_list)
               })
       );

// internal tests
#[test]
fn test_qstring1() {
    let x = parse_string(&b"\"hello world\""[..]);
    match x {
        nom::IResult::Done(_,y) => {
            let (e, _) = y;
            match e {
                Element::String(f) => assert_eq!(String::from("hello world"), f),
                _ => panic!("not string"),
            }
        },
        _ => panic!("parser not done"),
    }
}

/*
#[test]
#[should_panic(expected="assertion failed: `(left == right)` (left: `Incomplete(Size(1))`, right: `Done([], \"hello\")`)")]
fn test_qstring2() {
    parse_string(&b"\"hello"[..]);
}
*/

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

    #[allow(dead_code)]
    fn check_parse_res(s: &str, o:&str) {
        let e = parse_str(s).unwrap();
        let t = format!("{}", e);
        assert_eq!(o, t)
    }
    #[allow(dead_code)]
    fn check_parse(s: &str) {
        let e = parse_str(s).unwrap();
        let t = format!("{}", e);
        assert_eq!(s, t)
    }

    #[allow(dead_code)]
    fn parse_fail(s: &str) {
        parse_str(s).unwrap();
    }
    #[allow(dead_code)]
    fn check_compact(s: &str, o:&str) {
        let e = parse_str(s).unwrap();
        let t = format!("{}", compact(&e));
        assert_eq!(o, t)
    }

    #[test]
    fn test_empty() { check_parse("") }

    #[test]
    fn test_empty_qstring() { check_parse("(hello \"\")") }

    #[test]
    fn test_minimal() { check_parse("()") }

    #[test]
    fn test_string() { check_parse("hello") }

    #[test]
    fn test_qstring_a() { check_parse_res("\"hello\"", "hello") }

    #[test]
    fn test_qstring_a2() { check_parse("\"hello world\"") }

    #[test]
    fn test_qstring_a3() { check_parse("\"hello(world)\"") }

    #[test]
    fn test_number() { check_parse("1.3") }

    #[test]
    fn test_float_vs_int() { check_parse("2.0") }

    #[test]
    fn test_double() { check_parse("(())") }

    #[test]
    fn test_br_string() { check_parse("(world)") }

    #[test]
    fn test_br_qstring() { check_parse_res("(\"world\")", "(world)") }

    #[test]
    fn test_br_int() { check_parse("(42)") }

    #[test]
    fn test_br_float() { check_parse("(12.7)") }

    #[test]
    fn test_br_qbrstring() { check_parse("(\"(()\")") }

    #[test]
    fn test_number_string() { check_parse("567A_WZ") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: \"incomplete: Size(2)\"")]
    fn test_invalid1() { parse_fail("(") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: \"parse error: Alt |)|\"")]
    fn test_invalid2() { parse_fail(")") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: \"incomplete: Size(1)\"")]
    fn test_invalid3() { parse_fail("\"hello") }

    #[test]
    fn test_complex() { check_parse("(module SWITCH_3W_SIDE_MMP221-R (layer F.Cu) (descr \"\") (pad 1 thru_hole rect (size 1.2 1.2) (at -2.5 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 2 thru_hole rect (size 1.2 1.2) (at 0.0 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 3 thru_hole rect (size 1.2 1.2) (at 2.5 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 5 thru_hole rect (size 1.2 1.2) (at 0.0 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 6 thru_hole rect (size 1.2 1.2) (at -2.5 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 4 thru_hole rect (size 1.2 1.2) (at 2.5 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (fp_line (start -4.5 -1.75) (end 4.5 -1.75) (layer F.SilkS) (width 0.127)) (fp_line (start 4.5 -1.75) (end 4.5 1.75) (layer F.SilkS) (width 0.127)) (fp_line (start 4.5 1.75) (end -4.5 1.75) (layer F.SilkS) (width 0.127)) (fp_line (start -4.5 1.75) (end -4.5 -1.75) (layer F.SilkS) (width 0.127)))") }

    #[test]
    fn test_multiline() {
        check_parse("\
(hello \"test it\"
    (foo bar)
    (mars venus)
)
")
    }

    #[test]
    fn test_multiline2() {
        check_parse("\
(hello world
  mad
    (world)
  not)")
    }

    #[test]
    fn test_multiline_two_empty() {
        check_parse("\
(hello

world)")
    }

    #[test]
    fn test_compact1() {
        check_compact("( hello
world \"foo
  bar\"
     (baz)
)", "(hello world \"foo
  bar\" (baz))")
    }

    #[test]
    fn test_fail_pcb() {
        check_parse("\
(kicad_pcb (version 4) (host pcbnew \"(2015-05-31 BZR 5692)-product\")
  (general
  )
)")
    }
}

<commit_msg>fix test<commit_after>#[macro_use]
extern crate nom;

use std::str;
use std::str::FromStr;
use std::fmt;
use std::fs::File;
use std::io::prelude::*;

// like Into trait but works from a ref avoiding consumption or expensive clone
pub trait IntoSexp {
    fn into_sexp(&self) -> Sexp;
}

#[derive(Debug, Clone)]
pub struct Sexp {
    pub element:Element,
    pub meta:Meta,
}

pub struct Compact<'a> {
    what:&'a Sexp,
}

pub fn compact<'a>(e:&'a Sexp) -> Compact<'a> {
    Compact { what:e }
}

#[derive(Debug, Clone)]
pub enum Element {
    String(String),
    List(Vec<Sexp>),
    Empty,
}

#[derive(Debug, Clone)]
pub struct Meta {
    indent:String,
    nl:usize,
    after_list:String,
}

pub type ERes<T> = Result<T, String>;

impl Sexp {

    pub fn new_empty() -> Sexp {
        Sexp { element:Element::Empty, meta:Meta { indent:String::from(""), nl:0, after_list:String::from(""), } }
    }

    pub fn new(element:Element, indent:String, nl:usize, after_list:String) -> Sexp {
        Sexp { element:element, meta:Meta { indent:indent, nl:nl, after_list:after_list, }, }
    }

    pub fn from<T:IntoSexp>(t:&T) -> Sexp {
        t.into_sexp()
    }

    pub fn list(&self) -> ERes<&Vec<Sexp> > {
        match self.element {
            Element::List(ref v) => Ok(v),
            _ => Err(format!("not a list: {}", self))
        }
    }

    pub fn string(&self) -> ERes<&String> {
        match self.element {
            Element::String(ref s) => Ok(s),
            _ => Err(format!("not a string: {}", self))
        }
    }

    pub fn f(&self) -> ERes<f64> {
        let s = try!(self.string());
        match f64::from_str(&s) {
            Ok(f) => Ok(f),
            _ => Err(format!("Error parsing float"))
        }
    }

    pub fn i(&self) -> ERes<i64> {
        let s = try!(self.string());
        match i64::from_str(&s) {
            Ok(f) => Ok(f),
            _ => Err(format!("Error parsing int"))
        }
    }

    pub fn list_name(&self) -> ERes<&String> {
        let l = try!(self.list());
        let l = &l[..];
        let a = try!(l[0].string());
        Ok(a)
    }

    pub fn slice_atom(&self, s:&str) -> ERes<&[Sexp]> {
        let v = try!(self.list());
        let v2 =&v[..];
        let st = try!(v2[0].string());
        if st != s {
            return Err(format!("list doesn't start with {}, but with {}", s, st))
        };
        Ok(&v[1..])
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "{}", self.meta.indent));
        try!(match self.element {
            Element::String(ref s) => {
                if s.contains("(") || s.contains(" ") {
                    write!(f,"\"{}\"", s)
                } else {
                    write!(f,"{}", s)
                }
            },
            Element::List(ref v) => {
                try!(write!(f, "("));
                let mut prev_nl = 0;
                for (i, x) in v.iter().enumerate() {
                    let s = if i == 0 || x.meta.indent.len() > 0 || prev_nl > 0 { "" } else { " " };
                    try!(write!(f, "{}{}", s, x));
                    prev_nl = x.meta.nl;
                }
                write!(f, "{})", self.meta.after_list)
            },
            Element::Empty => Ok(())
        });
        for _ in 0..self.meta.nl {
            try!(writeln!(f,""));
        }
        Ok(())
    }
}

impl<'a> fmt::Display for Compact<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self.what.element {
            Element::String(ref s) => {
                if s.contains("(") || s.contains(" ") {
                    write!(f,"\"{}\"", s)
                } else {
                    write!(f,"{}", s)
                }
            },
            Element::List(ref v) => {
                try!(write!(f, "("));
                for (i, x) in v.iter().enumerate() {
                    let s = if i == 0 { "" } else { " " };
                    try!(write!(f, "{}{}", s, compact(x)));
                }
                write!(f, ")")
            },
            Element::Empty => Ok(())
        }
    }
}

pub fn display_string(s:&String) -> String {
    if s.contains("(") || s.contains(" ") || s.len() == 0 {
        format!("\"{}\"", s)
    } else {
        s.clone()
    }
}

pub fn parse_str(sexp: &str) -> Result<Sexp, String> {
    if sexp.len() == 0 {
        return Ok(Sexp::new_empty())
    }
    match parse_sexp(&sexp.as_bytes()[..]) {
        nom::IResult::Done(_, c) => Ok(c),
        nom::IResult::Error(err) => {
            match err {
                nom::Err::Position(kind,p) =>
                    Err(format!("parse error: {:?} |{}|", kind, str::from_utf8(p).unwrap())),
                _ => Err(format!("parse error"))
            }
        },
        nom::IResult::Incomplete(x) => Err(format!("incomplete: {:?}", x)),
    }
}

fn read_file(name: &str) -> Result<String, std::io::Error> {
    let mut f = try!(File::open(name));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}

pub fn parse_file(name: &str) -> ERes<Sexp> {
    let s = try!(match read_file(name) {
        Ok(s) => Ok(s),
        Err(x) => Err(format!("{:?}", x))
    });
    parse_str(&s[..])
}

named!(parse_qstring<String>,
       map_res!(
           map_res!(
               delimited!(char!('\"'), is_not!("\""), char!('\"')),
               str::from_utf8),
           FromStr::from_str)
       );

named!(parse_bare_string<String>,
       map_res!(
           map_res!(
               is_not!(b")( \r\n"),
               str::from_utf8),
           FromStr::from_str)
       );

named!(parse_string<(Element,Option<&[u8]>) >,
       map!(alt!(parse_qstring | parse_bare_string), |x| (Element::String(x), None))
       );

named!(parse_list<(Element,Option<&[u8]>) >,
       chain!(
           char!('(') ~
               v: many0!(parse_sexp) ~
               after_list: opt!(nom::multispace) ~ // sometimes there is space after a closing bracket, this would not be caught by parse_sexp
               char!(')'),
           || (Element::List(v), after_list) )
       );

// TODO: consider lines with just spaces and a nl as also nl
named!(line_ending<usize>,
       chain!(
           opt!(nom::space) ~
               c: opt!(is_a!(b"\r\n"))
               , || match c { None => 0, Some(ref x) => x.len(), }
               )
       );

named!(parse_sexp<Sexp>,
           chain!(
               indent: opt!(nom::space) ~
                   s_after_list: alt!(parse_list | parse_string) ~
                   nl: line_ending
                   ,
               || {
                   let s = s_after_list.0.clone();
                   let after_list = s_after_list.1;
                   let indent = match indent {
                       None => String::new(),
                       Some(x) => String::from(str::from_utf8(x).unwrap()),
                   };
                   let after_list = match after_list {
                       None => String::new(),
                       Some(x) => String::from(str::from_utf8(x).unwrap()),
                   };
                   Sexp::new(s, indent, nl, after_list)
               })
       );

// internal tests
#[test]
fn test_qstring1() {
    let x = parse_string(&b"\"hello world\""[..]);
    match x {
        nom::IResult::Done(_,y) => {
            let (e, _) = y;
            match e {
                Element::String(f) => assert_eq!(String::from("hello world"), f),
                _ => panic!("not string"),
            }
        },
        _ => panic!("parser not done"),
    }
}

/*
#[test]
#[should_panic(expected="assertion failed: `(left == right)` (left: `Incomplete(Size(1))`, right: `Done([], \"hello\")`)")]
fn test_qstring2() {
    parse_string(&b"\"hello"[..]);
}
*/

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

    #[allow(dead_code)]
    fn check_parse_res(s: &str, o:&str) {
        let e = parse_str(s).unwrap();
        let t = format!("{}", e);
        assert_eq!(o, t)
    }
    #[allow(dead_code)]
    fn check_parse(s: &str) {
        let e = parse_str(s).unwrap();
        let t = format!("{}", e);
        assert_eq!(s, t)
    }

    #[allow(dead_code)]
    fn parse_fail(s: &str) {
        parse_str(s).unwrap();
    }
    #[allow(dead_code)]
    fn check_compact(s: &str, o:&str) {
        let e = parse_str(s).unwrap();
        let t = format!("{}", compact(&e));
        assert_eq!(o, t)
    }

    #[test]
    fn test_empty() { check_parse("") }

    #[test]
    fn test_empty_qstring() { check_parse("(hello \"\")") }

    #[test]
    fn test_minimal() { check_parse("()") }

    #[test]
    fn test_string() { check_parse("hello") }

    #[test]
    fn test_qstring_a() { check_parse_res("\"hello\"", "hello") }

    #[test]
    fn test_qstring_a2() { check_parse("\"hello world\"") }

    #[test]
    fn test_qstring_a3() { check_parse("\"hello(world)\"") }

    #[test]
    fn test_number() { check_parse("1.3") }

    #[test]
    fn test_float_vs_int() { check_parse("2.0") }

    #[test]
    fn test_double() { check_parse("(())") }

    #[test]
    fn test_br_string() { check_parse("(world)") }

    #[test]
    fn test_br_qstring() { check_parse_res("(\"world\")", "(world)") }

    #[test]
    fn test_br_int() { check_parse("(42)") }

    #[test]
    fn test_br_float() { check_parse("(12.7)") }

    #[test]
    fn test_br_qbrstring() { check_parse("(\"(()\")") }

    #[test]
    fn test_number_string() { check_parse("567A_WZ") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: \"incomplete: Size(2)\"")]
    fn test_invalid1() { parse_fail("(") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: \"parse error: Alt |)|\"")]
    fn test_invalid2() { parse_fail(")") }

    #[test]
    #[should_panic(expected="incomplete: Size")]
    fn test_invalid3() { parse_fail("\"hello") }

    #[test]
    fn test_complex() { check_parse("(module SWITCH_3W_SIDE_MMP221-R (layer F.Cu) (descr \"\") (pad 1 thru_hole rect (size 1.2 1.2) (at -2.5 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 2 thru_hole rect (size 1.2 1.2) (at 0.0 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 3 thru_hole rect (size 1.2 1.2) (at 2.5 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 5 thru_hole rect (size 1.2 1.2) (at 0.0 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 6 thru_hole rect (size 1.2 1.2) (at -2.5 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 4 thru_hole rect (size 1.2 1.2) (at 2.5 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (fp_line (start -4.5 -1.75) (end 4.5 -1.75) (layer F.SilkS) (width 0.127)) (fp_line (start 4.5 -1.75) (end 4.5 1.75) (layer F.SilkS) (width 0.127)) (fp_line (start 4.5 1.75) (end -4.5 1.75) (layer F.SilkS) (width 0.127)) (fp_line (start -4.5 1.75) (end -4.5 -1.75) (layer F.SilkS) (width 0.127)))") }

    #[test]
    fn test_multiline() {
        check_parse("\
(hello \"test it\"
    (foo bar)
    (mars venus)
)
")
    }

    #[test]
    fn test_multiline2() {
        check_parse("\
(hello world
  mad
    (world)
  not)")
    }

    #[test]
    fn test_multiline_two_empty() {
        check_parse("\
(hello

world)")
    }

    #[test]
    fn test_compact1() {
        check_compact("( hello
world \"foo
  bar\"
     (baz)
)", "(hello world \"foo
  bar\" (baz))")
    }

    #[test]
    fn test_fail_pcb() {
        check_parse("\
(kicad_pcb (version 4) (host pcbnew \"(2015-05-31 BZR 5692)-product\")
  (general
  )
)")
    }
}

<|endoftext|>


<commit_before>#![feature(custom_derive)]
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

mod list;
mod storage;
mod todo;
<commit_msg>make imports public<commit_after>#![feature(custom_derive)]
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

pub mod list;
pub mod storage;
pub mod todo;
<|endoftext|>


<commit_before>//! This is a library for controlling a cursor and a screen,
//! on ANSI terminals.
//!
//!
//! ## Example
//!
//!     use ansi_control::*;
//!

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

    macro_rules! test {
        ($name: ident; $ctrl: expr => $result: expr) => {
            #[test]
            fn $name() {
                assert_eq!($result, $ctrl)
            }
        };
    }

    test!(move_cursor0; move_cursor(2, -4) => "\x1B[2A\x1B[4D");
    test!(move_cursor1; move_cursor(-2, 0) => "\x1B[2B");
    test!(move_cursor2; move_cursor(0, 6) => "\x1B[6C");
    test!(move_cursor3; move_cursor(0, 0) => "");

    test!(move_line0; move_line(4) => "\x1B[4E");
    test!(move_line1; move_line(-4) => "\x1B[4F");

    test!(set_column0; set_column(3) => "\x1B[3G");
    test!(set_column1; set_column(0) => "\x1B[1G");

    test!(set_position0; set_position(3, 5) => "\x1B[3;5H");
    test!(set_position1; set_position(0, 0) => "\x1B[1;1H");

    test!(clear_display0; clear_display(Pos::Back) => "\x1B[0J");
    test!(clear_display1; clear_display(Pos::Front) => "\x1B[1J");
    test!(clear_display2; clear_display(Pos::Both) => "\x1B[2J");

    test!(clear_line0; clear_line(Pos::Back) => "\x1B[0K");
    test!(clear_line1; clear_line(Pos::Front) => "\x1B[1K");
    test!(clear_line2; clear_line(Pos::Both) => "\x1B[2K");

    test!(scroll0; scroll(7) => "\x1B[7S");
    test!(scroll1; scroll(-5) => "\x1B[5T");
}
<commit_msg>Add functions<commit_after>//! This is a library for controlling a cursor and a screen,
//! on ANSI terminals.
//!
//!
//! ## Example
//!
//!     use ansi_control::*;
//!

pub fn move_cursor(i: i32, j: i32) -> String {
    ""
}

pub fn move_line(n: i32) -> String {
    ""
}

pub fn set_column(n: u32) -> String {
    ""
}

pub fn set_position(i: u32, j: u32) -> String {
    ""
}

pub fn clear_display(pos: Pos) -> String {
    ""
}

pub fn clear_line(pos: Pos) -> String {
    ""
}

pub fn scroll(n: i32) -> String {
    ""
}

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

    macro_rules! test {
        ($name: ident; $ctrl: expr => $result: expr) => {
            #[test]
            fn $name() {
                assert_eq!($result, $ctrl)
            }
        };
    }

    test!(move_cursor0; move_cursor(2, -4) => "\x1B[2A\x1B[4D");
    test!(move_cursor1; move_cursor(-2, 0) => "\x1B[2B");
    test!(move_cursor2; move_cursor(0, 6) => "\x1B[6C");
    test!(move_cursor3; move_cursor(0, 0) => "");

    test!(move_line0; move_line(4) => "\x1B[4E");
    test!(move_line1; move_line(-4) => "\x1B[4F");

    test!(set_column0; set_column(3) => "\x1B[3G");
    test!(set_column1; set_column(0) => "\x1B[1G");

    test!(set_position0; set_position(3, 5) => "\x1B[3;5H");
    test!(set_position1; set_position(0, 0) => "\x1B[1;1H");

    test!(clear_display0; clear_display(Pos::Back) => "\x1B[0J");
    test!(clear_display1; clear_display(Pos::Front) => "\x1B[1J");
    test!(clear_display2; clear_display(Pos::Both) => "\x1B[2J");

    test!(clear_line0; clear_line(Pos::Back) => "\x1B[0K");
    test!(clear_line1; clear_line(Pos::Front) => "\x1B[1K");
    test!(clear_line2; clear_line(Pos::Both) => "\x1B[2K");

    test!(scroll0; scroll(7) => "\x1B[7S");
    test!(scroll1; scroll(-5) => "\x1B[5T");
}
<|endoftext|>


<commit_before>pub mod config;
mod gpg;

use rand::{rngs::OsRng, RngCore};
use rpassword;
use std::fs;
use std::path::{Path, PathBuf};
use std::str;

use self::config::Config;

pub enum Output {
    Get(PathBuf, Vec<u8>, bool),
    NoOutput,
}

pub enum Error {
    AlreadyInitialized,
    CannotChangeToDir(PathBuf),
    CannotInitRepo,
    FileDoesNotExist(PathBuf),
    InputsDidntMatch,
    NoRepo,
    TargetIsDirectory(PathBuf),
    CannotCreateDirectory(PathBuf),
    UnlockFailed,
    Usage,
}

use Error::*;
use Output::*;

const INIT_MESSAGE: &str = "\
Please pick a master passphrase. It is used to encrypt a very long
random key, which in turn is used to encrypt all the private data in
this directory.

Make sure you remember the master passphrase and that it's strong
enough for your privacy needs.
";

fn read_password(prompt: &str) -> String {
    let result = if atty::is(atty::Stream::Stdin) {
        rpassword::read_password_from_tty(Some(prompt))
    } else {
        rpassword::prompt_password_stderr(prompt)
    };
    match result {
        Ok(password) => password,

        // TODO: Error reading password, handle it somehow?
        Err(_) => String::from(""),
    }
}

fn read_secret(prompt1: &str, prompt2: &str) -> Result<String, Error> {
    let input1 = read_password(prompt1);
    let input2 = read_password(prompt2);
    if input1 == input2 {
        Ok(input1)
    } else {
        Err(InputsDidntMatch)
    }
}

fn unlock_repo() -> Result<Vec<u8>, Error> {
    if !Path::new(".sala/key").is_file() {
        Err(NoRepo)
    } else {
        let passphrase = read_password("Enter the master passphrase: ");
        gpg::decrypt(Path::new(".sala/key"), &passphrase.as_bytes()).map_err(|_| UnlockFailed)
    }
}

pub fn init(repo_path: &Path, config: &Config) -> Result<Output, Error> {
    let key_path = repo_path.join(".sala/key");
    if key_path.exists() {
        return Err(AlreadyInitialized);
    }

    let sala_path = repo_path.join(".sala");
    if !sala_path.exists() {
        fs::create_dir_all(&sala_path).map_err(|_| CannotInitRepo)?
    } else {
        return Err(AlreadyInitialized);
    }
    println!("{}", INIT_MESSAGE);

    let master_passphrase = read_secret("Enter a master passphrase: ", "Confirm: ")?;

    println!("");
    print!("Generating a master key (512 bits)...");
    let mut rng = OsRng::new().unwrap();
    let mut key: [u8; 32] = [0; 32];
    rng.fill_bytes(&mut key);
    let key_ascii: String = key
        .iter()
        .map(|&b| format!("{:x}", b))
        .collect::<Vec<String>>()
        .concat();
    println!(" done");

    gpg::encrypt(
        &key_ascii,
        &master_passphrase.as_bytes(),
        &key_path,
        &config.cipher,
    )
    .unwrap();
    Ok(NoOutput)
}

pub fn get(repo_path: &Path, path: &Path, raw: bool) -> Result<Output, Error> {
    let full_path = repo_path.join(path);

    if !full_path.is_file() {
        return Err(FileDoesNotExist(path.to_path_buf()));
    }
    let master_key = unlock_repo()?;
    let secret = gpg::decrypt(&full_path, &master_key).unwrap();
    Ok(Get(path.to_path_buf(), secret, raw))
}

pub fn set(repo_path: &Path, path: &Path, config: &Config) -> Result<Output, Error> {
    let full_path = repo_path.join(path);
    if let Some(path_parent) = path.parent() {
        fs::create_dir_all(full_path.parent().unwrap())
            .map_err(|_| CannotCreateDirectory(path_parent.to_path_buf()))?
    }

    if full_path.is_dir() {
        return Err(TargetIsDirectory(path.to_path_buf()));
    }
    let master_key = unlock_repo()?;
    let new_secret = read_secret(
        &format!("Type a new secret for {}: ", path.to_string_lossy()),
        "Confirm: ",
    )?;

    gpg::encrypt(&new_secret, &master_key, &full_path, &config.cipher).unwrap();
    Ok(NoOutput)
}

pub fn get_or_set(
    repo_path: &Path,
    path: &Path,
    config: &Config,
    raw: bool,
) -> Result<Output, Error> {
    if repo_path.join(path).exists() {
        get(repo_path, path, raw)
    } else {
        set(repo_path, path, config)
    }
}
<commit_msg>Use key_length from config (Rust)<commit_after>pub mod config;
mod gpg;

use rand::{rngs::OsRng, RngCore};
use rpassword;
use std::fs;
use std::path::{Path, PathBuf};
use std::str;

use self::config::Config;

pub enum Output {
    Get(PathBuf, Vec<u8>, bool),
    NoOutput,
}

pub enum Error {
    AlreadyInitialized,
    CannotChangeToDir(PathBuf),
    CannotInitRepo,
    FileDoesNotExist(PathBuf),
    InputsDidntMatch,
    NoRepo,
    TargetIsDirectory(PathBuf),
    CannotCreateDirectory(PathBuf),
    UnlockFailed,
    Usage,
}

use Error::*;
use Output::*;

const INIT_MESSAGE: &str = "\
Please pick a master passphrase. It is used to encrypt a very long
random key, which in turn is used to encrypt all the private data in
this directory.

Make sure you remember the master passphrase and that it's strong
enough for your privacy needs.
";

fn read_password(prompt: &str) -> String {
    let result = if atty::is(atty::Stream::Stdin) {
        rpassword::read_password_from_tty(Some(prompt))
    } else {
        rpassword::prompt_password_stderr(prompt)
    };
    match result {
        Ok(password) => password,

        // TODO: Error reading password, handle it somehow?
        Err(_) => String::from(""),
    }
}

fn read_secret(prompt1: &str, prompt2: &str) -> Result<String, Error> {
    let input1 = read_password(prompt1);
    let input2 = read_password(prompt2);
    if input1 == input2 {
        Ok(input1)
    } else {
        Err(InputsDidntMatch)
    }
}

fn unlock_repo() -> Result<Vec<u8>, Error> {
    if !Path::new(".sala/key").is_file() {
        Err(NoRepo)
    } else {
        let passphrase = read_password("Enter the master passphrase: ");
        gpg::decrypt(Path::new(".sala/key"), &passphrase.as_bytes()).map_err(|_| UnlockFailed)
    }
}

pub fn init(repo_path: &Path, config: &Config) -> Result<Output, Error> {
    let key_path = repo_path.join(".sala/key");
    if key_path.exists() {
        return Err(AlreadyInitialized);
    }

    let sala_path = repo_path.join(".sala");
    if !sala_path.exists() {
        fs::create_dir_all(&sala_path).map_err(|_| CannotInitRepo)?
    } else {
        return Err(AlreadyInitialized);
    }
    println!("{}", INIT_MESSAGE);

    let master_passphrase = read_secret("Enter a master passphrase: ", "Confirm: ")?;

    println!("");
    print!(
        "Generating a master key ({} bits)...",
        config.key_length * 8
    );
    let mut rng = OsRng::new().unwrap();
    let mut key: Vec<u8> = Vec::new();
    key.resize(config.key_length, 0);
    rng.fill_bytes(&mut key);
    let key_ascii: String = key
        .iter()
        .map(|&b| format!("{:x}", b))
        .collect::<Vec<String>>()
        .concat();
    println!(" done");

    gpg::encrypt(
        &key_ascii,
        &master_passphrase.as_bytes(),
        &key_path,
        &config.cipher,
    )
    .unwrap();
    Ok(NoOutput)
}

pub fn get(repo_path: &Path, path: &Path, raw: bool) -> Result<Output, Error> {
    let full_path = repo_path.join(path);

    if !full_path.is_file() {
        return Err(FileDoesNotExist(path.to_path_buf()));
    }
    let master_key = unlock_repo()?;
    let secret = gpg::decrypt(&full_path, &master_key).unwrap();
    Ok(Get(path.to_path_buf(), secret, raw))
}

pub fn set(repo_path: &Path, path: &Path, config: &Config) -> Result<Output, Error> {
    let full_path = repo_path.join(path);
    if let Some(path_parent) = path.parent() {
        fs::create_dir_all(full_path.parent().unwrap())
            .map_err(|_| CannotCreateDirectory(path_parent.to_path_buf()))?
    }

    if full_path.is_dir() {
        return Err(TargetIsDirectory(path.to_path_buf()));
    }
    let master_key = unlock_repo()?;
    let new_secret = read_secret(
        &format!("Type a new secret for {}: ", path.to_string_lossy()),
        "Confirm: ",
    )?;

    gpg::encrypt(&new_secret, &master_key, &full_path, &config.cipher).unwrap();
    Ok(NoOutput)
}

pub fn get_or_set(
    repo_path: &Path,
    path: &Path,
    config: &Config,
    raw: bool,
) -> Result<Output, Error> {
    if repo_path.join(path).exists() {
        get(repo_path, path, raw)
    } else {
        set(repo_path, path, config)
    }
}
<|endoftext|>


<commit_before>use accesstoken::AccessToken;

#[doc(hidden)]
pub fn v3(token: &AccessToken, url: String) -> String {
    format!("https://www.strava.com/api/v3/{}?access_token={}", url, token.get())
}

#[derive(Debug)]
pub struct Paginated<T> {
    page: i32,
    per_page: i32,
    url: String,
    data: Vec<T>
}

impl<T> Paginated<T> {
    pub fn new(url: String, data: Vec<T>) -> Paginated<T> {
        Paginated {
            page: 1,
            per_page: 30,
            url: url,
            data: data,
        }
    }
}
<commit_msg>Add paging methods to Paginated<commit_after>use accesstoken::AccessToken;

#[doc(hidden)]
pub fn v3(token: &AccessToken, url: String) -> String {
    format!("https://www.strava.com/api/v3/{}?access_token={}", url, token.get())
}

/// Wrapper for endpoints that paginate
///
/// A Paginated<T> will be returned from any endpoint that supports paging. Provides methods for
/// fetching the next page and checking if more pages are available.
#[derive(Debug)]
pub struct Paginated<T> {
    page: usize,
    per_page: usize,
    url: String,
    data: Vec<T>
}

impl<T> Paginated<T> {
    pub fn new(url: String, data: Vec<T>) -> Paginated<T> {
        Paginated {
            page: 1,
            per_page: 30,
            url: url,
            data: data,
        }
    }

    /// Get the next page of results
    pub fn next(&self) -> Option<Paginated<T>> {
        unimplemented!();
    }

    /// Check if this is the last page
    pub fn last_page(&self) -> bool {
        self.per_page != self.data.len()
    }
}

#[cfg(test)]
mod paginated_tests {
    use super::Paginated;

    #[test]
    fn last_page() {
        let vec = (0..30).collect::<Vec<u8>>();
        let pager = Paginated::new("test".to_string(), vec);
        println!("{:?}", pager);
        assert_eq!(pager.last_page(), false);
    }
}
<|endoftext|>


<commit_before>//! The export module for Tdo server.
#![deny(missing_docs, unsafe_code,
        missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unused_import_braces, unused_qualifications)]
#![warn(missing_debug_implementations)]
extern crate tdo_core;
extern crate libc;

use std::{slice, io, ptr};
use libc::{ioctl, c_ushort, STDOUT_FILENO, TIOCGWINSZ};

#[repr(C)]
struct winsize {
    ws_row: c_ushort, /* rows, in characters */
    ws_col: c_ushort, /* columns, in characters */
    ws_xpixel: c_ushort, /* horizontal size, pixels */
    ws_ypixel: c_ushort, /* vertical size, pixels */
}

/// Generates a well formated String of all undone Todos
pub fn gen_tasks_mail(tdo: &tdo_core::tdo::Tdo) -> Option<String> {
    let mut listed = String::new();
    for list in tdo.to_owned().lists.into_iter() {
        let undone = list.list_undone();
        if undone.len() > 0 {
            listed.push_str("\n------------------------------------------------------------\n\t");
            listed.push_str(&list.name);
            listed.push_str("\n------------------------------------------------------------\n");
            for entry in undone {
                if entry.done {
                    listed.push_str(&format!("- {:?}\n", entry.name));
                }
            }
            listed.push_str("\n\n");
        }
    }
    match listed.len() {
        0 => None,
        _ => Some(listed),
    }
}

/// Generates a markdown String to export the lists.
pub fn gen_tasks_md(tdo: &tdo_core::tdo::Tdo, list_done: bool) -> Option<String> {
    let mut markdown = String::from("# Your tasks\n\n");
    let name = get_full_name();
    if name.is_ok() {
        markdown.push_str(&format!("Here are the tasks for {}\n\n", &name.unwrap()));
    }
    let mut intern = String::new();
    for list in tdo.to_owned().lists.iter() {
        let tasks: Vec<tdo_core::todo::Todo>;
        if list_done {
            tasks = list.list.to_owned();
        } else {
            tasks = list.list_undone();
        }
        if tasks.len() > 0 {
            intern.push_str(&format!("\n### {}\n", &list.name));
            for entry in tasks {
                if entry.done {
                    intern.push_str(&format!("- [x] {}\n", &entry.name));
                } else {
                    intern.push_str(&format!("- [ ] {}\n", &entry.name));
                }
            }
        }
    }
    match intern.len() {
        0 => None,
        _ => {
            markdown.push_str(&intern);
            Some(markdown)
        }
    }
}

/// Returns the formated output for the terminal printout.
#[allow(unused_variables, unused_mut)] //for now
pub fn render_terminal_output(tdo: &tdo_core::tdo::Tdo, all: bool) -> Option<Vec<String>> {
    let (col, _): (usize, _) = match get_winsize() {
        Ok(res) => res,
        Err(_) => {
            println!("[Error] Terminalsize could not be fetched.", );
            std::process::exit(1);
        }
    };
    let id_space = tdo.get_highest_id().to_string().len();
    let mut formated_printout: Vec<String> = Vec::new();
    for list in tdo.lists.to_owned().iter() {
        let tasks: Vec<tdo_core::todo::Todo>;
        if all {
            tasks = list.list.to_owned();
        } else {
            tasks = list.list_undone();
        }
        if tasks.len() > 0 {
            formated_printout.push(format!("## {}", &list.name));
            for entry in tasks {
                let space = id_space - entry.id.to_string().len();
                let mut task_vec: Vec<String> = Vec::new();
                let mut entr_str = entry.name;
                let mut tmp_str: String;
                while entr_str.len() > col - 9 - id_space {
                    tmp_str = entr_str.split_off(col - 9 - id_space);
                    task_vec.push(entr_str);
                    entr_str = tmp_str;
                }
                task_vec.push(entr_str);
                if entry.done {
                    formated_printout.push(format!("  [x] {}{} | {}",
                                                   " ".repeat(space),
                                                   entry.id,
                                                   task_vec.remove(0)));
                } else {
                    formated_printout.push(format!("  [ ] {}{} | {}",
                                                   " ".repeat(space),
                                                   entry.id,
                                                   task_vec.remove(0)));
                }
                while task_vec.capacity() > 0 {
                    formated_printout.push(format!("{}| {}",
                                                   " ".repeat(7+id_space),
                                                   task_vec.remove(0)));
                }
            }
            formated_printout.push(String::new());
        }
    }
    match formated_printout.len() {
        0 => None,
        _ => Some(formated_printout),
    }
}

#[allow(unsafe_code)]
fn get_full_name() -> Result<String, io::Error> {
    unsafe {
        let uid = libc::geteuid();
        let user = ptr::read(libc::getpwuid(uid));
        let name = String::from_utf8_unchecked(slice::from_raw_parts(user.pw_gecos as *const u8,
                                                                     libc::strlen(user.pw_gecos))
            .to_vec());
        if name == "" {
            Err(io::Error::last_os_error())
        } else {
            Ok(name)
        }
    }
}

#[allow(unsafe_code)]
fn get_winsize() -> io::Result<(usize, usize)> {
    let w = winsize {
        ws_row: 0,
        ws_col: 0,
        ws_xpixel: 0,
        ws_ypixel: 0,
    };
    let r = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) };

    match r {
        0 => Ok((w.ws_col as usize, w.ws_row as usize)),
        _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "No valid data.")),
    }
}
<commit_msg>fix render_terminal_output<commit_after>//! The export module for Tdo server.
#![deny(missing_docs, unsafe_code,
        missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unused_import_braces, unused_qualifications)]
#![warn(missing_debug_implementations)]
extern crate tdo_core;
extern crate libc;

use std::{slice, io, ptr};
use libc::{ioctl, c_ushort, STDOUT_FILENO, TIOCGWINSZ};

#[repr(C)]
struct winsize {
    ws_row: c_ushort, /* rows, in characters */
    ws_col: c_ushort, /* columns, in characters */
    ws_xpixel: c_ushort, /* horizontal size, pixels */
    ws_ypixel: c_ushort, /* vertical size, pixels */
}

/// Generates a well formated String of all undone Todos
pub fn gen_tasks_mail(tdo: &tdo_core::tdo::Tdo) -> Option<String> {
    let mut listed = String::new();
    for list in tdo.to_owned().lists.into_iter() {
        let undone = list.list_undone();
        if undone.len() > 0 {
            listed.push_str("\n------------------------------------------------------------\n\t");
            listed.push_str(&list.name);
            listed.push_str("\n------------------------------------------------------------\n");
            for entry in undone {
                if entry.done {
                    listed.push_str(&format!("- {:?}\n", entry.name));
                }
            }
            listed.push_str("\n\n");
        }
    }
    match listed.len() {
        0 => None,
        _ => Some(listed),
    }
}

/// Generates a markdown String to export the lists.
pub fn gen_tasks_md(tdo: &tdo_core::tdo::Tdo, list_done: bool) -> Option<String> {
    let mut markdown = String::from("# Your tasks\n\n");
    let name = get_full_name();
    if name.is_ok() {
        markdown.push_str(&format!("Here are the tasks for {}\n\n", &name.unwrap()));
    }
    let mut intern = String::new();
    for list in tdo.to_owned().lists.iter() {
        let tasks: Vec<tdo_core::todo::Todo>;
        if list_done {
            tasks = list.list.to_owned();
        } else {
            tasks = list.list_undone();
        }
        if tasks.len() > 0 {
            intern.push_str(&format!("\n### {}\n", &list.name));
            for entry in tasks {
                if entry.done {
                    intern.push_str(&format!("- [x] {}\n", &entry.name));
                } else {
                    intern.push_str(&format!("- [ ] {}\n", &entry.name));
                }
            }
        }
    }
    match intern.len() {
        0 => None,
        _ => {
            markdown.push_str(&intern);
            Some(markdown)
        }
    }
}

/// Returns the formated output for the terminal printout.
#[allow(unused_variables, unused_mut)] //for now
pub fn render_terminal_output(tdo: &tdo_core::tdo::Tdo, all: bool) -> Option<Vec<String>> {
    let (col, _): (usize, _) = match get_winsize() {
        Ok(res) => res,
        Err(_) => {
            println!("[Error] Terminalsize could not be fetched.", );
            std::process::exit(1);
        }
    };
    let id_space = tdo.get_highest_id().to_string().len();
    let mut formated_printout: Vec<String> = Vec::new();
    for list in tdo.lists.to_owned().iter() {
        let tasks: Vec<tdo_core::todo::Todo>;
        if all {
            tasks = list.list.to_owned();
        } else {
            tasks = list.list_undone();
        }
        if tasks.len() > 0 {
            formated_printout.push(format!("## {}", &list.name));
            for entry in tasks {
                let space = id_space - entry.id.to_string().len();
                let mut task_vec: Vec<String> = Vec::new();
                let mut entr_str = entry.name;
                let mut tmp_str: String;
                while entr_str.len() > col - 9 - id_space {
                    tmp_str = entr_str.split_off(col - 9 - id_space);
                    task_vec.push(entr_str);
                    entr_str = tmp_str;
                }
                task_vec.push(entr_str);
                if entry.done {
                    formated_printout.push(format!("  [x] {}{} | {}",
                                                   " ".repeat(space),
                                                   entry.id,
                                                   task_vec.remove(0)));
                } else {
                    formated_printout.push(format!("  [ ] {}{} | {}",
                                                   " ".repeat(space),
                                                   entry.id,
                                                   task_vec.remove(0)));
                }
                if task_vec.capacity() > 0 {
                    for part in task_vec {
                        formated_printout.push(format!("{}| {}",
                                                       " ".repeat(7+id_space),
                                                       part));
                    }
                }
            }
            formated_printout.push(String::new());
        }
    }
    match formated_printout.len() {
        0 => None,
        _ => Some(formated_printout),
    }
}

#[allow(unsafe_code)]
fn get_full_name() -> Result<String, io::Error> {
    unsafe {
        let uid = libc::geteuid();
        let user = ptr::read(libc::getpwuid(uid));
        let name = String::from_utf8_unchecked(slice::from_raw_parts(user.pw_gecos as *const u8,
                                                                     libc::strlen(user.pw_gecos))
            .to_vec());
        if name == "" {
            Err(io::Error::last_os_error())
        } else {
            Ok(name)
        }
    }
}

#[allow(unsafe_code)]
fn get_winsize() -> io::Result<(usize, usize)> {
    let w = winsize {
        ws_row: 0,
        ws_col: 0,
        ws_xpixel: 0,
        ws_ypixel: 0,
    };
    let r = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) };

    match r {
        0 => Ok((w.ws_col as usize, w.ws_row as usize)),
        _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "No valid data.")),
    }
}
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

mod abort;
mod wf;

use abort::{decode_iss_data_abort, decode_iss_instruction_abort};
use bit_field::BitField;
use std::fmt::{self, Debug, Display, Formatter};
use thiserror::Error;
use wf::decode_iss_wf;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FieldInfo {
    pub name: &'static str,
    pub start: usize,
    pub width: usize,
    pub value: u64,
    pub decoded: Option<Decoded>,
}

impl FieldInfo {
    fn get(register: u64, name: &'static str, start: usize, end: usize) -> Self {
        let value = register.get_bits(start..end);
        Self {
            name,
            start,
            width: end - start,
            value,
            decoded: None,
        }
    }

    fn get_bit(register: u64, name: &'static str, bit: usize) -> Self {
        Self::get(register, name, bit, bit + 1)
    }

    fn with_decoded(self, decoded: Decoded) -> Self {
        Self {
            decoded: Some(decoded),
            ..self
        }
    }

    fn with_description(self, description: String) -> Self {
        self.with_decoded(Decoded {
            description: Some(description),
            fields: vec![],
        })
    }

    fn as_bit(&self) -> bool {
        assert!(self.width == 1);
        self.value == 1
    }

    /// Assuming this field has a width of exactly 1, describe it with the given function.
    ///
    /// Panics if `self.width != 1`.
    fn describe_bit<F>(self, describer: F) -> Self
    where
        F: FnOnce(bool) -> &'static str,
    {
        let bit = self.as_bit();
        let description = describer(bit).to_string();
        self.with_description(description)
    }

    fn describe<F>(self, describer: F) -> Result<Self, DecodeError>
    where
        F: FnOnce(u64) -> Result<&'static str, DecodeError>,
    {
        let description = describer(self.value)?.to_string();
        Ok(self.with_description(description))
    }

    fn check_res0(self) -> Result<Self, DecodeError> {
        if self.value != 0 {
            Err(DecodeError::InvalidRes0 { res0: self.value })
        } else {
            Ok(self)
        }
    }
}

impl Display for FieldInfo {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        if self.width == 1 {
            write!(
                f,
                "{}: {}",
                self.name,
                if self.value == 1 { "true" } else { "false" }
            )
        } else {
            write!(
                f,
                "{}: {:#02$x} {1:#03$b}",
                self.name,
                self.value,
                (self.width + 3) / 4 + 2,
                self.width + 2
            )
        }
    }
}

#[derive(Debug, Error)]
pub enum DecodeError {
    #[error("Invalid ESR, res0 is {res0:#x}")]
    InvalidRes0 { res0: u64 },
    #[error("Invalid EC {ec:#x}")]
    InvalidEc { ec: u64 },
    #[error("Invalid DFSC or IFSC {fsc:#x}")]
    InvalidFsc { fsc: u64 },
    #[error("ISV was false but instruction syndrome bits were nonzero {is:#x}")]
    UnexpectedInstructionSyndrome { is: u64 },
    #[error("Invalid SET {set:#x}")]
    InvalidSet { set: u64 },
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Decoded {
    pub description: Option<String>,
    pub fields: Vec<FieldInfo>,
}

fn decode_iss_res0(iss: u64) -> Result<Decoded, DecodeError> {
    if iss == 0 {
        Ok(Decoded {
            description: Some("ISS is RES0".to_string()),
            fields: vec![],
        })
    } else {
        Err(DecodeError::InvalidRes0 { res0: iss })
    }
}

pub fn decode(esr: u64) -> Result<Decoded, DecodeError> {
    let res0 = FieldInfo::get(esr, "RES0", 37, 64).check_res0()?;
    let iss2 = FieldInfo::get(esr, "ISS2", 32, 37);
    let ec = FieldInfo::get(esr, "EC", 26, 32);
    let il = FieldInfo::get_bit(esr, "IL", 25);
    let iss = FieldInfo::get(esr, "ISS", 0, 25);
    let (class, iss_decoded) = match ec.value {
        0b000000 => ("Unknown reason", Some(decode_iss_res0(iss.value)?)),
        0b000001 => ("Wrapped WF* instruction execution", Some(decode_iss_wf(iss.value)?)),
        0b000011 => ("Trapped MCR or MRC access with coproc=0b1111", None),
        0b000100 => ("Trapped MCRR or MRRC access with coproc=0b1111", None),
        0b000101 => ("Trapped MCR or MRC access with coproc=0b1110", None),
        0b000110 => ("Trapped LDC or STC access", None),
        0b000111 => ("Trapped access to SVE, Advanced SIMD or floating point", None),
        0b001010 => ("Trapped execution of an LD64B, ST64B, ST64BV, or ST64BV0 instruction", None),
        0b001100 => ("Trapped MRRC access with (coproc==0b1110)", None),
        0b001101 => ("Branch Target Exception", None),
        0b001110 => ("Illegal Execution state", Some(decode_iss_res0(iss.value)?)),
        0b010001 => ("SVC instruction execution in AArch32 state", None),
        0b010101 => ("SVC instruction execution in AArch64 state", None),
        0b011000 => ("Trapped MSR, MRS or System instruction execution in AArch64 state", None),
        0b011001 => ("Access to SVE functionality trapped as a result of CPACR_EL1.ZEN, CPTR_EL2.ZEN, CPTR_EL2.TZ, or CPTR_EL3.EZ", Some(decode_iss_res0(iss.value)?)),
        0b011100 => ("Exception from a Pointer Authentication instruction authentication failure", None),
        0b100000 => ("Instruction Abort from a lower Exception level", Some(decode_iss_instruction_abort(iss.value)?)),
        0b100001 => ("Instruction Abort taken without a change in Exception level", Some(decode_iss_instruction_abort(iss.value)?)),
        0b100010 => ("PC alignment fault exception", Some(decode_iss_res0(iss.value)?)),
        0b100100 => ("Data Abort from a lower Exception level", Some(decode_iss_data_abort(iss.value)?)),
        0b100101 => ("Data Abort taken without a change in Exception level", Some(decode_iss_data_abort(iss.value)?)),
        0b100110 => ("SP alignment fault exception", Some(decode_iss_res0(iss.value)?)),
        0b101000 => ("Trapped floating-point exception taken from AArch32 state", None),
        0b101100 => ("Trapped floating-point exception taken from AArch64 state", None),
        0b101111 => ("SError interrupt", None),
        0b110000 => ("Breakpoint exception from a lower Exception level", None),
        0b110001 => ("Breakpoint exception taken without a change in Exception level", None),
        0b110010 => ("Software Step exception from a lower Exception level", None),
        0b110011 => ("Software Step exception taken without a change in Exception level", None),
        0b110100 => ("Watchpoint exception from a lower Exception level", None),
        0b110101 => ("Watchpoint exception taken without a change in Exception level", None),
        0b111000 => ("BKPT instruction execution in AArch32 state", None),
        0b111100 => ("BRK instruction execution in AArch64 state", None),
        _ => return Err(DecodeError::InvalidEc { ec: ec.value }),
    };
    let iss = FieldInfo {
        decoded: iss_decoded,
        ..iss
    };
    let ec = ec.with_decoded(Decoded {
        description: Some(class.to_string()),
        fields: vec![],
    });
    Ok(Decoded {
        description: Some(class.to_string()),
        fields: vec![res0, iss2, ec, il, iss],
    })
}

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

    #[test]
    fn unknown() {
        let decoded = decode(0).unwrap();
        assert_eq!(
            decoded,
            Decoded {
                description: Some("Unknown reason".to_string()),
                fields: vec![
                    FieldInfo {
                        name: "RES0",
                        start: 37,
                        width: 27,
                        value: 0,
                        decoded: None
                    },
                    FieldInfo {
                        name: "ISS2",
                        start: 32,
                        width: 5,
                        value: 0,
                        decoded: None
                    },
                    FieldInfo {
                        name: "EC",
                        start: 26,
                        width: 6,
                        value: 0,
                        decoded: Some(Decoded {
                            description: Some("Unknown reason".to_string()),
                            fields: vec![]
                        })
                    },
                    FieldInfo {
                        name: "IL",
                        start: 25,
                        width: 1,
                        value: 0,
                        decoded: None
                    },
                    FieldInfo {
                        name: "ISS",
                        start: 0,
                        width: 25,
                        value: 0,
                        decoded: Some(Decoded {
                            description: Some("ISS is RES0".to_string()),
                            fields: vec![]
                        })
                    }
                ]
            }
        );
    }
}
<commit_msg>Describe IL.<commit_after>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

mod abort;
mod wf;

use abort::{decode_iss_data_abort, decode_iss_instruction_abort};
use bit_field::BitField;
use std::fmt::{self, Debug, Display, Formatter};
use thiserror::Error;
use wf::decode_iss_wf;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FieldInfo {
    pub name: &'static str,
    pub start: usize,
    pub width: usize,
    pub value: u64,
    pub decoded: Option<Decoded>,
}

impl FieldInfo {
    fn get(register: u64, name: &'static str, start: usize, end: usize) -> Self {
        let value = register.get_bits(start..end);
        Self {
            name,
            start,
            width: end - start,
            value,
            decoded: None,
        }
    }

    fn get_bit(register: u64, name: &'static str, bit: usize) -> Self {
        Self::get(register, name, bit, bit + 1)
    }

    fn with_decoded(self, decoded: Decoded) -> Self {
        Self {
            decoded: Some(decoded),
            ..self
        }
    }

    fn with_description(self, description: String) -> Self {
        self.with_decoded(Decoded {
            description: Some(description),
            fields: vec![],
        })
    }

    fn as_bit(&self) -> bool {
        assert!(self.width == 1);
        self.value == 1
    }

    /// Assuming this field has a width of exactly 1, describe it with the given function.
    ///
    /// Panics if `self.width != 1`.
    fn describe_bit<F>(self, describer: F) -> Self
    where
        F: FnOnce(bool) -> &'static str,
    {
        let bit = self.as_bit();
        let description = describer(bit).to_string();
        self.with_description(description)
    }

    fn describe<F>(self, describer: F) -> Result<Self, DecodeError>
    where
        F: FnOnce(u64) -> Result<&'static str, DecodeError>,
    {
        let description = describer(self.value)?.to_string();
        Ok(self.with_description(description))
    }

    fn check_res0(self) -> Result<Self, DecodeError> {
        if self.value != 0 {
            Err(DecodeError::InvalidRes0 { res0: self.value })
        } else {
            Ok(self)
        }
    }
}

impl Display for FieldInfo {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        if self.width == 1 {
            write!(
                f,
                "{}: {}",
                self.name,
                if self.value == 1 { "true" } else { "false" }
            )
        } else {
            write!(
                f,
                "{}: {:#02$x} {1:#03$b}",
                self.name,
                self.value,
                (self.width + 3) / 4 + 2,
                self.width + 2
            )
        }
    }
}

#[derive(Debug, Error)]
pub enum DecodeError {
    #[error("Invalid ESR, res0 is {res0:#x}")]
    InvalidRes0 { res0: u64 },
    #[error("Invalid EC {ec:#x}")]
    InvalidEc { ec: u64 },
    #[error("Invalid DFSC or IFSC {fsc:#x}")]
    InvalidFsc { fsc: u64 },
    #[error("ISV was false but instruction syndrome bits were nonzero {is:#x}")]
    UnexpectedInstructionSyndrome { is: u64 },
    #[error("Invalid SET {set:#x}")]
    InvalidSet { set: u64 },
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Decoded {
    pub description: Option<String>,
    pub fields: Vec<FieldInfo>,
}

fn decode_iss_res0(iss: u64) -> Result<Decoded, DecodeError> {
    if iss == 0 {
        Ok(Decoded {
            description: Some("ISS is RES0".to_string()),
            fields: vec![],
        })
    } else {
        Err(DecodeError::InvalidRes0 { res0: iss })
    }
}

pub fn decode(esr: u64) -> Result<Decoded, DecodeError> {
    let res0 = FieldInfo::get(esr, "RES0", 37, 64).check_res0()?;
    let iss2 = FieldInfo::get(esr, "ISS2", 32, 37);
    let ec = FieldInfo::get(esr, "EC", 26, 32);
    let il = FieldInfo::get_bit(esr, "IL", 25).describe_bit(describe_il);
    let iss = FieldInfo::get(esr, "ISS", 0, 25);
    let (class, iss_decoded) = match ec.value {
        0b000000 => ("Unknown reason", Some(decode_iss_res0(iss.value)?)),
        0b000001 => ("Wrapped WF* instruction execution", Some(decode_iss_wf(iss.value)?)),
        0b000011 => ("Trapped MCR or MRC access with coproc=0b1111", None),
        0b000100 => ("Trapped MCRR or MRRC access with coproc=0b1111", None),
        0b000101 => ("Trapped MCR or MRC access with coproc=0b1110", None),
        0b000110 => ("Trapped LDC or STC access", None),
        0b000111 => ("Trapped access to SVE, Advanced SIMD or floating point", None),
        0b001010 => ("Trapped execution of an LD64B, ST64B, ST64BV, or ST64BV0 instruction", None),
        0b001100 => ("Trapped MRRC access with (coproc==0b1110)", None),
        0b001101 => ("Branch Target Exception", None),
        0b001110 => ("Illegal Execution state", Some(decode_iss_res0(iss.value)?)),
        0b010001 => ("SVC instruction execution in AArch32 state", None),
        0b010101 => ("SVC instruction execution in AArch64 state", None),
        0b011000 => ("Trapped MSR, MRS or System instruction execution in AArch64 state", None),
        0b011001 => ("Access to SVE functionality trapped as a result of CPACR_EL1.ZEN, CPTR_EL2.ZEN, CPTR_EL2.TZ, or CPTR_EL3.EZ", Some(decode_iss_res0(iss.value)?)),
        0b011100 => ("Exception from a Pointer Authentication instruction authentication failure", None),
        0b100000 => ("Instruction Abort from a lower Exception level", Some(decode_iss_instruction_abort(iss.value)?)),
        0b100001 => ("Instruction Abort taken without a change in Exception level", Some(decode_iss_instruction_abort(iss.value)?)),
        0b100010 => ("PC alignment fault exception", Some(decode_iss_res0(iss.value)?)),
        0b100100 => ("Data Abort from a lower Exception level", Some(decode_iss_data_abort(iss.value)?)),
        0b100101 => ("Data Abort taken without a change in Exception level", Some(decode_iss_data_abort(iss.value)?)),
        0b100110 => ("SP alignment fault exception", Some(decode_iss_res0(iss.value)?)),
        0b101000 => ("Trapped floating-point exception taken from AArch32 state", None),
        0b101100 => ("Trapped floating-point exception taken from AArch64 state", None),
        0b101111 => ("SError interrupt", None),
        0b110000 => ("Breakpoint exception from a lower Exception level", None),
        0b110001 => ("Breakpoint exception taken without a change in Exception level", None),
        0b110010 => ("Software Step exception from a lower Exception level", None),
        0b110011 => ("Software Step exception taken without a change in Exception level", None),
        0b110100 => ("Watchpoint exception from a lower Exception level", None),
        0b110101 => ("Watchpoint exception taken without a change in Exception level", None),
        0b111000 => ("BKPT instruction execution in AArch32 state", None),
        0b111100 => ("BRK instruction execution in AArch64 state", None),
        _ => return Err(DecodeError::InvalidEc { ec: ec.value }),
    };
    let iss = FieldInfo {
        decoded: iss_decoded,
        ..iss
    };
    let ec = ec.with_decoded(Decoded {
        description: Some(class.to_string()),
        fields: vec![],
    });
    Ok(Decoded {
        description: Some(class.to_string()),
        fields: vec![res0, iss2, ec, il, iss],
    })
}

fn describe_il(il: bool) -> &'static str {
    if il {
        "32-bit instruction trapped"
    } else {
        "16-bit instruction trapped"
    }
}

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

    #[test]
    fn unknown() {
        let decoded = decode(0).unwrap();
        assert_eq!(
            decoded,
            Decoded {
                description: Some("Unknown reason".to_string()),
                fields: vec![
                    FieldInfo {
                        name: "RES0",
                        start: 37,
                        width: 27,
                        value: 0,
                        decoded: None
                    },
                    FieldInfo {
                        name: "ISS2",
                        start: 32,
                        width: 5,
                        value: 0,
                        decoded: None
                    },
                    FieldInfo {
                        name: "EC",
                        start: 26,
                        width: 6,
                        value: 0,
                        decoded: Some(Decoded {
                            description: Some("Unknown reason".to_string()),
                            fields: vec![]
                        })
                    },
                    FieldInfo {
                        name: "IL",
                        start: 25,
                        width: 1,
                        value: 0,
                        decoded: Some(Decoded {
                            description: Some("16-bit instruction trapped".to_string()),
                            fields: vec![]
                        })
                    },
                    FieldInfo {
                        name: "ISS",
                        start: 0,
                        width: 25,
                        value: 0,
                        decoded: Some(Decoded {
                            description: Some("ISS is RES0".to_string()),
                            fields: vec![]
                        })
                    }
                ]
            }
        );
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 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.

/*!
Syntax extension to generate FourCCs.

Once loaded, fourcc!() is called with a single 4-character string,
and an optional ident that is either `big`, `little`, or `target`.
The ident represents endianness, and specifies in which direction
the characters should be read. If the ident is omitted, it is assumed
to be `big`, i.e. left-to-right order. It returns a u32.

# Examples

To load the extension and use it:

```rust,ignore
#[phase(plugin)]
extern crate fourcc;

fn main() {
    let val = fourcc!("\xC0\xFF\xEE!");
    assert_eq!(val, 0xC0FFEE21u32);
    let little_val = fourcc!("foo ", little);
    assert_eq!(little_val, 0x21EEFFC0u32);
}
```

# References

* [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)

*/

#![crate_name = "fourcc"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico")]

#![feature(plugin_registrar)]

extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::attr::contains;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
use rustc::plugin::Registry;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("fourcc", expand_syntax_ext);
}

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                         -> Box<base::MacResult + 'static> {
    let (expr, endian) = parse_tts(cx, tts);

    let little = match endian {
        None => false,
        Some(Ident{ident, span}) => match token::get_ident(ident).get() {
            "little" => true,
            "big" => false,
            "target" => target_endian_little(cx, sp),
            _ => {
                cx.span_err(span, "invalid endian directive in fourcc!");
                target_endian_little(cx, sp)
            }
        }
    };

    let s = match expr.node {
        // expression is a literal
        ast::ExprLit(ref lit) => match lit.node {
            // string literal
            ast::LitStr(ref s, _) => {
                if s.get().char_len() != 4 {
                    cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
                }
                s
            }
            _ => {
                cx.span_err(expr.span, "unsupported literal in fourcc!");
                return base::DummyResult::expr(sp)
            }
        },
        _ => {
            cx.span_err(expr.span, "non-literal in fourcc!");
            return base::DummyResult::expr(sp)
        }
    };

    let mut val = 0u32;
    for codepoint in s.get().chars().take(4) {
        let byte = if codepoint as u32 > 0xFF {
            cx.span_err(expr.span, "fourcc! literal character out of range 0-255");
            0u8
        } else {
            codepoint as u8
        };

        val = if little {
            (val >> 8) | ((byte as u32) << 24)
        } else {
            (val << 8) | (byte as u32)
        };
    }
    let e = cx.expr_lit(sp, ast::LitInt(val as u64, ast::UnsignedIntLit(ast::TyU32)));
    MacExpr::new(e)
}

struct Ident {
    ident: ast::Ident,
    span: Span
}

fn parse_tts(cx: &ExtCtxt,
             tts: &[ast::TokenTree]) -> (P<ast::Expr>, Option<Ident>) {
    let p = &mut cx.new_parser_from_tts(tts);
    let ex = p.parse_expr();
    let id = if p.token == token::EOF {
        None
    } else {
        p.expect(&token::COMMA);
        let lo = p.span.lo;
        let ident = p.parse_ident();
        let hi = p.last_span.hi;
        Some(Ident{ident: ident, span: mk_sp(lo, hi)})
    };
    if p.token != token::EOF {
        p.unexpected();
    }
    (ex, id)
}

fn target_endian_little(cx: &ExtCtxt, sp: Span) -> bool {
    let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
        ast::LitStr(InternedString::new("little"), ast::CookedStr));
    contains(cx.cfg().as_slice(), &*meta)
}

// FIXME (10872): This is required to prevent an LLVM assert on Windows
#[test]
fn dummy_test() { }
<commit_msg>Update to rust master<commit_after>// Copyright 2014 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.

/*!
Syntax extension to generate FourCCs.

Once loaded, fourcc!() is called with a single 4-character string,
and an optional ident that is either `big`, `little`, or `target`.
The ident represents endianness, and specifies in which direction
the characters should be read. If the ident is omitted, it is assumed
to be `big`, i.e. left-to-right order. It returns a u32.

# Examples

To load the extension and use it:

```rust,ignore
#[phase(plugin)]
extern crate fourcc;

fn main() {
    let val = fourcc!("\xC0\xFF\xEE!");
    assert_eq!(val, 0xC0FFEE21u32);
    let little_val = fourcc!("foo ", little);
    assert_eq!(little_val, 0x21EEFFC0u32);
}
```

# References

* [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)

*/

#![crate_name = "fourcc"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico")]

#![feature(plugin_registrar)]

extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::attr::contains;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
use rustc::plugin::Registry;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("fourcc", expand_syntax_ext);
}

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                         -> Box<base::MacResult + 'static> {
    let (expr, endian) = parse_tts(cx, tts);

    let little = match endian {
        None => false,
        Some(Ident{ident, span}) => match token::get_ident(ident).get() {
            "little" => true,
            "big" => false,
            "target" => target_endian_little(cx, sp),
            _ => {
                cx.span_err(span, "invalid endian directive in fourcc!");
                target_endian_little(cx, sp)
            }
        }
    };

    let s = match expr.node {
        // expression is a literal
        ast::ExprLit(ref lit) => match lit.node {
            // string literal
            ast::LitStr(ref s, _) => {
                if s.get().char_len() != 4 {
                    cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
                }
                s
            }
            _ => {
                cx.span_err(expr.span, "unsupported literal in fourcc!");
                return base::DummyResult::expr(sp)
            }
        },
        _ => {
            cx.span_err(expr.span, "non-literal in fourcc!");
            return base::DummyResult::expr(sp)
        }
    };

    let mut val = 0u32;
    for codepoint in s.get().chars().take(4) {
        let byte = if codepoint as u32 > 0xFF {
            cx.span_err(expr.span, "fourcc! literal character out of range 0-255");
            0u8
        } else {
            codepoint as u8
        };

        val = if little {
            (val >> 8) | ((byte as u32) << 24)
        } else {
            (val << 8) | (byte as u32)
        };
    }
    let e = cx.expr_lit(sp, ast::LitInt(val as u64, ast::UnsignedIntLit(ast::TyU32)));
    MacExpr::new(e)
}

struct Ident {
    ident: ast::Ident,
    span: Span
}

fn parse_tts(cx: &ExtCtxt,
             tts: &[ast::TokenTree]) -> (P<ast::Expr>, Option<Ident>) {
    let p = &mut cx.new_parser_from_tts(tts);
    let ex = p.parse_expr();
    let id = if p.token == token::Eof {
        None
    } else {
        p.expect(&token::Comma);
        let lo = p.span.lo;
        let ident = p.parse_ident();
        let hi = p.last_span.hi;
        Some(Ident{ident: ident, span: mk_sp(lo, hi)})
    };
    if p.token != token::Eof {
        p.unexpected();
    }
    (ex, id)
}

fn target_endian_little(cx: &ExtCtxt, sp: Span) -> bool {
    let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
        ast::LitStr(InternedString::new("little"), ast::CookedStr));
    contains(cx.cfg().as_slice(), &*meta)
}

// FIXME (10872): This is required to prevent an LLVM assert on Windows
#[test]
fn dummy_test() { }
<|endoftext|>


<commit_before>#![cfg(any(unix, windows))]

/// Allocates `size` Bytes aligned to `align` Bytes. Returns a null pointer on allocation failure.
///
/// The returned pointer must be deallocated by using `aligned_free`.
///
/// Note: This function is meant to be used for infrequent large allocations (as `malloc` already
/// guarantees suitable alignment for all native datatypes) and might be quite slow when used
/// heavily.
///
/// # Parameters
///
/// * `size`: The size of the allocation in bytes.
/// * `align`: The alignment of the allocation (at least the size of `usize` on the current
///   platform). Must also be a power of two.
#[inline]
pub fn aligned_alloc(size: usize, align: usize) -> *mut () {
    imp::aligned_alloc(size, align)
}

/// Deallocates aligned memory that was allocated with `aligned_alloc`. Unsafe because calling this
/// with a pointer that was not allocated with `aligned_alloc` (or already released) causes
/// undefined behavior.
#[inline]
pub unsafe fn aligned_free(ptr: *mut ()) {
    imp::aligned_free(ptr)
}

#[cfg(unix)]
mod imp {
    extern crate libc;

    use self::libc::{c_void, c_int, size_t, EINVAL, ENOMEM, free};

    use std::{mem, ptr};

    extern "C" {
        fn posix_memalign(memptr: *mut *mut c_void, alignment: size_t, size: size_t) -> c_int;
    }

    pub fn aligned_alloc(size: usize, align: usize) -> *mut () {
        let mut memptr: *mut c_void = ptr::null_mut();
        let result = unsafe { posix_memalign(&mut memptr, align as size_t, size as size_t) };
        match result {
            0 => return memptr as *mut (),
            EINVAL => {
                if align < mem::size_of::<usize>() {
                    panic!("EINVAL: invalid alignment: {} (minimum is {})", align,
                        mem::size_of::<usize>());
                }
                if !align.is_power_of_two() {
                    panic!("EINVAL: invalid alignment: {} (must be a power of two)", align)
                }
                panic!("EINVAL: invalid alignment: {}", align);
            }
            ENOMEM => return ptr::null_mut(),
            _ => unreachable!(),
        }
    }

    #[inline]
    pub unsafe fn aligned_free(ptr: *mut ()) {
        free(ptr as *mut c_void)
    }
}

#[cfg(windows)]
mod imp {
    extern crate winapi;
    extern crate kernel32;

    use self::kernel32::{GetLastError, GetSystemInfo, VirtualAlloc, VirtualFree};
    use self::winapi::{MEM_COMMIT, MEM_RESERVE, MEM_RELEASE, PAGE_NOACCESS, PAGE_READWRITE, SIZE_T,
        LPVOID, DWORD, SYSTEM_INFO};

    use std::mem;
    use std::ptr;

    static mut PAGE_SIZE: DWORD = 0;

    #[cold]
    fn get_page_size() {
        let mut info: SYSTEM_INFO = unsafe { mem::uninitialized() };
        unsafe { GetSystemInfo(&mut info); }

        unsafe {
            PAGE_SIZE = info.dwPageSize;
        }
    }

    pub fn aligned_alloc(size: usize, align: usize) -> *mut () {
        assert!(align.is_power_of_two(), "align must be a power of two");
        assert!(align >= mem::size_of::<usize>(), "align must be at least as large as a usize");

        if unsafe { PAGE_SIZE } == 0 { get_page_size() }

        unsafe {
            if align <= PAGE_SIZE as usize {
                // Page alignment is guaranteed by `VirtualAlloc`
                let ptr = VirtualAlloc(ptr::null_mut(), size as SIZE_T, MEM_COMMIT | MEM_RESERVE,
                    PAGE_READWRITE);
                return ptr as *mut ()
            }

            // Step 1: Reserve `size+align-1` Bytes of address space to find a suitable address
            let ptr = VirtualAlloc(ptr::null_mut(), (size + align - 1) as SIZE_T, MEM_RESERVE,
                PAGE_NOACCESS);
            if ptr.is_null() { return ptr::null_mut() }

            // Step 2: Calculate an aligned address within the reserved range
            // (this works because `align` must be a power of two)
            let aligned_ptr = (ptr as usize + align - 1) & !(align - 1);

            // Step 3: Actually allocate (commit) the memory
            let res = VirtualFree(ptr as LPVOID, 0, MEM_RELEASE);
            if res == 0 {
                panic!("WINAPI error {} while freeing reserved memory", GetLastError());
            }
            let ptr = VirtualAlloc(aligned_ptr as LPVOID, size as SIZE_T, MEM_COMMIT | MEM_RESERVE,
                PAGE_READWRITE);
            ptr as *mut ()
        }
    }

    pub unsafe fn aligned_free(ptr: *mut ()) {
        let res = VirtualFree(ptr as LPVOID, 0, MEM_RELEASE);
        if res == 0 {
            panic!("WINAPI error {} while releasing memory", GetLastError());
        }
    }
}

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

    #[test]
    fn small_low_align() {
        let ptr = aligned_alloc(1, 128);
        assert!(!ptr.is_null());
        assert!(ptr as usize % 128 == 0);
        unsafe { aligned_free(ptr) }
    }

    #[test]
    fn small_high_align() {
        let ptr = aligned_alloc(1, 1024 * 1024);
        assert!(!ptr.is_null());
        assert!(ptr as usize % (1024 * 1024) == 0);
        unsafe { aligned_free(ptr) }
    }

    #[test]
    fn large_high_align() {
        // allocate 1 MiB aligned to 1 MiB
        let ptr = aligned_alloc(1024 * 1024, 1024 * 1024);
        assert!(!ptr.is_null());
        assert!(ptr as usize % (1024 * 1024) == 0);
        unsafe { aligned_free(ptr) }
    }

    #[test]
    #[should_panic]
    fn align_less_than_sizeof_usize() {
        // alignment of less than sizeof(usize)
        aligned_alloc(1, 2);
    }

    #[test]
    #[should_panic]
    fn align_not_power_of_two() {
        aligned_alloc(1, 27);
    }

    #[test]
    #[should_panic]
    fn align_zero() {
        aligned_alloc(1, 0);
    }
}
<commit_msg>replace blatant unsafety with atomic static<commit_after>#![cfg(any(unix, windows))]

/// Allocates `size` Bytes aligned to `align` Bytes. Returns a null pointer on allocation failure.
///
/// The returned pointer must be deallocated by using `aligned_free`.
///
/// Note: This function is meant to be used for infrequent large allocations (as `malloc` already
/// guarantees suitable alignment for all native datatypes) and might be quite slow when used
/// heavily.
///
/// # Parameters
///
/// * `size`: The size of the allocation in bytes.
/// * `align`: The alignment of the allocation (at least the size of `usize` on the current
///   platform). Must also be a power of two.
#[inline]
pub fn aligned_alloc(size: usize, align: usize) -> *mut () {
    imp::aligned_alloc(size, align)
}

/// Deallocates aligned memory that was allocated with `aligned_alloc`. Unsafe because calling this
/// with a pointer that was not allocated with `aligned_alloc` (or already released) causes
/// undefined behavior.
#[inline]
pub unsafe fn aligned_free(ptr: *mut ()) {
    imp::aligned_free(ptr)
}

#[cfg(unix)]
mod imp {
    extern crate libc;

    use self::libc::{c_void, c_int, size_t, EINVAL, ENOMEM, free};

    use std::{mem, ptr};

    extern "C" {
        fn posix_memalign(memptr: *mut *mut c_void, alignment: size_t, size: size_t) -> c_int;
    }

    pub fn aligned_alloc(size: usize, align: usize) -> *mut () {
        let mut memptr: *mut c_void = ptr::null_mut();
        let result = unsafe { posix_memalign(&mut memptr, align as size_t, size as size_t) };
        match result {
            0 => return memptr as *mut (),
            EINVAL => {
                if align < mem::size_of::<usize>() {
                    panic!("EINVAL: invalid alignment: {} (minimum is {})", align,
                        mem::size_of::<usize>());
                }
                if !align.is_power_of_two() {
                    panic!("EINVAL: invalid alignment: {} (must be a power of two)", align)
                }
                panic!("EINVAL: invalid alignment: {}", align);
            }
            ENOMEM => return ptr::null_mut(),
            _ => unreachable!(),
        }
    }

    #[inline]
    pub unsafe fn aligned_free(ptr: *mut ()) {
        free(ptr as *mut c_void)
    }
}

#[cfg(windows)]
mod imp {
    extern crate winapi;
    extern crate kernel32;

    use self::kernel32::{GetLastError, GetSystemInfo, VirtualAlloc, VirtualFree};
    use self::winapi::{MEM_COMMIT, MEM_RESERVE, MEM_RELEASE, PAGE_NOACCESS, PAGE_READWRITE, SIZE_T,
        LPVOID, SYSTEM_INFO};

    use std::mem;
    use std::ptr;
    use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};

    static PAGE_SIZE: AtomicUsize = ATOMIC_USIZE_INIT;

    #[cold]
    fn get_page_size() {
        let mut info: SYSTEM_INFO = unsafe { mem::uninitialized() };
        unsafe { GetSystemInfo(&mut info); }

        PAGE_SIZE.store(info.dwPageSize as usize, Ordering::SeqCst);
    }

    pub fn aligned_alloc(size: usize, align: usize) -> *mut () {
        assert!(align.is_power_of_two(), "align must be a power of two");
        assert!(align >= mem::size_of::<usize>(), "align must be at least as large as a usize");

        if PAGE_SIZE.load(Ordering::SeqCst) == 0 {
            get_page_size();
        }

        unsafe {
            if align <= PAGE_SIZE.load(Ordering::SeqCst) {
                // Page alignment is guaranteed by `VirtualAlloc`
                let ptr = VirtualAlloc(ptr::null_mut(), size as SIZE_T, MEM_COMMIT | MEM_RESERVE,
                    PAGE_READWRITE);
                return ptr as *mut ()
            }

            // Step 1: Reserve `size+align-1` Bytes of address space to find a suitable address
            let ptr = VirtualAlloc(ptr::null_mut(), (size + align - 1) as SIZE_T, MEM_RESERVE,
                PAGE_NOACCESS);
            if ptr.is_null() { return ptr::null_mut() }

            // Step 2: Calculate an aligned address within the reserved range
            // (this works because `align` must be a power of two)
            let aligned_ptr = (ptr as usize + align - 1) & !(align - 1);

            // Step 3: Actually allocate (commit) the memory
            let res = VirtualFree(ptr as LPVOID, 0, MEM_RELEASE);
            if res == 0 {
                panic!("WINAPI error {} while freeing reserved memory", GetLastError());
            }
            let ptr = VirtualAlloc(aligned_ptr as LPVOID, size as SIZE_T, MEM_COMMIT | MEM_RESERVE,
                PAGE_READWRITE);
            ptr as *mut ()
        }
    }

    pub unsafe fn aligned_free(ptr: *mut ()) {
        let res = VirtualFree(ptr as LPVOID, 0, MEM_RELEASE);
        if res == 0 {
            panic!("WINAPI error {} while releasing memory", GetLastError());
        }
    }
}

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

    #[test]
    fn small_low_align() {
        let ptr = aligned_alloc(1, 128);
        assert!(!ptr.is_null());
        assert!(ptr as usize % 128 == 0);
        unsafe { aligned_free(ptr) }
    }

    #[test]
    fn small_high_align() {
        let ptr = aligned_alloc(1, 1024 * 1024);
        assert!(!ptr.is_null());
        assert!(ptr as usize % (1024 * 1024) == 0);
        unsafe { aligned_free(ptr) }
    }

    #[test]
    fn large_high_align() {
        // allocate 1 MiB aligned to 1 MiB
        let ptr = aligned_alloc(1024 * 1024, 1024 * 1024);
        assert!(!ptr.is_null());
        assert!(ptr as usize % (1024 * 1024) == 0);
        unsafe { aligned_free(ptr) }
    }

    #[test]
    #[should_panic]
    fn align_less_than_sizeof_usize() {
        // alignment of less than sizeof(usize)
        aligned_alloc(1, 2);
    }

    #[test]
    #[should_panic]
    fn align_not_power_of_two() {
        aligned_alloc(1, 27);
    }

    #[test]
    #[should_panic]
    fn align_zero() {
        aligned_alloc(1, 0);
    }
}
<|endoftext|>


<commit_before>
#![allow(dead_code)]

pub extern crate crypto;

use crypto::digest::Digest;

pub trait Hashable {
    fn to_bytes(&self) -> Vec<u8>;
}

impl Hashable for String {
    fn to_bytes(&self) -> Vec<u8> {
        self.clone().into_bytes()
    }
}

impl Hashable for u8 {
    fn to_bytes(&self) -> Vec<u8> {
        vec![*self]
    }
}

pub trait MerkleDigest {
    fn hash_bytes(&mut self, bytes: &Vec<u8>) -> Vec<u8>;
    fn combine_hashes(&mut self, left: &Vec<u8>, right: &Vec<u8>) -> Vec<u8>;
}

impl <D> MerkleDigest for D where D: Digest {

    fn hash_bytes(&mut self, bytes: &Vec<u8>) -> Vec<u8> {
        let mut hash = vec![0; self.output_bytes()];

        self.reset();
        self.input(bytes);
        self.result(&mut hash);
        self.reset();

        hash
    }

    fn combine_hashes(&mut self, left: &Vec<u8>, right: &Vec<u8>) -> Vec<u8> {
        let mut hash = vec![0; self.output_bytes()];

        self.reset();
        self.input(left);
        self.input(right);
        self.result(&mut hash);
        self.reset();

        hash
    }

}

enum Tree<T> {
    Leaf {
        hash: Vec<u8>,
        value: T
    },

    Node {
        hash: Vec<u8>,
        left: Box<Tree<T>>,
        right: Box<Tree<T>>
    }
}

impl <T> Tree<T> where T: Hashable {

    fn new(hash: Vec<u8>, value: T) -> Self {
        Tree::Leaf {
            hash: hash,
            value: value
        }
    }

    fn get_hash(&self) -> &Vec<u8> {
        match *self {
            Tree::Leaf { ref hash, value: _ }          => hash,
            Tree::Node { ref hash, left: _, right: _ } => hash
        }
    }
}

fn make_leaf<D, T>(digest: &mut D, value: T) -> Tree<T> where D: Digest, T: Hashable {
    let hash = digest.hash_bytes(&value.to_bytes());
    Tree::new(hash, value)
}

pub struct MerkleTree<D, T> where D: Digest, T: Hashable {
    digest: D,
    tree: Tree<T>
}

impl <D, T> MerkleTree<D, T> where D: Digest, T: Hashable {

    pub fn from_vec(mut digest: D, values: Vec<T>) -> Self {
        if values.is_empty() {
            panic!("Cannot build a Merkle tree from an empty vector.");
        }

        let len = values.len();
        let mut cur = Vec::with_capacity(len);

        for v in values {
            let leaf = make_leaf(&mut digest, v);
            cur.push(leaf);
        }

        cur.reverse();

        while cur.len() > 1 {
            let mut next = Vec::with_capacity(len);

            while cur.len() > 0 {
                if cur.len() == 1 {
                    next.push(cur.pop().unwrap());
                }
                else {
                    let right = cur.pop().unwrap();
                    let left  = cur.pop().unwrap();

                    let combined_hash = digest.combine_hashes(
                        left.get_hash(),
                        right.get_hash()
                    );

                    let node = Tree::Node {
                       hash: combined_hash,
                       left: Box::new(left),
                       right: Box::new(right)
                    };

                    next.push(node);
                }
            }

            cur = next;
        }

        let tree = cur.remove(0);

        MerkleTree {
            digest: digest,
            tree: tree
        }
    }

}

#[cfg(test)]
use crypto::sha3::Sha3;

#[test]
fn test_stuff() {
}

#[cfg(test)]
pub mod tests;
<commit_msg>Add height, count and root_hash to MerkleTree.<commit_after>
#![allow(dead_code)]

pub extern crate crypto;

use crypto::digest::Digest;

pub trait Hashable {
    fn to_bytes(&self) -> Vec<u8>;
}

impl Hashable for String {
    fn to_bytes(&self) -> Vec<u8> {
        self.clone().into_bytes()
    }
}

impl Hashable for u8 {
    fn to_bytes(&self) -> Vec<u8> {
        vec![*self]
    }
}

pub trait MerkleDigest {
    fn hash_bytes(&mut self, bytes: &Vec<u8>) -> Vec<u8>;
    fn combine_hashes(&mut self, left: &Vec<u8>, right: &Vec<u8>) -> Vec<u8>;
}

impl <D> MerkleDigest for D where D: Digest {

    fn hash_bytes(&mut self, bytes: &Vec<u8>) -> Vec<u8> {
        let mut hash = vec![0; self.output_bytes()];

        self.reset();
        self.input(bytes);
        self.result(&mut hash);
        self.reset();

        hash
    }

    fn combine_hashes(&mut self, left: &Vec<u8>, right: &Vec<u8>) -> Vec<u8> {
        let mut hash = vec![0; self.output_bytes()];

        self.reset();
        self.input(left);
        self.input(right);
        self.result(&mut hash);
        self.reset();

        hash
    }

}

enum Tree<T> {
    Leaf {
        hash: Vec<u8>,
        value: T
    },

    Node {
        hash: Vec<u8>,
        left: Box<Tree<T>>,
        right: Box<Tree<T>>
    }
}

impl <T> Tree<T> where T: Hashable {

    fn new(hash: Vec<u8>, value: T) -> Self {
        Tree::Leaf {
            hash: hash,
            value: value
        }
    }

    fn get_hash(&self) -> &Vec<u8> {
        match *self {
            Tree::Leaf { ref hash, value: _ }          => hash,
            Tree::Node { ref hash, left: _, right: _ } => hash
        }
    }
}

fn make_leaf<D, T>(digest: &mut D, value: T) -> Tree<T> where D: Digest, T: Hashable {
    let hash = digest.hash_bytes(&value.to_bytes());
    Tree::new(hash, value)
}

pub struct MerkleTree<D, T> where D: Digest, T: Hashable {
    digest: D,
    tree: Tree<T>,
    height: usize,
    count: usize
}

impl <D, T> MerkleTree<D, T> where D: Digest, T: Hashable {

    pub fn from_vec(mut digest: D, values: Vec<T>) -> Self {
        if values.is_empty() {
            panic!("Cannot build a Merkle tree from an empty vector.");
        }

        let count  = values.len();
        let height = (count as f32 + 1.0).log2().ceil() as usize;

        let mut cur = Vec::with_capacity(count);

        for v in values.into_iter().rev() {
            let leaf = make_leaf(&mut digest, v);
            cur.push(leaf);
        }

        for i in 0 .. height {
            let mut next = Vec::with_capacity(height / 2 << i);

            while cur.len() > 0 {
                if cur.len() == 1 {
                    next.push(cur.pop().unwrap());
                }
                else {
                    let right = cur.pop().unwrap();
                    let left  = cur.pop().unwrap();

                    let combined_hash = digest.combine_hashes(
                        left.get_hash(),
                        right.get_hash()
                    );

                    let node = Tree::Node {
                       hash: combined_hash,
                       left: Box::new(left),
                       right: Box::new(right)
                    };

                    next.push(node);
                }
            }

            cur = next;
        }

        assert!(cur.len() == 1);

        let tree = cur.remove(0);

        MerkleTree {
            digest: digest,
            tree: tree,
            height: height,
            count: count
        }
    }

    fn root_hash(&self) -> &Vec<u8> {
        self.tree.get_hash()
    }

}

#[cfg(test)]
mod tests;

<|endoftext|>