<commit_before>#![feature(plugin)]
#![plugin(clippy)]

#[macro_use]
extern crate nom;

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

use error::*;

// 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 enum Sexp {
    String(String),
    List(Vec<Sexp>),
    Empty,
}

impl Sexp {

    pub fn new_empty() -> Sexp {
        Sexp::Empty
    }

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

    pub fn list(&self) -> Result<&Vec<Sexp> > {
        match *self {
            Sexp::List(ref v) => Ok(v),
            _ => str_error(format!("not a list: {}", self))
        }
    }

    pub fn string(&self) -> Result<&String> {
        match *self {
            Sexp::String(ref s) => Ok(s),
            _ => str_error(format!("not a string: {}", self))
        }
    }

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

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

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

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

    pub fn named_value(&self, s:&str) -> Result<&Sexp> {
        let v = try!(self.list());
        if v.len() != 2 {
            return str_error(format!("list {} is not a named_value", s))
        }
        let l = try!(self.slice_atom(s));
        Ok(&l[0])
    }

    pub fn named_value_i(&self, s:&str) -> Result<i64> {
        try!(self.named_value(s)).i()
    }

    pub fn named_value_f(&self, s:&str) -> Result<f64> {
        try!(self.named_value(s)).f()
    }

    pub fn named_value_string(&self, s:&str) -> Result<&String> {
        try!(self.named_value(s)).string()
    }

    pub fn slice_atom_num(&self, s:&str, num:usize) -> Result<&[Sexp]> {
        let v = try!(self.list());
        let v2 =&v[..];
        let st = try!(v2[0].string());
        if st != s {
            return str_error(format!("list doesn't start with {}, but with {}", s, st))
        };
        if v.len() != (num+1) {
            return str_error(format!("list ({}) doesn't have {} elements but {}", s, num, v.len()-1))
        }
        Ok(&v[1..])
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
        match *self {
            Sexp::String(ref s) => {
                if s.contains('(') || s.contains(' ') {
                    write!(f,"\"{}\"", s)
                } else {
                    write!(f,"{}", s)
                }
            },
            Sexp::List(ref v) => {
                try!(write!(f, "("));
                let l = v.len();
                for (i,x) in v.iter().enumerate() {
                    if i < l-1 {
                        try!(write!(f, "{} ", x));
                    } else {
                        try!(write!(f, "{}", x));
                    }
                }
                write!(f, ")")
            },
            Sexp::Empty => Ok(())
        }
    }
}

pub fn display_string(s:&str) -> String {
    if s.contains('(') || s.contains(' ') || s.is_empty() {
        format!("\"{}\"", s)
    } else {
        String::from(s)
    }
}

pub fn parse_str(sexp: &str) -> Result<Sexp> {
    if sexp.is_empty() {
        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) =>
                    str_error(format!("parse error: {:?} |{}|", kind, str::from_utf8(p).unwrap())),
                _ => str_error("parse error".to_string())
            }
        },
        nom::IResult::Incomplete(x) => str_error(format!("incomplete: {:?}", x)),
    }
}

fn read_file(name: &str) -> std::result::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) -> Result<Sexp> {
    let s = try!(match read_file(name) {
        Ok(s) => Ok(s),
        Err(x) => str_error(format!("{:?}", x))
    });
    parse_str(&s[..])
}

pub fn to_writer<W>(writer: &mut W, value: &Sexp) -> Result<()>
    where W: io::Write
{
    //let mut ser = Serializer::new(writer);
    //try!(value.serialize(&mut ser));
    // TODO
    Ok(())
}

pub fn to_vec(value:&Sexp) -> Result<Vec<u8>> {
    let mut writer = Vec::with_capacity(128);
    try!(to_writer(&mut writer, value));
    Ok(writer)
}

pub fn to_string(value:&Sexp) -> Result<String> {
    let vec = try!(to_vec(value));
    let string = try!(String::from_utf8(vec));
    Ok(string)
}

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<Sexp>,
       map!(alt!(parse_qstring | parse_bare_string), |x| Sexp::String(x))
       );

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

// 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) ~
                   sexp: alt!(parse_list | parse_string) ~
                   _nl: line_ending
                   ,
               || {
                   sexp
               })
       );

// internal tests
#[test]
fn test_qstring1() {
    let x = parse_string(&b"\"hello world\""[..]);
    match x {
        nom::IResult::Done(_,y) => {
            match y {
                Sexp::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();
    }

    #[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: Other(\"incomplete: Size(2)\")")]
    fn test_invalid1() { parse_fail("(") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: Other(\"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_fail_pcb() {
        check_parse("\
(kicad_pcb (version 4) (host pcbnew \"(2015-05-31 BZR 5692)-product\")
  (general
  )
)")
    }
}

pub mod error;
<commit_msg>use formatter (thanks serde-json for the idea)<commit_after>#![feature(plugin)]
#![plugin(clippy)]

#[macro_use]
extern crate nom;

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

use error::*;

// 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 enum Sexp {
    String(String),
    List(Vec<Sexp>),
    Empty,
}

impl Sexp {

    pub fn new_empty() -> Sexp {
        Sexp::Empty
    }

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

    pub fn list(&self) -> Result<&Vec<Sexp> > {
        match *self {
            Sexp::List(ref v) => Ok(v),
            _ => str_error(format!("not a list: {}", self))
        }
    }

    pub fn string(&self) -> Result<&String> {
        match *self {
            Sexp::String(ref s) => Ok(s),
            _ => str_error(format!("not a string: {}", self))
        }
    }

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

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

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

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

    pub fn named_value(&self, s:&str) -> Result<&Sexp> {
        let v = try!(self.list());
        if v.len() != 2 {
            return str_error(format!("list {} is not a named_value", s))
        }
        let l = try!(self.slice_atom(s));
        Ok(&l[0])
    }

    pub fn named_value_i(&self, s:&str) -> Result<i64> {
        try!(self.named_value(s)).i()
    }

    pub fn named_value_f(&self, s:&str) -> Result<f64> {
        try!(self.named_value(s)).f()
    }

    pub fn named_value_string(&self, s:&str) -> Result<&String> {
        try!(self.named_value(s)).string()
    }

    pub fn slice_atom_num(&self, s:&str, num:usize) -> Result<&[Sexp]> {
        let v = try!(self.list());
        let v2 =&v[..];
        let st = try!(v2[0].string());
        if st != s {
            return str_error(format!("list doesn't start with {}, but with {}", s, st))
        };
        if v.len() != (num+1) {
            return str_error(format!("list ({}) doesn't have {} elements but {}", s, num, v.len()-1))
        }
        Ok(&v[1..])
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
        match *self {
            Sexp::String(ref s) => {
                if s.contains('(') || s.contains(' ') {
                    write!(f,"\"{}\"", s)
                } else {
                    write!(f,"{}", s)
                }
            },
            Sexp::List(ref v) => {
                try!(write!(f, "("));
                let l = v.len();
                for (i,x) in v.iter().enumerate() {
                    if i < l-1 {
                        try!(write!(f, "{} ", x));
                    } else {
                        try!(write!(f, "{}", x));
                    }
                }
                write!(f, ")")
            },
            Sexp::Empty => Ok(())
        }
    }
}

pub trait Formatter {
    /// Called when serializing a '('.
    fn open<W>(&mut self, writer: &mut W) -> Result<()>
        where W: io::Write;

    /// Called when serializing a ' '.
    fn space<W>(&mut self, writer: &mut W, first:bool) -> Result<()>
        where W: io::Write;

    /// Called when serializing a ')'.
    fn close<W>(&mut self, writer: &mut W) -> Result<()>
        where W: io::Write;
}

pub struct CompactFormatter;

impl Formatter for CompactFormatter {
    fn open<W>(&mut self, writer: &mut W) -> Result<()>
        where W: io::Write
    {
        writer.write_all(b"(").map_err(From::from)
    }
    fn space<W>(&mut self, writer: &mut W, first:bool) -> Result<()>
        where W: io::Write
    {
        if first {
            Ok(())
        } else {
            writer.write_all(b" ").map_err(From::from)
        }
    }
    fn close<W>(&mut self, writer: &mut W) -> Result<()>
        where W: io::Write
    {
        writer.write_all(b")").map_err(From::from)
    }
}

pub struct Serializer<W, F=CompactFormatter> {
    writer: W,
    formatter: F,

    /// `first` is used to signify if we should print a comma when we are walking through a
    /// sequence.
    first: bool,
}

// dispatches only based on Formatter
impl<W> Serializer<W>
    where W: io::Write,
{
    pub fn new(writer: W) -> Self {
        Serializer::with_formatter(writer, CompactFormatter)
    }
}

impl<W, F> Serializer<W, F>
    where W: io::Write,
          F: Formatter,
{
    pub fn with_formatter(writer: W, formatter: F) -> Self {
        Serializer {
            writer: writer,
            formatter: formatter,
            first: false,
        }
    }

    fn serialize_str(&mut self, value:&str) -> Result<()> {
        if value.contains('(') || value.contains(' ') {
            write!(&mut self.writer, "\"{}\"", value).map_err(From::from)
        } else {
            write!(&mut self.writer, "{}", value).map_err(From::from)
        }
    }

    fn serialize(&mut self, value:&Sexp) -> Result<()> {
        match *value {
            Sexp::String(ref s) => {
                self.serialize_str(s)
            },
            Sexp::List(ref list) => {
                try!(self.formatter.open(&mut self.writer));
                let mut first = true;
                for v in list {
                    try!(self.formatter.space(&mut self.writer, first));
                    first = false;
                    try!(self.serialize(v));
                }
                self.formatter.close(&mut self.writer)
            },
            Sexp::Empty => Ok(()),
        }

    }
}

pub fn display_string(s:&str) -> String {
    if s.contains('(') || s.contains(' ') || s.is_empty() {
        format!("\"{}\"", s)
    } else {
        String::from(s)
    }
}

pub fn parse_str(sexp: &str) -> Result<Sexp> {
    if sexp.is_empty() {
        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) =>
                    str_error(format!("parse error: {:?} |{}|", kind, str::from_utf8(p).unwrap())),
                _ => str_error("parse error".to_string())
            }
        },
        nom::IResult::Incomplete(x) => str_error(format!("incomplete: {:?}", x)),
    }
}

fn read_file(name: &str) -> std::result::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) -> Result<Sexp> {
    let s = try!(match read_file(name) {
        Ok(s) => Ok(s),
        Err(x) => str_error(format!("{:?}", x))
    });
    parse_str(&s[..])
}

pub fn to_writer<W>(writer: &mut W, value: &Sexp) -> Result<()>
    where W: io::Write
{
    let mut ser = Serializer::new(writer);
    ser.serialize(value)
}

pub fn to_vec(value:&Sexp) -> Result<Vec<u8>> {
    let mut writer = Vec::with_capacity(128);
    try!(to_writer(&mut writer, value));
    Ok(writer)
}

pub fn to_string(value:&Sexp) -> Result<String> {
    let vec = try!(to_vec(value));
    let string = try!(String::from_utf8(vec));
    Ok(string)
}

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<Sexp>,
       map!(alt!(parse_qstring | parse_bare_string), |x| Sexp::String(x))
       );

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

// 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) ~
                   sexp: alt!(parse_list | parse_string) ~
                   _nl: line_ending
                   ,
               || {
                   sexp
               })
       );

// internal tests
#[test]
fn test_qstring1() {
    let x = parse_string(&b"\"hello world\""[..]);
    match x {
        nom::IResult::Done(_,y) => {
            match y {
                Sexp::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 = to_string(&e).unwrap();
        assert_eq!(o, t)
    }

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

    #[allow(dead_code)]
    fn parse_fail(s: &str) {
        parse_str(s).unwrap();
    }

    #[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: Other(\"incomplete: Size(2)\")")]
    fn test_invalid1() { parse_fail("(") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: Other(\"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_fail_pcb() {
        check_parse("\
(kicad_pcb (version 4) (host pcbnew \"(2015-05-31 BZR 5692)-product\")
  (general
  )
)")
    }
}

pub mod error;
<|endoftext|>


<commit_before>#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/7853871?s=128", html_favicon_url = "https://avatars0.githubusercontent.com/u/7853871?s=256", html_root_url = "http://ironframework.io/core/iron")]
#![crate_name = "iron"]
#![comment = "Rapid Web Development in Rust"]
#![license = "MIT"]

#![deny(missing_docs)]
#![deny(warnings)]

#![feature(macro_rules, phase, globs, unboxed_closures, slicing_syntax)]

//! The main crate for the Iron library.
//!
//! Iron is a high level web framework built in and for Rust.
//!
//! Iron provides a robust and efficient framework
//! for creating and plugging in middleware.
//!
//! Obligatory Hello World:
//!
//! ```ignore
//! fn hello_world(req: &mut Request) -> IronResult<Response> {
//!   Response::new().set(Status(status::Ok)).set(Body("Hello World!"))
//! }
//!
//! Iron::new(hello_world).listen(Ipv4Addr(127, 0, 0, 1), 3000);
//! ```

// Stdlib dependencies
#[phase(plugin, link)] extern crate log;
#[cfg(test)] extern crate test;
extern crate serialize;

// Third party packages
extern crate content_type;
extern crate http;
extern crate "typemap" as tmap;
extern crate plugin;
extern crate modifier;
extern crate error;
extern crate taskpool;
extern crate "url" as rust_url;

// Request + Response
pub use request::{Request, Url};
pub use response::Response;

// Middleware system
pub use middleware::{BeforeMiddleware, AfterMiddleware, AroundMiddleware,
                     Handler, Chain, ChainBuilder};

// Server
pub use iron::Iron;

// Extensions
pub use typemap::TypeMap;

// Status codes and Methods.
pub use http::status;
pub use http::method;

// Headers
pub use http::headers;

// Expose `GetCached` as `Plugin` so users can do `use iron::Plugin`.
pub use plugin::GetCached as Plugin;

// Expose modifiers.
pub use modifier::Set;

// Errors
pub use error::{Error, ErrorRefExt};

// Return type of many methods
pub type IronError = Box<Error>;
pub type IronResult<T> = Result<T, IronError>;

/// Re-exports from the TypeMap crate.
pub mod typemap {
    pub use tmap::{TypeMap, Assoc};
}

// Publicized to show the documentation
pub mod middleware;

// Common Errors
pub mod errors;

// Response utilities
pub mod response;

// Internal modules
mod request;
mod iron;

<commit_msg>(feat) Re-export all items from modifier.<commit_after>#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/7853871?s=128", html_favicon_url = "https://avatars0.githubusercontent.com/u/7853871?s=256", html_root_url = "http://ironframework.io/core/iron")]
#![crate_name = "iron"]
#![comment = "Rapid Web Development in Rust"]
#![license = "MIT"]

#![deny(missing_docs)]
#![deny(warnings)]

#![feature(macro_rules, phase, globs, unboxed_closures, slicing_syntax)]

//! The main crate for the Iron library.
//!
//! Iron is a high level web framework built in and for Rust.
//!
//! Iron provides a robust and efficient framework
//! for creating and plugging in middleware.
//!
//! Obligatory Hello World:
//!
//! ```ignore
//! fn hello_world(req: &mut Request) -> IronResult<Response> {
//!   Response::new().set(Status(status::Ok)).set(Body("Hello World!"))
//! }
//!
//! Iron::new(hello_world).listen(Ipv4Addr(127, 0, 0, 1), 3000);
//! ```

// Stdlib dependencies
#[phase(plugin, link)] extern crate log;
#[cfg(test)] extern crate test;
extern crate serialize;

// Third party packages
extern crate content_type;
extern crate http;
extern crate "typemap" as tmap;
extern crate plugin;
extern crate "modifier" as modfier;
extern crate error;
extern crate taskpool;
extern crate "url" as rust_url;

// Request + Response
pub use request::{Request, Url};
pub use response::Response;

// Middleware system
pub use middleware::{BeforeMiddleware, AfterMiddleware, AroundMiddleware,
                     Handler, Chain, ChainBuilder};

// Server
pub use iron::Iron;

// Extensions
pub use typemap::TypeMap;

// Status codes and Methods.
pub use http::status;
pub use http::method;

// Headers
pub use http::headers;

// Expose `GetCached` as `Plugin` so users can do `use iron::Plugin`.
pub use plugin::GetCached as Plugin;

// Expose modifiers.
pub use modifier::Set;

// Errors
pub use error::{Error, ErrorRefExt};

// Return type of many methods
pub type IronError = Box<Error>;
pub type IronResult<T> = Result<T, IronError>;

/// Re-exports from the TypeMap crate.
pub mod typemap {
    pub use tmap::{TypeMap, Assoc};
}

/// Re-exports from the Modifier crate.
pub mod modifier {
    pub use modfier::{Set, Modifier};
}

// Publicized to show the documentation
pub mod middleware;

// Common Errors
pub mod errors;

// Response utilities
pub mod response;

// Internal modules
mod request;
mod iron;

<|endoftext|>


<commit_before>#![cfg_attr(not(feature = "use_std"), no_std)]

#[derive(Debug)]
pub struct CobsEncoder<'a> {
    dest: &'a mut [u8],
    dest_idx: usize,
    code_idx: usize,
    num_bt_sent: u8,
}

impl<'a> CobsEncoder<'a> {
    pub fn new(out_buf: &'a mut [u8]) -> CobsEncoder<'a> {
        CobsEncoder {
            dest: out_buf,
            dest_idx: 1,
            code_idx: 0,
            num_bt_sent: 1,
        }
    }

    pub fn push(&mut self, data: &[u8]) -> Result<(), ()> {
        // TODO: could probably check if this would fit without
        // iterating through all data
        for x in data {
            if *x == 0 {
                *self.dest.get_mut(self.code_idx)
                    .ok_or_else(|| ())? = self.num_bt_sent;

                self.num_bt_sent = 1;
                self.code_idx = self.dest_idx;
                self.dest_idx += 1;
            } else {
                *self.dest.get_mut(self.dest_idx)
                    .ok_or_else(|| ())? = *x;

                self.num_bt_sent += 1;
                self.dest_idx += 1;
                if 0xFF == self.num_bt_sent {
                    *self.dest.get_mut(self.code_idx)
                        .ok_or_else(|| ())? = self.num_bt_sent;
                    self.num_bt_sent = 1;
                    self.code_idx = self.dest_idx;
                    self.dest_idx += 1;
                }
            }
        }

        Ok(())
    }

    pub fn finalize(self) -> Result<usize, ()> {
        if self.dest_idx == 1 {
            return Ok(0);
        }

        *self.dest.get_mut(self.code_idx)
            .ok_or_else(|| ())? = self.num_bt_sent;

        return Ok(self.dest_idx);
    }
}

/// Encodes the `source` buffer into the `dest` buffer.
///
/// This function uses the typical sentinel value of 0. It returns the number of bytes
/// written to in the `dest` buffer.
///
/// # Panics
///
/// This function will panic if the `dest` buffer is not large enough for the
/// encoded message. You can calculate the size the `dest` buffer needs to be with
/// the `max_encoding_length` function.
pub fn encode(source: &[u8], dest: &mut[u8]) -> usize {
    let mut enc = CobsEncoder::new(dest);
    enc.push(source).unwrap();
    enc.finalize().unwrap()
}

/// Encodes the `source` buffer into the `dest` buffer using an
/// arbitrary sentinel value.
///
/// This is done by first encoding the message with the typical sentinel value
/// of 0, then XOR-ing each byte of the encoded message with the chosen sentinel
/// value. This will ensure that the sentinel value doesn't show up in the encoded
/// message. See the paper "Consistent Overhead Byte Stuffing" for details.
pub fn encode_with_sentinel(source: &[u8], dest: &mut[u8], sentinel: u8) -> usize {
    let encoded_size = encode(source, dest);
    for x in &mut dest[..encoded_size] {
        *x ^= sentinel;
    }
    return encoded_size;
}

#[cfg(feature = "use_std")]
/// Encodes the `source` buffer into a vector.
pub fn encode_vec(source: &[u8]) -> Vec<u8> {
    let mut encoded = vec![0; max_encoding_length(source.len())];
    let encoded_len = encode(source, &mut encoded[..]);
    encoded.truncate(encoded_len);
    return encoded;
}

#[cfg(feature = "use_std")]
/// Encodes the `source` buffer into a vector with an arbitrary sentinel value.
pub fn encode_vec_with_sentinel(source: &[u8], sentinel: u8) -> Vec<u8> {
    let mut encoded = vec![0; max_encoding_length(source.len())];
    let encoded_len = encode_with_sentinel(source, &mut encoded[..], sentinel);
    encoded.truncate(encoded_len);
    return encoded;
}

#[derive(Debug)]
pub struct CobsDecoder<'a> {
    dest: &'a mut [u8],
    dest_idx: usize,
    state: DecoderState,
}

#[derive(Debug)]
enum DecoderState {
    /// State machine has not received any non-zero bytes
    Idle,

    /// 1-254 bytes, can be header or 00
    Grab(u8),

    /// 255 bytes, will be a header next
    GrabChain(u8),

    /// Prevent re-using the state machine
    ErrOrComplete,
}

fn add(to: &mut [u8], idx: usize, data: u8) -> Result<(), ()> {
    *to.get_mut(idx)
        .ok_or_else(|| ())? = data;
    Ok(())
}

impl<'a> CobsDecoder<'a> {
    pub fn new(dest: &'a mut [u8]) -> CobsDecoder<'a> {
        CobsDecoder {
            dest,
            dest_idx: 0,
            state: DecoderState::Idle,
        }
    }

    // fn test_encode_2() {
    //     test_pair(vec![0, 0, 1, 0], vec![1, 1, 2, 1, 1])
    // }

    pub fn feed(&mut self, data: u8) -> Result<Option<usize>, usize> {
        use DecoderState::*;

        println!("Before {} {:?}", data, self);

        let (ret, state) = match (&self.state, data) {
            (Idle, 0x00) => (Ok(None), Idle),
            (Idle, 0xFF) => (Ok(None), GrabChain(0xFF)), // off by one?
            (Idle, n)    => (Ok(None), Grab(n)),
            (Grab(0..=1), 0x00) => (Ok(Some(self.dest_idx)), ErrOrComplete),
            (Grab(0..=1), 0xFF) => {
                let _ = add(self.dest, self.dest_idx, 0u8).map_err(|_| self.dest_idx)?;
                self.dest_idx += 1usize;
                (Ok(None), GrabChain(0xFF))
            },
            (Grab(0..=1), n) => {
                let _ = add(self.dest, self.dest_idx, 0u8).map_err(|_| self.dest_idx)?;
                self.dest_idx += 1usize;
                (Ok(None), Grab(n))
            },
            (Grab(i), n) =>  {
                add(self.dest, self.dest_idx, n).map_err(|_| self.dest_idx)?;
                self.dest_idx += 1;
                (Ok(None), Grab(i - 1))
            },
            (GrabChain(0..=1), 0x00) => (Ok(Some(self.dest_idx)), ErrOrComplete),
            (GrabChain(0..=1), 0xFF) => (Ok(None), GrabChain(0xFF)),
            (GrabChain(0..=1), n) => (Ok(None), Grab(n)),
            (GrabChain(i), n) => {
                add(self.dest, self.dest_idx, n).map_err(|_| self.dest_idx)?;
                self.dest_idx += 1;
                (Ok(None), GrabChain(i - 1))
            },
            (ErrOrComplete, _) => (Err(self.dest_idx), ErrOrComplete),
        };

        self.state = state;

        println!("After {} {:?}", data, self);

        ret
    }

    pub fn push(&mut self, data: &[u8]) -> Result<Option<(usize, usize)>, ()> {
        for (i, d) in data.iter().enumerate() {
            // println!("Decode tab {} {} {:?}", i, *d, self);
            let x = self.feed(*d);
            println!("==> {:?}", x);
            if let Some(n) = x.map_err(|_| ())? {
                return Ok(Some((n, i)));
            }
        }

        Ok(None)
    }
}
    //     if self.done {
    //         return Err(());
    //     }

    //     for (i, d) in data.iter().enumerate() {
    //         if self.code.is_none() {
    //             if *d == 0 {
    //                 self.done = true;

    //                 if i < (data.len() - 1) {
    //                     return Ok(Some(if self.dest_idx == 0 { 0 } else { self.dest_idx - 1 }))
    //                 } else {
    //                     continue
    //                 }
    //             }

    //             self.code = Some(*d);
    //             self.skip = (self.dest_idx == 0) || (*d == 0xFF);
    //             continue;
    //         } else if *d == 0 {
    //             return Err(());
    //         }

    //         let end = {
    //             let c = self.code.as_mut().unwrap();
    //             *c -= 1;

    //             if *c == 0 {
    //                 true
    //             } else {
    //                 *self.dest.get_mut(self.dest_idx)
    //                     .ok_or_else(|| ())? = *d;
    //                 self.dest_idx += 1;
    //                 false
    //             }
    //         };

    //         if end {
    //             self.code = None;
    //             if !self.skip {
    //                 *self.dest.get_mut(self.dest_idx)
    //                     .ok_or_else(|| ())? = 0;
    //                 self.dest_idx += 1;
    //             }
    //         }

    //     }
    //     Ok(None)
    // }

// This needs to be a macro because `src` and `dst` could be the same or different.
macro_rules! decode_raw (
    ($src:ident, $dst:ident) => ({
        let mut source_index = 0;
        let mut dest_index = 0;

        while source_index < $src.len() {
            let code = $src[source_index];

            if source_index + code as usize > $src.len() && code != 1 {
                return Err(());
            }

            source_index += 1;

            for _ in 1..code {
                $dst[dest_index] = $src[source_index];
                source_index += 1;
                dest_index += 1;
            }

            if 0xFF != code && source_index < $src.len() {
                $dst[dest_index] = 0;
                dest_index += 1;
            }
        }

        Ok(dest_index)
    })
);

/// Decodes the `source` buffer into the `dest` buffer.
///
/// This function uses the typical sentinel value of 0.
///
/// # Failures
///
/// This will return `Err(())` if there was a decoding error. Otherwise,
/// it will return `Ok(n)` where `n` is the length of the decoded message.
///
/// # Panics
///
/// This function will panic if the `dest` buffer is not large enough for the
/// decoded message. Since an encoded message as always larger than a decoded
/// message, it may be a good idea to make the `dest` buffer as big as the
/// `source` buffer.
pub fn decode(source: &[u8], dest: &mut[u8]) -> Result<usize, ()> {
    // decode_raw!(source, dest)
    let mut dec = CobsDecoder::new(dest);
    assert!(dec.push(source).unwrap().is_none());
    println!("{:?}", dec);
    if let Some((d_used, s_used)) = dec.push(&[0]).unwrap() {
        Ok(d_used)
    } else {
        Err(())
    }
}

/// Decodes a message in-place.
///
/// This is the same function as `decode`, but replaces the encoded message
/// with the decoded message instead of writing to another buffer.
pub fn decode_in_place(buff: &mut[u8]) -> Result<usize, ()> {
    decode_raw!(buff, buff)
}

/// Decodes the `source` buffer into the `dest` buffer using an arbitrary sentinel value.
///
/// This is done by XOR-ing each byte of the source message with the chosen sentinel value,
/// which transforms the message into the same message encoded with a sentinel value of 0.
/// Then the regular decoding transformation is performed.
pub fn decode_with_sentinel(source: &[u8], dest: &mut[u8], sentinel: u8) -> Result<usize, ()> {
    for (x, y) in source.iter().zip(dest.iter_mut()) {
        *y = *x ^ sentinel;
    }
    decode_in_place(dest)
}

/// Decodes a message in-place using an arbitrary sentinel value.
pub fn decode_in_place_with_sentinel(buff: &mut[u8], sentinel: u8) -> Result<usize, ()> {
    for x in buff.iter_mut() {
        *x ^= sentinel;
    }
    decode_in_place(buff)
}

#[cfg(feature = "use_std")]
/// Decodes the `source` buffer into a vector.
pub fn decode_vec(source: &[u8]) -> Result<Vec<u8>, ()> {
    let mut decoded = vec![0; source.len()];
    match decode(source, &mut decoded[..]) {
        Ok(n) => {
            decoded.truncate(n);
            Ok(decoded)
        },
        Err(()) => Err(()),
    }
}

#[cfg(feature = "use_std")]
/// Decodes the `source` buffer into a vector with an arbitrary sentinel value.
pub fn decode_vec_with_sentinel(source: &[u8], sentinel: u8) -> Result<Vec<u8>, ()> {
    let mut decoded = vec![0; source.len()];
    match decode_with_sentinel(source, &mut decoded[..], sentinel) {
        Ok(n) => {
            decoded.truncate(n);
            Ok(decoded)
        },
        Err(()) => Err(()),
    }
}

/// Calculates the maximum possible size of an encoded message given the length
/// of the source message. This may be useful for calculating how large the
/// `dest` buffer needs to be in the encoding functions.
pub fn max_encoding_length(source_len: usize) -> usize {
    source_len + (source_len / 254) + if source_len % 254 > 0 { 1 } else { 0 }
}
<commit_msg>Clean up code for PR!<commit_after>#![cfg_attr(not(feature = "use_std"), no_std)]

#[derive(Debug)]
pub struct CobsEncoder<'a> {
    dest: &'a mut [u8],
    dest_idx: usize,
    code_idx: usize,
    num_bt_sent: u8,
}

impl<'a> CobsEncoder<'a> {

    /// Create a new streaming Cobs Encoder
    pub fn new(out_buf: &'a mut [u8]) -> CobsEncoder<'a> {
        CobsEncoder {
            dest: out_buf,
            dest_idx: 1,
            code_idx: 0,
            num_bt_sent: 1,
        }
    }

    /// Push a slice of data to be encoded
    pub fn push(&mut self, data: &[u8]) -> Result<(), ()> {
        // TODO: could probably check if this would fit without
        // iterating through all data
        for x in data {
            if *x == 0 {
                *self.dest.get_mut(self.code_idx)
                    .ok_or_else(|| ())? = self.num_bt_sent;

                self.num_bt_sent = 1;
                self.code_idx = self.dest_idx;
                self.dest_idx += 1;
            } else {
                *self.dest.get_mut(self.dest_idx)
                    .ok_or_else(|| ())? = *x;

                self.num_bt_sent += 1;
                self.dest_idx += 1;
                if 0xFF == self.num_bt_sent {
                    *self.dest.get_mut(self.code_idx)
                        .ok_or_else(|| ())? = self.num_bt_sent;
                    self.num_bt_sent = 1;
                    self.code_idx = self.dest_idx;
                    self.dest_idx += 1;
                }
            }
        }

        Ok(())
    }

    /// Complete encoding of the output message. Does NOT terminate
    /// the message with the sentinel value
    pub fn finalize(self) -> Result<usize, ()> {
        if self.dest_idx == 1 {
            return Ok(0);
        }

        *self.dest.get_mut(self.code_idx)
            .ok_or_else(|| ())? = self.num_bt_sent;

        return Ok(self.dest_idx);
    }
}

/// Encodes the `source` buffer into the `dest` buffer.
///
/// This function uses the typical sentinel value of 0. It returns the number of bytes
/// written to in the `dest` buffer.
///
/// # Panics
///
/// This function will panic if the `dest` buffer is not large enough for the
/// encoded message. You can calculate the size the `dest` buffer needs to be with
/// the `max_encoding_length` function.
pub fn encode(source: &[u8], dest: &mut[u8]) -> usize {
    let mut enc = CobsEncoder::new(dest);
    enc.push(source).unwrap();
    enc.finalize().unwrap()
}

/// Encodes the `source` buffer into the `dest` buffer using an
/// arbitrary sentinel value.
///
/// This is done by first encoding the message with the typical sentinel value
/// of 0, then XOR-ing each byte of the encoded message with the chosen sentinel
/// value. This will ensure that the sentinel value doesn't show up in the encoded
/// message. See the paper "Consistent Overhead Byte Stuffing" for details.
pub fn encode_with_sentinel(source: &[u8], dest: &mut[u8], sentinel: u8) -> usize {
    let encoded_size = encode(source, dest);
    for x in &mut dest[..encoded_size] {
        *x ^= sentinel;
    }
    return encoded_size;
}

#[cfg(feature = "use_std")]
/// Encodes the `source` buffer into a vector.
pub fn encode_vec(source: &[u8]) -> Vec<u8> {
    let mut encoded = vec![0; max_encoding_length(source.len())];
    let encoded_len = encode(source, &mut encoded[..]);
    encoded.truncate(encoded_len);
    return encoded;
}

#[cfg(feature = "use_std")]
/// Encodes the `source` buffer into a vector with an arbitrary sentinel value.
pub fn encode_vec_with_sentinel(source: &[u8], sentinel: u8) -> Vec<u8> {
    let mut encoded = vec![0; max_encoding_length(source.len())];
    let encoded_len = encode_with_sentinel(source, &mut encoded[..], sentinel);
    encoded.truncate(encoded_len);
    return encoded;
}

#[derive(Debug)]
pub struct CobsDecoder<'a> {
    /// Destination slice for decoded message
    dest: &'a mut [u8],

    /// Index of next byte to write in `dest`
    dest_idx: usize,

    /// Decoder state as an enum
    state: DecoderState,
}

#[derive(Debug)]
enum DecoderState {
    /// State machine has not received any non-zero bytes
    Idle,

    /// 1-254 bytes, can be header or 00
    Grab(u8),

    /// 255 bytes, will be a header next
    GrabChain(u8),

    /// Prevent re-using the state machine
    ErrOrComplete,
}

fn add(to: &mut [u8], idx: usize, data: u8) -> Result<(), ()> {
    *to.get_mut(idx)
        .ok_or_else(|| ())? = data;
    Ok(())
}

impl<'a> CobsDecoder<'a> {

    /// Create a new streaming Cobs Decoder. Provide the output buffer
    /// for the decoded message to be placed in
    pub fn new(dest: &'a mut [u8]) -> CobsDecoder<'a> {
        CobsDecoder {
            dest,
            dest_idx: 0,
            state: DecoderState::Idle,
        }
    }

    /// Push a single byte into the streaming CobsDecoder. Return values mean:
    ///
    /// * Ok(None) - State machine okay, more data needed
    /// * Ok(Some(N)) - A message of N bytes was successfully decoded
    /// * Err(M) - Message decoding failed, and M bytes were written to output
    ///
    /// NOTE: Sentinel value must be included in the input to this function for the
    /// decoding to complete
    pub fn feed(&mut self, data: u8) -> Result<Option<usize>, usize> {
        use DecoderState::*;

        let (ret, state) = match (&self.state, data) {
            (Idle, 0x00) => (Ok(None), Idle),
            (Idle, 0xFF) => (Ok(None), GrabChain(0xFE)),
            (Idle, n)    => (Ok(None), Grab(n - 1)),
            (Grab(0), 0x00) => (Ok(Some(self.dest_idx)), ErrOrComplete),
            (Grab(0), 0xFF) => {
                add(self.dest, self.dest_idx, 0u8).map_err(|_| self.dest_idx)?;
                self.dest_idx += 1usize;
                (Ok(None), GrabChain(0xFE))
            },
            (Grab(0), n) => {
                add(self.dest, self.dest_idx, 0u8).map_err(|_| self.dest_idx)?;
                self.dest_idx += 1usize;
                (Ok(None), Grab(n - 1))
            },
            (Grab(i), n) =>  {
                add(self.dest, self.dest_idx, n).map_err(|_| self.dest_idx)?;
                self.dest_idx += 1;
                (Ok(None), Grab(i - 1))
            },
            (GrabChain(0), 0x00) => (Ok(Some(self.dest_idx)), ErrOrComplete),
            (GrabChain(0), 0xFF) => (Ok(None), GrabChain(0xFE)),
            (GrabChain(0), n) => (Ok(None), Grab(n - 1)),
            (GrabChain(i), n) => {
                add(self.dest, self.dest_idx, n).map_err(|_| self.dest_idx)?;
                self.dest_idx += 1;
                (Ok(None), GrabChain(i - 1))
            },
            (ErrOrComplete, _) => (Err(self.dest_idx), ErrOrComplete),
        };

        self.state = state;
        ret
    }

    /// Push a slice of bytes into the streaming CobsDecoder. Return values mean:
    ///
    /// * Ok(None) - State machine okay, more data needed
    /// * Ok(Some((N, M))) - A message of N bytes was successfully decoded,
    ///     using M bytes from `data` (and earlier data)
    /// * Err(J - Message decoding failed, and J bytes were written to output
    ///
    /// NOTE: Sentinel value must be included in the input to this function for the
    /// decoding to complete
    pub fn push(&mut self, data: &[u8]) -> Result<Option<(usize, usize)>, usize> {
        for (i, d) in data.iter().enumerate() {
            let x = self.feed(*d);
            if let Some(n) = x? {
                return Ok(Some((n, i)));
            }
        }

        Ok(None)
    }
}

// This needs to be a macro because `src` and `dst` could be the same or different.
macro_rules! decode_raw (
    ($src:ident, $dst:ident) => ({
        let mut source_index = 0;
        let mut dest_index = 0;

        while source_index < $src.len() {
            let code = $src[source_index];

            if source_index + code as usize > $src.len() && code != 1 {
                return Err(());
            }

            source_index += 1;

            for _ in 1..code {
                $dst[dest_index] = $src[source_index];
                source_index += 1;
                dest_index += 1;
            }

            if 0xFF != code && source_index < $src.len() {
                $dst[dest_index] = 0;
                dest_index += 1;
            }
        }

        Ok(dest_index)
    })
);

/// Decodes the `source` buffer into the `dest` buffer.
///
/// This function uses the typical sentinel value of 0.
///
/// # Failures
///
/// This will return `Err(())` if there was a decoding error. Otherwise,
/// it will return `Ok(n)` where `n` is the length of the decoded message.
///
/// # Panics
///
/// This function will panic if the `dest` buffer is not large enough for the
/// decoded message. Since an encoded message as always larger than a decoded
/// message, it may be a good idea to make the `dest` buffer as big as the
/// `source` buffer.
pub fn decode(source: &[u8], dest: &mut[u8]) -> Result<usize, ()> {
    // decode_raw!(source, dest)
    let mut dec = CobsDecoder::new(dest);
    assert!(dec.push(source).unwrap().is_none());

    // Explicitly push sentinel of zero
    if let Some((d_used, _s_used)) = dec.push(&[0]).unwrap() {
        Ok(d_used)
    } else {
        Err(())
    }
}

/// Decodes a message in-place.
///
/// This is the same function as `decode`, but replaces the encoded message
/// with the decoded message instead of writing to another buffer.
pub fn decode_in_place(buff: &mut[u8]) -> Result<usize, ()> {
    decode_raw!(buff, buff)
}

/// Decodes the `source` buffer into the `dest` buffer using an arbitrary sentinel value.
///
/// This is done by XOR-ing each byte of the source message with the chosen sentinel value,
/// which transforms the message into the same message encoded with a sentinel value of 0.
/// Then the regular decoding transformation is performed.
pub fn decode_with_sentinel(source: &[u8], dest: &mut[u8], sentinel: u8) -> Result<usize, ()> {
    for (x, y) in source.iter().zip(dest.iter_mut()) {
        *y = *x ^ sentinel;
    }
    decode_in_place(dest)
}

/// Decodes a message in-place using an arbitrary sentinel value.
pub fn decode_in_place_with_sentinel(buff: &mut[u8], sentinel: u8) -> Result<usize, ()> {
    for x in buff.iter_mut() {
        *x ^= sentinel;
    }
    decode_in_place(buff)
}

#[cfg(feature = "use_std")]
/// Decodes the `source` buffer into a vector.
pub fn decode_vec(source: &[u8]) -> Result<Vec<u8>, ()> {
    let mut decoded = vec![0; source.len()];
    match decode(source, &mut decoded[..]) {
        Ok(n) => {
            decoded.truncate(n);
            Ok(decoded)
        },
        Err(()) => Err(()),
    }
}

#[cfg(feature = "use_std")]
/// Decodes the `source` buffer into a vector with an arbitrary sentinel value.
pub fn decode_vec_with_sentinel(source: &[u8], sentinel: u8) -> Result<Vec<u8>, ()> {
    let mut decoded = vec![0; source.len()];
    match decode_with_sentinel(source, &mut decoded[..], sentinel) {
        Ok(n) => {
            decoded.truncate(n);
            Ok(decoded)
        },
        Err(()) => Err(()),
    }
}

/// Calculates the maximum possible size of an encoded message given the length
/// of the source message. This may be useful for calculating how large the
/// `dest` buffer needs to be in the encoding functions.
pub fn max_encoding_length(source_len: usize) -> usize {
    source_len + (source_len / 254) + if source_len % 254 > 0 { 1 } else { 0 }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2015 FaultyRAM
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

//! ngLog processing utilities.
//!
//! ngLog is a textual file format designed for recording gameplay events. Each
//! line of text in an ngLog-formatted file represents an *event*, consisting
//! of several parameters in the following order, each separated by an ASCII
//! TAB control code:
//!
//! * A *timestamp*: a floating-point number representing the time in seconds
//!   that have elapsed since gameplay began;
//! * An optional *event class*, describing the category to which the event
//!   belongs;
//! * An *event ID*, describing the type of event which occurred;
//! * Zero or more *event parameters*, each representing an arbitrary data
//!   point associated with the event.
//!
//! ngLog was used in conjunction with ngStats and ngWorldStats to provide both
//! local and online statistical analysis and tracking. Supported video games
//! would create two copies of an ngLog file upon gameplay completion: a copy
//! for local processing, and an encoded copy to be sent to a *world server*.
//! This crate provides functionality for processing both forms, from either a
//! `String` or a type that implements `std::io::Read`. For example:
//!
//! ```rust
//! use ng_log::NgLog;
//!
//! use std::fs::OpenOptions;
//! use std::io::Read;
//! use std::string::ToString;
//!
//! let mut file = OpenOptions::new()
//! 	.read(true)
//! 	.open("./tests/ngLog_Example_Log_File.log.txt")
//! 	.unwrap();
//! let log = NgLog::local_from_reader(&mut file).unwrap();
//! println!("{}", log.to_string());
//! ```

use std::io::Error as IoError;
use std::io::ErrorKind as IoErrorKind;
use std::io::Result as IoResult;
use std::io::Read;
use std::string::ToString;

pub struct NgLog {
	pub events: Vec<NgEvent>,
}

pub struct NgEvent {
	pub timestamp:    String,
	pub event_class:  Option<String>,
	pub event_id:     String,
	pub event_params: Vec<String>,
}

impl NgLog {
	pub fn new(capacity: usize) -> NgLog {
		NgLog {
			events: Vec::with_capacity(capacity),
		}
	}

	pub fn local_from_reader<T>(reader: &mut T) -> IoResult<NgLog> where
	T: Read {
		let mut data: Vec<u8> = Vec::with_capacity(0);
		try!(reader.read_to_end(&mut data));
		NgLog::from_string(&try!(String::from_utf8(data).map_err(|e|
			IoError::new(IoErrorKind::InvalidData, format!("{}", e))
		)))
	}

	pub fn world_from_reader<T>(reader: &mut T) -> IoResult<NgLog> where
	T: Read {
		let mut data: Vec<u8> = Vec::with_capacity(0);
		try!(reader.read_to_end(&mut data));
		if data.len() % 2 != 0 {
			return Err(IoError::new(IoErrorKind::InvalidData, "Non-even log length"))
		}
		// TODO: check if this format is used by games other than UT99.
		let mut decoded: Vec<u8> = Vec::with_capacity(data.len() / 2);
		for v in data.chunks(2) {
			decoded.push(v[0] ^ v[1]);
		}
		NgLog::from_string(&try!(String::from_utf8(decoded).map_err(|e|
			IoError::new(IoErrorKind::InvalidData, format!("{}", e))
		)))
	}

	pub fn from_string(s: &String) -> IoResult<NgLog> {
		let mut log = NgLog::new(s.len());
		for line in s.lines() {
			let event = try!(NgEvent::from_string(&String::from(line)));
			log.events.push(event);
		}
		Ok(log)
	}
}

impl ToString for NgLog {
	fn to_string(&self) -> String {
		let mut s = String::with_capacity(0);
		for v in &self.events {
			s = s + &v.to_string() + &"\n";
		}
		s
	}
}

impl NgEvent {
	pub fn new(timestamp: String, class: Option<String>, id: String, params: Vec<String>) -> NgEvent {
		NgEvent {
			timestamp:    timestamp,
			event_class:  class,
			event_id:     id,
			event_params: params,
		}
	}

	pub fn from_string(s: &String) -> IoResult<NgEvent> {
		let mut columns: Vec<String> = s.split('\t').map(|s| String::from(s)).collect();
		if columns.len() < 2 {
			return Err(IoError::new(IoErrorKind::InvalidData, "Bad event string"))
		} else if columns.len() == 2 {
			Ok(NgEvent::new(
				columns.remove(0),
				None,
				columns.remove(0),
				Vec::with_capacity(0)
			))
		} else {
			Ok(NgEvent::new(
				columns.remove(0),
				Some(columns.remove(0)),
				columns.remove(0),
				columns.clone()
			))
		}
	}
}

impl ToString for NgEvent {
	fn to_string(&self) -> String {
		let mut s = String::with_capacity(0);
		s = s + &self.timestamp;
		if let Some(v) = self.event_class.clone() {
			s = s + &"\t" + &v;
		}
		s = s + &"\t" + &self.event_id;
		for v in self.event_params.iter() {
			s = s + &"\t" + &v;
		}
		s
	}
}
<commit_msg>Fully documented the API<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 FaultyRAM
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

//! ngLog processing utilities.
//!
//! ngLog is a textual file format designed for recording gameplay events. Each
//! line of text in an ngLog-formatted file represents an *event*, consisting
//! of several parameters in the following order, each separated by an ASCII
//! TAB control code:
//!
//! * A *timestamp*: a floating-point number representing the time in seconds
//!   that have elapsed since gameplay began;
//! * An optional *event class*, describing the category to which the event
//!   belongs;
//! * An *event ID*, describing the type of event which occurred;
//! * Zero or more *event parameters*, each representing an arbitrary data
//!   point associated with the event.
//!
//! ngLog was used in conjunction with ngStats and ngWorldStats to provide both
//! local and online statistical analysis and tracking. Supported video games
//! would create two copies of an ngLog file upon gameplay completion: a copy
//! for local processing, and an encoded copy to be sent to a *world server*.
//! This crate provides functionality for processing both forms, from either a
//! `String` or a type that implements `std::io::Read`. For example:
//!
//! ```rust
//! use ng_log::NgLog;
//!
//! use std::fs::OpenOptions;
//! use std::io::Read;
//! use std::string::ToString;
//!
//! let mut file = OpenOptions::new()
//! 	.read(true)
//! 	.open("./tests/ngLog_Example_Log_File.log.txt")
//! 	.unwrap();
//! let log = NgLog::local_from_reader(&mut file).unwrap();
//! println!("{}", log.to_string());
//! ```

use std::io::Error as IoError;
use std::io::ErrorKind as IoErrorKind;
use std::io::Result as IoResult;
use std::io::Read;
use std::string::ToString;

/// A type representing an ngLog-formatted file.
pub struct NgLog {
	/// A collection of ngLog events.
	pub events: Vec<NgEvent>,
}

/// A type representing an ngLog event.
pub struct NgEvent {
	/// A floating-point value representing the elapsed time since gameplay began.
	pub timestamp:    String,
	/// The category to which this event belongs, if any.
	pub event_class:  Option<String>,
	/// The type of this event.
	pub event_id:     String,
	/// Optional data points associated with this event.
	pub event_params: Vec<String>,
}

impl NgLog {
	/// Constructs a new `NgLog` instance, allocating memory for at least
	/// `capacity` events.
	pub fn new(capacity: usize) -> NgLog {
		NgLog {
			events: Vec::with_capacity(capacity),
		}
	}

	/// Constructs a new `NgLog` instance using data from a type implementing
	/// `std::io::Read`. The data is interpreted as a UTF-8 string.
	///
	/// # Failures
	///
	/// If the input data is either not valid UTF-8 or malformed, this method
	/// returns an `std::io::Error` instance describing the error.
	pub fn local_from_reader<T>(reader: &mut T) -> IoResult<NgLog> where
	T: Read {
		let mut data: Vec<u8> = Vec::with_capacity(0);
		try!(reader.read_to_end(&mut data));
		NgLog::from_string(&try!(String::from_utf8(data).map_err(|e|
			IoError::new(IoErrorKind::InvalidData, format!("{}", e))
		)))
	}

	/// Constructs a new `NgLog` instance using data from a type implementing
	/// `std::io::Error`. The data is fed through a decoding algorithm, then
	/// interpreted as a UTF-8 string.
	///
	/// # Failures
	///
	/// If the input data is either not valid UTF-8 or malformed, this method
	/// returns an `std::io::Error` instance describing the error.
	pub fn world_from_reader<T>(reader: &mut T) -> IoResult<NgLog> where
	T: Read {
		let mut data: Vec<u8> = Vec::with_capacity(0);
		try!(reader.read_to_end(&mut data));
		if data.len() % 2 != 0 {
			return Err(IoError::new(IoErrorKind::InvalidData, "Non-even log length"))
		}
		// TODO: check if this format is used by games other than UT99.
		let mut decoded: Vec<u8> = Vec::with_capacity(data.len() / 2);
		for v in data.chunks(2) {
			decoded.push(v[0] ^ v[1]);
		}
		NgLog::from_string(&try!(String::from_utf8(decoded).map_err(|e|
			IoError::new(IoErrorKind::InvalidData, format!("{}", e))
		)))
	}

	/// Constructs a new `NgLog` instance from the given input string.
	///
	/// # Failures
	///
	/// If the input data is malformed, this method returns an `std::io::Error`
	/// instance describing the error.
	pub fn from_string(s: &String) -> IoResult<NgLog> {
		let mut log = NgLog::new(s.len());
		for line in s.lines() {
			let event = try!(NgEvent::from_string(&String::from(line)));
			log.events.push(event);
		}
		Ok(log)
	}
}

impl ToString for NgLog {
	fn to_string(&self) -> String {
		let mut s = String::with_capacity(0);
		for v in &self.events {
			s = s + &v.to_string() + &"\n";
		}
		s
	}
}

impl NgEvent {
	/// Constructs a new `NgEvent` instance from the given arguments.
	pub fn new(timestamp: String, class: Option<String>, id: String, params: Vec<String>) -> NgEvent {
		NgEvent {
			timestamp:    timestamp,
			event_class:  class,
			event_id:     id,
			event_params: params,
		}
	}

	/// Constructs a new `NgEvent` instance from the given input string.
	///
	/// # Failures
	///
	/// If the given data is malformed, this method returns an `std::io::Error`
	/// instance describing the error.
	pub fn from_string(s: &String) -> IoResult<NgEvent> {
		let mut columns: Vec<String> = s.split('\t').map(|s| String::from(s)).collect();
		if columns.len() < 2 {
			return Err(IoError::new(IoErrorKind::InvalidData, "Bad event string"))
		} else if columns.len() == 2 {
			Ok(NgEvent::new(
				columns.remove(0),
				None,
				columns.remove(0),
				Vec::with_capacity(0)
			))
		} else {
			Ok(NgEvent::new(
				columns.remove(0),
				Some(columns.remove(0)),
				columns.remove(0),
				columns.clone()
			))
		}
	}
}

impl ToString for NgEvent {
	fn to_string(&self) -> String {
		let mut s = String::with_capacity(0);
		s = s + &self.timestamp;
		if let Some(v) = self.event_class.clone() {
			s = s + &"\t" + &v;
		}
		s = s + &"\t" + &self.event_id;
		for v in self.event_params.iter() {
			s = s + &"\t" + &v;
		}
		s
	}
}
<|endoftext|>


<commit_before>macro_rules! swrite {
    (@one $writer:expr, ($e:expr)) => { write!($writer, "{}", $e) };
    (@one $writer:expr, [$e:expr]) => { write!($writer, "{:?}", $e) };
    (@one $writer:expr, {$e:tt : $($fmt:tt)*}) => {
        write!($writer, concat!("{:", stringify!($($fmt)*), "}"), $e)
    };
    (@one $writer:expr, {$($arg:tt)*}) => {
        write!($writer, $($arg)*)
    };
    (@one $writer:expr, $string:tt) => {
        write!($writer, "{}", { let s: &str = $string; s })
    };
    ($writer:expr, $($part:tt)*) => {
        (||{
            let mut _w = $writer;
            $(
                match swrite!(@one _w, $part) {
                    Ok(()) => (),
                    error => return error,
                }
            )*
            Ok(())
        })()
    };
    ($writer:expr) => { swrite!($writer,) };
}

macro_rules! swriteln {
    ($($arg:tt)*) => { swrite!($($arg)* "\n") }
}

macro_rules! sprint {
    ($($arg:tt)*) => { {
        use ::std::io::Write;
        let o = ::std::io::stdout();
        swrite!(o.lock(), $($arg)*).unwrap();
    } }
}

macro_rules! sprintln {
    ($($arg:tt)*) => { sprint!($($arg)* "\n") }
}

macro_rules! sprerr {
    ($($arg:tt)*) => { {
        use ::std::io::Write;
        let o = ::std::io::stderr();
        swrite!(o.lock(), $($arg)*).unwrap();
    } }
}

macro_rules! sprerrln {
    ($($arg:tt)*) => { sprerr!($($arg)* "\n") }
}

macro_rules! sformat {
    () => { String::new() };
    ($($arg:tt)*) => { {
        use ::std::fmt::Write;
        let mut _s = String::new(); // TODO with capacity
        swrite!(&mut _s, $($arg)*).ok();
        _s
    } }
}

#[test]
fn basics() {
    let world = "World";
    assert_eq!(sformat!("Hello, "(world)"!"), "Hello, World!");
    let x = 3;
    assert_eq!(sformat!((x)" * 2 = "(x * 2)), "3 * 2 = 6");
}

#[test]
fn empty() {
    assert_eq!(sformat!(), "");
}

#[test]
fn vec() {
    let v = vec![1,2,3];
    assert_eq!(sformat!([v]), "[1, 2, 3]");
}

#[test]
fn write() {
    use std::io::Write;
    let mut v = Vec::new();
    swriteln!(&mut v, "hi" "!").unwrap();
    assert_eq!(v, "hi!\n".as_bytes());
}

#[test]
fn format() {
    assert_eq!( sformat!({5:02}), "05" );
    assert_eq!( sformat!({"{}-{}", 4, 2}), "4-2" );
}

#[test]
fn hello() {
    let foo = "foo";
    let x = 2;
    let y = 4;
    sprintln!("Bar "(foo)" and "(x));
    sprintln!( (x)"<"(y) );
}
<commit_msg>for and if + error messages<commit_after>macro_rules! swrite {
    (@one $w:ident, ($e:expr)) => { write!($w, "{}", $e) };
    (@one $w:ident, [$e:expr]) => { write!($w, "{:?}", $e) };
    (@one $w:ident, {$e:tt : $($fmt:tt)*}) => {
        write!($w, concat!("{:", stringify!($($fmt)*), "}"), $e)
    };
    (@one $w:ident, {$($arg:tt)*}) => {
        write!($w, $($arg)*)
    };
    (@one $w:ident, $string:tt) => {
        write!($w, "{}", concat!($string))
    };

    (@rec $w:ident, for $p:pat in ($e:expr) { $($body:tt)* } $($rest:tt)* ) => {
        {
            for $p in $e {
                swrite!(@rec $w, $($body)*);
            }
            swrite!(@rec $w, $($rest)*);
        }
    };
    (@rec $w:ident, for $($rest:tt)* ) => {
        {
            let NOTE: () = "use parens around expression: for PAT in (EXPR) { BODY }";
        }
    };
    (@rec $w:ident, if ($cond:expr) { $($then:tt)* } else { $($els:tt)* } $($rest:tt)* ) => {
        {
            if $cond {
                swrite!(@rec $w, $($then)*);
            } else {
                swrite!(@rec $w, $($els)*);
            }
            swrite!(@rec $w, $($rest)*);
        }
    };
    (@rec $w:ident, if ($cont:expr) { $($then:tt)* } else if $($rest:tt)* ) => {
        {
            let ERROR: () = "`else if` is unsupported";
            let NOTE: () = "use `match` or `else { if ... }` instead";
        }
    };
    (@rec $w:ident, if ($cond:expr) { $($then:tt)* } $($rest:tt)* ) => {
        swrite!(@rec $w, if ($cond) { $($then)* } else {} $($rest)*);
    };
    (@rec $w:ident, if $($rest:tt)* ) => {
        {
            let () = "note: use parens around expression: if (EXPR) { BODY }";
        }
    };
    (@rec $w:ident, $part:tt $($rest:tt)*) => {
        {
            match swrite!(@one $w, $part) {
                Ok(_) => (),
                error => return error,
            }
            swrite!(@rec $w, $($rest)*);
        }
    };
    (@rec $w:ident, ) => { () };

    ($writer:expr, $($part:tt)*) => {
        (||{
            let mut _w = $writer;
            swrite!(@rec _w, $($part)*);
            Ok(())
        })()
    };
    ($writer:expr) => { swrite!($writer,) };
}

macro_rules! swriteln {
    ($($arg:tt)*) => { swrite!($($arg)* "\n") }
}

macro_rules! sprint {
    ($($arg:tt)*) => {
        {
            use ::std::io::Write;
            let o = ::std::io::stdout();
            swrite!(o.lock(), $($arg)*).unwrap();
        }
    }
}

macro_rules! sprintln {
    ($($arg:tt)*) => { sprint!($($arg)* "\n") }
}

macro_rules! sprerr {
    ($($arg:tt)*) => {
        {
            use ::std::io::Write;
            let o = ::std::io::stderr();
            swrite!(o.lock(), $($arg)*).unwrap();
        }
    }
}

macro_rules! sprerrln {
    ($($arg:tt)*) => { sprerr!($($arg)* "\n") }
}

macro_rules! sformat {
    () => { String::new() };
    ($($arg:tt)*) => {
        {
            use ::std::fmt::Write;
            let mut _s = String::new(); // TODO with capacity
            swrite!(&mut _s, $($arg)*).ok();
            _s
        }
    }
}

#[test]
fn basics() {
    let world = "World";
    assert_eq!(sformat!("Hello, "(world)"!"), "Hello, World!");
    let x = 3;
    assert_eq!(sformat!((x)" * 2 = "(x * 2)), "3 * 2 = 6");
}

#[test]
fn empty() {
    assert_eq!(sformat!(), "");
}

#[test]
fn vec() {
    let v = vec![1,2,3];
    assert_eq!(sformat!([v]), "[1, 2, 3]");
}

#[test]
fn write() {
    use std::io::Write;
    let mut v = Vec::new();
    swriteln!(&mut v, "hi" "!").unwrap();
    assert_eq!(v, "hi!\n".as_bytes());
}

#[test]
fn format() {
    assert_eq!( sformat!({5:02}), "05" );
    assert_eq!( sformat!({"{}-{}", 4, 2}), "4-2" );
}

#[test]
fn hello() {
    let foo = "foo";
    let x = 2;
    let y = 4;
    sprintln!("Bar "(foo)" and "(x));
    sprintln!( (x)"<"(y) );
    sprintln!( for x in (&[1,2,3]) { (x)" :: " } "nil" );
}

#[test]
fn matrix() {
    let matrix = vec![vec![0]];
    assert_eq!(sformat!( for row in (&matrix) { for x in (row) { {x:3} } "\n" } ), "  0\n");
}
<|endoftext|>


<commit_before>//! Rust bindings to the libcurl C library
//!
//! This crate contains bindings for an HTTP/HTTPS client which is powered by
//! [libcurl], the same library behind the `curl` command line tool. The API
//! currently closely matches that of libcurl itself, except that a Rustic layer
//! of safety is applied on top.
//!
//! [libcurl]: https://curl.haxx.se/libcurl/
//!
//! # The "Easy" API
//!
//! The easiest way to send a request is to use the `Easy` api which corresponds
//! to `CURL` in libcurl. This handle supports a wide variety of options and can
//! be used to make a single blocking request in a thread. Callbacks can be
//! specified to deal with data as it arrives and a handle can be reused to
//! cache connections and such.
//!
//! ```rust,no_run
//! use std::io::{stdout, Write};
//!
//! use curl::easy::Easy;
//!
//! // Write the contents of rust-lang.org to stdout
//! let mut easy = Easy::new();
//! easy.url("https://www.rust-lang.org/").unwrap();
//! easy.write_function(|data| {
//!     Ok(stdout().write(data).unwrap())
//! }).unwrap();
//! easy.perform().unwrap();
//! ```
//!
//! # What about multiple concurrent HTTP requests?
//!
//! One option you have currently is to send multiple requests in multiple
//! threads, but otherwise libcurl has a "multi" interface for doing this
//! operation. Initial bindings of this interface can be found in the `multi`
//! module, but feedback is welcome!
//!
//! # Where does libcurl come from?
//!
//! This crate links to the `curl-sys` crate which is in turn responsible for
//! acquiring and linking to the libcurl library. Currently this crate will
//! build libcurl from source if one is not already detected on the system.
//!
//! There is a large number of releases for libcurl, all with different sets of
//! capabilities. Robust programs may wish to inspect `Version::get()` to test
//! what features are implemented in the linked build of libcurl at runtime.

#![deny(missing_docs)]

extern crate curl_sys;
extern crate libc;

#[cfg(all(unix, not(target_os = "macos")))]
extern crate openssl_sys;

use std::ffi::CStr;
use std::str;
use std::sync::{Once, ONCE_INIT};

pub use error::{Error, ShareError, MultiError, FormError};
mod error;

pub use version::{Version, Protocols};
mod version;

mod panic;
pub mod easy;
pub mod multi;

/// Initializes the underlying libcurl library.
///
/// It's not required to call this before the library is used, but it's
/// recommended to do so as soon as the program starts.
pub fn init() {
    static INIT: Once = ONCE_INIT;
    INIT.call_once(|| {
        unsafe {
            curl_sys::curl_global_init(curl_sys::CURL_GLOBAL_ALL);
            libc::atexit(cleanup);
        }
    });

    extern fn cleanup() {
        unsafe { curl_sys::curl_global_cleanup(); }
    }
}

unsafe fn opt_str<'a>(ptr: *const libc::c_char) -> Option<&'a str> {
    if ptr.is_null() {
        None
    } else {
        Some(str::from_utf8(CStr::from_ptr(ptr).to_bytes()).unwrap())
    }
}
<commit_msg>Be sure to initialize OpenSSL<commit_after>//! Rust bindings to the libcurl C library
//!
//! This crate contains bindings for an HTTP/HTTPS client which is powered by
//! [libcurl], the same library behind the `curl` command line tool. The API
//! currently closely matches that of libcurl itself, except that a Rustic layer
//! of safety is applied on top.
//!
//! [libcurl]: https://curl.haxx.se/libcurl/
//!
//! # The "Easy" API
//!
//! The easiest way to send a request is to use the `Easy` api which corresponds
//! to `CURL` in libcurl. This handle supports a wide variety of options and can
//! be used to make a single blocking request in a thread. Callbacks can be
//! specified to deal with data as it arrives and a handle can be reused to
//! cache connections and such.
//!
//! ```rust,no_run
//! use std::io::{stdout, Write};
//!
//! use curl::easy::Easy;
//!
//! // Write the contents of rust-lang.org to stdout
//! let mut easy = Easy::new();
//! easy.url("https://www.rust-lang.org/").unwrap();
//! easy.write_function(|data| {
//!     Ok(stdout().write(data).unwrap())
//! }).unwrap();
//! easy.perform().unwrap();
//! ```
//!
//! # What about multiple concurrent HTTP requests?
//!
//! One option you have currently is to send multiple requests in multiple
//! threads, but otherwise libcurl has a "multi" interface for doing this
//! operation. Initial bindings of this interface can be found in the `multi`
//! module, but feedback is welcome!
//!
//! # Where does libcurl come from?
//!
//! This crate links to the `curl-sys` crate which is in turn responsible for
//! acquiring and linking to the libcurl library. Currently this crate will
//! build libcurl from source if one is not already detected on the system.
//!
//! There is a large number of releases for libcurl, all with different sets of
//! capabilities. Robust programs may wish to inspect `Version::get()` to test
//! what features are implemented in the linked build of libcurl at runtime.

#![deny(missing_docs)]

extern crate curl_sys;
extern crate libc;

#[cfg(all(unix, not(target_os = "macos")))]
extern crate openssl_sys;

use std::ffi::CStr;
use std::str;
use std::sync::{Once, ONCE_INIT};

pub use error::{Error, ShareError, MultiError, FormError};
mod error;

pub use version::{Version, Protocols};
mod version;

mod panic;
pub mod easy;
pub mod multi;

/// Initializes the underlying libcurl library.
///
/// It's not required to call this before the library is used, but it's
/// recommended to do so as soon as the program starts.
pub fn init() {
    static INIT: Once = ONCE_INIT;
    INIT.call_once(|| {
        platform_init();
        unsafe {
            curl_sys::curl_global_init(curl_sys::CURL_GLOBAL_ALL);
            libc::atexit(cleanup);
        }
    });

    extern fn cleanup() {
        unsafe { curl_sys::curl_global_cleanup(); }
    }

    #[cfg(all(unix, not(target_os = "macos")))]
    fn platform_init() {
        openssl_sys::init();
    }

    #[cfg(not(all(unix, not(target_os = "macos"))))]
    fn platform_init() {}
}

unsafe fn opt_str<'a>(ptr: *const libc::c_char) -> Option<&'a str> {
    if ptr.is_null() {
        None
    } else {
        Some(str::from_utf8(CStr::from_ptr(ptr).to_bytes()).unwrap())
    }
}
<|endoftext|>


<commit_before>
#[macro_use]
extern crate maplit;
#[macro_use]
mod macros;

pub use action::Action;
pub use condition::Condition;
pub use conditions::Conditions;
pub use context::Context;
pub use correlator::Correlator;
pub use dispatcher::{Dispatcher, Response, Request};
pub use message::Message;
pub use timer::{Timer,
                TimerEvent};

pub mod conditions;
pub mod config;
pub mod action;
mod condition;
mod context;
mod correlator;
mod dispatcher;
pub mod message;
mod state;
mod reactor;
mod timer;

pub type MiliSec = u32;

#[derive(Debug)]
pub enum Event {
    Timer(TimerEvent),
    Message(Message)
}
<commit_msg>lib: implement Evet for Event<commit_after>
#[macro_use]
extern crate maplit;
#[macro_use]
mod macros;

pub use action::Action;
pub use condition::Condition;
pub use conditions::Conditions;
pub use context::Context;
pub use correlator::Correlator;
pub use dispatcher::{Dispatcher, Response, Request};
pub use message::Message;
pub use timer::{Timer,
                TimerEvent};

pub mod conditions;
pub mod config;
pub mod action;
mod condition;
mod context;
mod correlator;
mod dispatcher;
pub mod message;
mod state;
mod reactor;
mod timer;

pub type MiliSec = u32;

#[derive(Debug)]
pub enum Event {
    Timer(TimerEvent),
    Message(Message)
}

#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum EventHandler {
    Timer,
    Message
}

impl reactor::Event for Event {
    type Handler = EventHandler;
    fn handler(&self) -> Self::Handler {
        match *self {
            Event::Message(_) => EventHandler::Message,
            Event::Timer(_) => EventHandler::Timer
        }
    }
}
<|endoftext|>


<commit_before>#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results)]

extern crate crypto;
extern crate curl;
#[macro_use] extern crate log;
extern crate rand;
extern crate rustc_serialize;
extern crate time;
extern crate url;

use std::borrow::Cow;
use std::collections::HashMap;
use std::str;
use rand::Rng;
use rustc_serialize::base64::{self, ToBase64};
use crypto::hmac::Hmac;
use crypto::mac::{Mac, MacResult};
use crypto::sha1::Sha1;
use curl::http;
use curl::http::handle::Method;
use url::percent_encoding;

#[derive(Clone, Debug)]
pub struct Token<'a> { pub key: Cow<'a, str>, pub secret: Cow<'a, str> }

impl<'a> Token<'a> {
    pub fn new<K, S>(key: K, secret: S) -> Token<'a>
        where K : Into<Cow<'a, str>>, S: Into<Cow<'a, str>>
    {
        Token { key: key.into(), secret: secret.into() }
    }
}

pub type ParamList<'a> = HashMap<Cow<'a, str>, Cow<'a, str>>;

fn insert_param<'a, K, V>(param: &mut ParamList<'a>, key: K, value: V)
                          -> Option<Cow<'a, str>>
    where K : Into<Cow<'a, str>>, V: Into<Cow<'a, str>>
{
    param.insert(key.into(), value.into())
}

fn join_query<'a>(param: &ParamList<'a>) -> String {
    let mut pairs = param
        .iter()
        .map(|(k, v)| format!("{}={}", encode(&k), encode(&v)))
        .collect::<Vec<_>>();
    pairs.sort();
    pairs.connect("&")
}

fn encode(s: &str) -> String {
    percent_encoding::utf8_percent_encode(s, percent_encoding::FORM_URLENCODED_ENCODE_SET)
}

fn hmac_sha1(key: &[u8], data: &[u8]) -> MacResult {
    let mut hmac = Hmac::new(Sha1::new(), key);
    hmac.input(data);
    hmac.result()
}

fn signature(method: &str, uri: &str, query: &str, consumer_secret: &str, token_secret: Option<&str>) -> String {
    let base = format!("{}&{}&{}", encode(method), encode(uri), encode(query));
    let key  = format!("{}&{}", encode(consumer_secret), encode(token_secret.unwrap_or("")));
    let conf = base64::Config {
        char_set: base64::CharacterSet::Standard,
        newline: base64::Newline::LF,
        pad: true,
        line_length: None
    };
    debug!("Signature base string: {}", base);
    debug!("Authorization header: Authorization: {}", base);
    hmac_sha1(key.as_bytes(), base.as_bytes()).code().to_base64(conf)
}

fn header(param: &ParamList) -> String{
    let mut pairs = param
        .iter()
        .filter(|&(k, _)| k.starts_with("oauth_"))
        .map(|(k, v)| format!("{}=\"{}\"", k, encode(&v)))
        .collect::<Vec<_>>();
    pairs.sort();
    format!("OAuth {}", pairs.connect(", "))
}

fn body(param: &ParamList) -> String{
    let mut pairs = param
        .iter()
        .filter(|&(k, _)| !k.starts_with("oauth_"))
        .map(|(k, v)| format!("{}={}", k, encode(&v)))
        .collect::<Vec<_>>();
    pairs.sort();
    format!("{}", pairs.connect("&"))
}

fn get_header(method: Method, uri: &str, consumer: &Token, token: Option<&Token>, other_param: Option<&ParamList>) -> (String, String) {
    let mut param = HashMap::new();
    let timestamp = format!("{}", time::now_utc().to_timespec().sec);
    let nonce = rand::thread_rng().gen_ascii_chars().take(32).collect::<String>();

    let _ = insert_param(&mut param, "oauth_consumer_key",     consumer.key.to_string());
    let _ = insert_param(&mut param, "oauth_nonce",            nonce);
    let _ = insert_param(&mut param, "oauth_signature_method", "HMAC-SHA1");
    let _ = insert_param(&mut param, "oauth_timestamp",        timestamp);
    let _ = insert_param(&mut param, "oauth_version",          "1.0");
    if let Some(tk) = token {
        let _ = insert_param(&mut param, "oauth_token", tk.key.as_ref());
    }

    if let Some(ps) = other_param {
        for (k, v) in ps.iter() {
            let _ = insert_param(&mut param, k.as_ref(), v.as_ref());
        }
    }

    let method_str = match method {
        Method::Options => "OPTIONS",
        Method::Get => "GET",
        Method::Head => "HEAD",
        Method::Post => "POST",
        Method::Put => "PUT",
        Method::Patch => "PATCH",
        Method::Delete => "DELETE",
        Method::Trace => "TRACE",
        Method::Connect => "CONNECT"
    };

    let sign = signature(method_str, uri,
                         join_query(&param).as_ref(),
                         consumer.secret.as_ref(),
                         token.map(|t| t.secret.as_ref()));
    let _ = insert_param(&mut param, "oauth_signature", sign);

    (header(&param), body(&param))
}

pub fn authorization_header(method: Method, uri: &str, consumer: &Token, token: Option<&Token>, other_param: Option<&ParamList>) -> String {
    get_header(method, uri, consumer, token, other_param).0
}

pub fn get(uri: &str, consumer: &Token, token: Option<&Token>, other_param: Option<&ParamList>) -> String {
    let (header, body) = get_header(Method::Get, uri, consumer, token, other_param);
    let resp = http::handle()
        .get(if body.len() > 0 { format!("{}?{}", uri, body) } else { format!("{}", uri) })
        .header("Authorization", header.as_ref())
        .exec().unwrap();
    debug!("{}", resp);
    assert_eq!(200, resp.get_code());
    str::from_utf8(resp.get_body()).unwrap().to_string()
}

pub fn post(uri: &str, consumer: &Token, token: Option<&Token>, other_param: Option<&ParamList>) -> String {
    let (header, body) = get_header(Method::Post, uri, consumer, token, other_param);
    let resp = http::handle()
        .post(uri, &body)
        .header("Authorization", header.as_ref())
        .content_type("application/x-www-form-urlencoded")
        .exec().unwrap();
    debug!("{}", resp);
    assert_eq!(200, resp.get_code());
    str::from_utf8(resp.get_body()).unwrap().to_string()
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;

    #[test]
    fn query() {
        let mut map = HashMap::new();
        let _ = map.insert("aaa".into(), "AAA".into());
        let _ = map.insert("bbbb".into(), "BBBB".into());
        let query = super::join_query(&map);
        assert_eq!("aaa=AAA&bbbb=BBBB", query);
    }
}
<commit_msg>suppress missing-docs warning<commit_after>#![warn(bad_style)]
// #![warn(missing_docs)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

extern crate crypto;
extern crate curl;
#[macro_use] extern crate log;
extern crate rand;
extern crate rustc_serialize;
extern crate time;
extern crate url;

use std::borrow::Cow;
use std::collections::HashMap;
use std::str;
use rand::Rng;
use rustc_serialize::base64::{self, ToBase64};
use crypto::hmac::Hmac;
use crypto::mac::{Mac, MacResult};
use crypto::sha1::Sha1;
use curl::http;
use curl::http::handle::Method;
use url::percent_encoding;

#[derive(Clone, Debug)]
pub struct Token<'a> { pub key: Cow<'a, str>, pub secret: Cow<'a, str> }

impl<'a> Token<'a> {
    pub fn new<K, S>(key: K, secret: S) -> Token<'a>
        where K : Into<Cow<'a, str>>, S: Into<Cow<'a, str>>
    {
        Token { key: key.into(), secret: secret.into() }
    }
}

pub type ParamList<'a> = HashMap<Cow<'a, str>, Cow<'a, str>>;

fn insert_param<'a, K, V>(param: &mut ParamList<'a>, key: K, value: V)
                          -> Option<Cow<'a, str>>
    where K : Into<Cow<'a, str>>, V: Into<Cow<'a, str>>
{
    param.insert(key.into(), value.into())
}

fn join_query<'a>(param: &ParamList<'a>) -> String {
    let mut pairs = param
        .iter()
        .map(|(k, v)| format!("{}={}", encode(&k), encode(&v)))
        .collect::<Vec<_>>();
    pairs.sort();
    pairs.connect("&")
}

fn encode(s: &str) -> String {
    percent_encoding::utf8_percent_encode(s, percent_encoding::FORM_URLENCODED_ENCODE_SET)
}

fn hmac_sha1(key: &[u8], data: &[u8]) -> MacResult {
    let mut hmac = Hmac::new(Sha1::new(), key);
    hmac.input(data);
    hmac.result()
}

fn signature(method: &str, uri: &str, query: &str, consumer_secret: &str, token_secret: Option<&str>) -> String {
    let base = format!("{}&{}&{}", encode(method), encode(uri), encode(query));
    let key  = format!("{}&{}", encode(consumer_secret), encode(token_secret.unwrap_or("")));
    let conf = base64::Config {
        char_set: base64::CharacterSet::Standard,
        newline: base64::Newline::LF,
        pad: true,
        line_length: None
    };
    debug!("Signature base string: {}", base);
    debug!("Authorization header: Authorization: {}", base);
    hmac_sha1(key.as_bytes(), base.as_bytes()).code().to_base64(conf)
}

fn header(param: &ParamList) -> String{
    let mut pairs = param
        .iter()
        .filter(|&(k, _)| k.starts_with("oauth_"))
        .map(|(k, v)| format!("{}=\"{}\"", k, encode(&v)))
        .collect::<Vec<_>>();
    pairs.sort();
    format!("OAuth {}", pairs.connect(", "))
}

fn body(param: &ParamList) -> String{
    let mut pairs = param
        .iter()
        .filter(|&(k, _)| !k.starts_with("oauth_"))
        .map(|(k, v)| format!("{}={}", k, encode(&v)))
        .collect::<Vec<_>>();
    pairs.sort();
    format!("{}", pairs.connect("&"))
}

fn get_header(method: Method, uri: &str, consumer: &Token, token: Option<&Token>, other_param: Option<&ParamList>) -> (String, String) {
    let mut param = HashMap::new();
    let timestamp = format!("{}", time::now_utc().to_timespec().sec);
    let nonce = rand::thread_rng().gen_ascii_chars().take(32).collect::<String>();

    let _ = insert_param(&mut param, "oauth_consumer_key",     consumer.key.to_string());
    let _ = insert_param(&mut param, "oauth_nonce",            nonce);
    let _ = insert_param(&mut param, "oauth_signature_method", "HMAC-SHA1");
    let _ = insert_param(&mut param, "oauth_timestamp",        timestamp);
    let _ = insert_param(&mut param, "oauth_version",          "1.0");
    if let Some(tk) = token {
        let _ = insert_param(&mut param, "oauth_token", tk.key.as_ref());
    }

    if let Some(ps) = other_param {
        for (k, v) in ps.iter() {
            let _ = insert_param(&mut param, k.as_ref(), v.as_ref());
        }
    }

    let method_str = match method {
        Method::Options => "OPTIONS",
        Method::Get => "GET",
        Method::Head => "HEAD",
        Method::Post => "POST",
        Method::Put => "PUT",
        Method::Patch => "PATCH",
        Method::Delete => "DELETE",
        Method::Trace => "TRACE",
        Method::Connect => "CONNECT"
    };

    let sign = signature(method_str, uri,
                         join_query(&param).as_ref(),
                         consumer.secret.as_ref(),
                         token.map(|t| t.secret.as_ref()));
    let _ = insert_param(&mut param, "oauth_signature", sign);

    (header(&param), body(&param))
}

pub fn authorization_header(method: Method, uri: &str, consumer: &Token, token: Option<&Token>, other_param: Option<&ParamList>) -> String {
    get_header(method, uri, consumer, token, other_param).0
}

pub fn get(uri: &str, consumer: &Token, token: Option<&Token>, other_param: Option<&ParamList>) -> String {
    let (header, body) = get_header(Method::Get, uri, consumer, token, other_param);
    let resp = http::handle()
        .get(if body.len() > 0 { format!("{}?{}", uri, body) } else { format!("{}", uri) })
        .header("Authorization", header.as_ref())
        .exec().unwrap();
    debug!("{}", resp);
    assert_eq!(200, resp.get_code());
    str::from_utf8(resp.get_body()).unwrap().to_string()
}

pub fn post(uri: &str, consumer: &Token, token: Option<&Token>, other_param: Option<&ParamList>) -> String {
    let (header, body) = get_header(Method::Post, uri, consumer, token, other_param);
    let resp = http::handle()
        .post(uri, &body)
        .header("Authorization", header.as_ref())
        .content_type("application/x-www-form-urlencoded")
        .exec().unwrap();
    debug!("{}", resp);
    assert_eq!(200, resp.get_code());
    str::from_utf8(resp.get_body()).unwrap().to_string()
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;

    #[test]
    fn query() {
        let mut map = HashMap::new();
        let _ = map.insert("aaa".into(), "AAA".into());
        let _ = map.insert("bbbb".into(), "BBBB".into());
        let query = super::join_query(&map);
        assert_eq!("aaa=AAA&bbbb=BBBB", query);
    }
}
<|endoftext|>