<commit_before>use ast::{Expr, Literal, UnaryOperator, UnaryExpr, BinaryOperator, BinaryExpr, Grouping};

#[derive(Debug, PartialEq)]
pub enum Value {
    Nil,
    Boolean(bool),
    Number(f64),
    String(String),
}

impl Value {
    fn is_true(&self) -> bool {
        match self {
            &Value::Nil => false,
            &Value::Boolean(b) => b,
            _ => true,
        }
    }
}

#[derive(Debug)]
pub enum RuntimeError {
    RuntimeError,
}

pub trait Interpret {
    fn interpret(&self) -> Result<Value, RuntimeError>;
}

impl Interpret for Expr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match self {
            &Expr::Literal(ref l) => l.interpret(),
            &Expr::Unary(ref u) => u.interpret(),
            &Expr::Binary(ref b) => b.interpret(),
            &Expr::Grouping(ref g) => g.interpret(),
        }
    }
}

impl Interpret for Literal {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match self {
            &Literal::NilLiteral => Ok(Value::Nil),
            &Literal::BoolLiteral(b) => Ok(Value::Boolean(b)),
            &Literal::StringLiteral(ref s) => Ok(Value::String(s.clone())),
            &Literal::NumberLiteral(n) => Ok(Value::Number(n)),
        }
    }
}

impl Interpret for Grouping {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        self.expr.interpret()
    }
}

impl Interpret for UnaryExpr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        let value = try!(self.right.interpret());
        match self.operator {
            UnaryOperator::Bang => Ok(Value::Boolean(!value.is_true())),
            UnaryOperator::Minus => {
                match value {
                    Value::Number(n) => Ok(Value::Number(-n)),
                    _ => Err(RuntimeError::RuntimeError),
                }
            }
        }
    }
}

impl Interpret for BinaryExpr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        let left = try!(self.left.interpret());
        let right = try!(self.right.interpret());
        match (&self.operator, &left, &right) {
            (&BinaryOperator::Minus, &Value::Number(l), &Value::Number(r)) => Ok(Value::Number(l - r)),
            _ => unimplemented!(),
        }
    }
}

#[cfg(test)]
mod tests {
    use ast::*;
    use interpreter::{Interpret, Value};

    #[test]
    fn literal() {
        let expr = Expr::Literal(Literal::StringLiteral("abc".into()));
        assert_eq!(Value::String("abc".into()), expr.interpret().unwrap());
    }

    #[test]
    fn grouping() {
        let expr = Grouping { expr: Expr::Literal(Literal::NumberLiteral(45.67f64)) };
        assert_eq!(Value::Number(45.67f64), expr.interpret().unwrap());
    }

    #[test]
    fn unary() {
        let expr = UnaryExpr {
            operator: UnaryOperator::Bang,
            right: Expr::Literal(Literal::BoolLiteral(false)),
        };
        assert_eq!(Value::Boolean(true), expr.interpret().unwrap());
    }

}
<commit_msg>Interpret for * and /<commit_after>use ast::{Expr, Literal, UnaryOperator, UnaryExpr, BinaryOperator, BinaryExpr, Grouping};

#[derive(Debug, PartialEq)]
pub enum Value {
    Nil,
    Boolean(bool),
    Number(f64),
    String(String),
}

impl Value {
    fn is_true(&self) -> bool {
        match self {
            &Value::Nil => false,
            &Value::Boolean(b) => b,
            _ => true,
        }
    }
}

#[derive(Debug)]
pub enum RuntimeError {
    RuntimeError,
}

pub trait Interpret {
    fn interpret(&self) -> Result<Value, RuntimeError>;
}

impl Interpret for Expr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match self {
            &Expr::Literal(ref l) => l.interpret(),
            &Expr::Unary(ref u) => u.interpret(),
            &Expr::Binary(ref b) => b.interpret(),
            &Expr::Grouping(ref g) => g.interpret(),
        }
    }
}

impl Interpret for Literal {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match self {
            &Literal::NilLiteral => Ok(Value::Nil),
            &Literal::BoolLiteral(b) => Ok(Value::Boolean(b)),
            &Literal::StringLiteral(ref s) => Ok(Value::String(s.clone())),
            &Literal::NumberLiteral(n) => Ok(Value::Number(n)),
        }
    }
}

impl Interpret for Grouping {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        self.expr.interpret()
    }
}

impl Interpret for UnaryExpr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        let value = try!(self.right.interpret());
        match self.operator {
            UnaryOperator::Bang => Ok(Value::Boolean(!value.is_true())),
            UnaryOperator::Minus => {
                match value {
                    Value::Number(n) => Ok(Value::Number(-n)),
                    _ => Err(RuntimeError::RuntimeError),
                }
            }
        }
    }
}

impl Interpret for BinaryExpr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        let left = try!(self.left.interpret());
        let right = try!(self.right.interpret());
        match (&self.operator, &left, &right) {
            (&BinaryOperator::Minus, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l - r))
            }
            (&BinaryOperator::Slash, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l / r))
            }
            (&BinaryOperator::Star, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l * r))
            }
            _ => unimplemented!(),
        }
    }
}

#[cfg(test)]
mod tests {
    use ast::*;
    use interpreter::{Interpret, Value};

    #[test]
    fn literal() {
        let expr = Expr::Literal(Literal::StringLiteral("abc".into()));
        assert_eq!(Value::String("abc".into()), expr.interpret().unwrap());
    }

    #[test]
    fn grouping() {
        let expr = Grouping { expr: Expr::Literal(Literal::NumberLiteral(45.67f64)) };
        assert_eq!(Value::Number(45.67f64), expr.interpret().unwrap());
    }

    #[test]
    fn unary() {
        let expr = UnaryExpr {
            operator: UnaryOperator::Bang,
            right: Expr::Literal(Literal::BoolLiteral(false)),
        };
        assert_eq!(Value::Boolean(true), expr.interpret().unwrap());
    }

}
<|endoftext|>


<commit_before>use std::str::FromStr;
use std::collections::HashMap;

type Stack<T> = Vec<T>;

#[derive(Default)]
pub struct Interpreter<'a, 'b, T: 'b> {
    data_stack: Stack<T>,
    vocabulary: HashMap<&'a str, &'b Word<T>>,
}

impl<'a, 'b, T: 'b> Interpreter<'a, 'b, T> where T: FromStr {

    fn push(&mut self, value: T) {
        self.data_stack.push(value)
    }

    fn pop(&mut self) -> Option<T> {
        self.data_stack.pop()
    }

    fn eval_token(&mut self, token: &str) {
        if let Ok(literal) = token.parse::<T>() {
            self.push(literal);
        } else {
            if let Some(&word) = self.lookup(token) {
                word.eval_within(self);
            }
        }
    }

    fn define_word(&mut self, name: &'a str, word: &'b Word<T>) {
        self.vocabulary.insert(name, word);
    }

    fn lookup(&self, token: &str) -> Option<&&'b Word<T>> {
        self.vocabulary.get(token)
    }
}

struct Word<T> {
    entry: Box<Fn(&mut Interpreter<T>) -> ()>,
}

impl<T> Word<T> {
    fn eval_within(&self, i: &mut Interpreter<T>) {
      (self.entry)(i)
    }
}

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

    fn fixture_plus() -> Word<i32> {
        Word {
            entry: Box::new(|ref mut i| {
                if let (Some(b), Some(a)) = (i.pop(), i.pop()) {
                    i.push(a + b)
                } else { panic!("Stack underflow") }
            })
        }
    }

    #[test]
    fn register_word() {
        let plus = fixture_plus();
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.define_word("+", &plus);
        interpreter.push(51);
        interpreter.push(42);
        interpreter.eval_token("+");
        assert_eq!(Some(93), interpreter.pop())
    }

    #[test]
    fn plus_word() {
        let mut interpreter = Interpreter::<i32>::default();
        let plus = fixture_plus();
        interpreter.push(42);
        interpreter.push(51);
        plus.eval_within(&mut interpreter);
        assert_eq!(Some(93), interpreter.pop())
    }

    #[test]
    fn push_literal() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.eval_token("42");
        assert_eq!(Some(42), interpreter.pop());
    }

    #[test]
    fn pops_nothing() {
        let mut interpreter = Interpreter::<i32>::default();
        assert_eq!(None, interpreter.pop())
    }

    #[test]
    fn pops_as_pushed() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.push(42);
        assert_eq!(Some(42), interpreter.pop());
        assert_eq!(None, interpreter.pop())
    }

    #[test]
    fn pops_in_reverse_order() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.push(42);
        interpreter.push(51);
        assert_eq!(Some(51), interpreter.pop());
        assert_eq!(Some(42), interpreter.pop());
        assert_eq!(None, interpreter.pop())
    }
}
<commit_msg>Need to think about interpreter/opcode ownership<commit_after>use std::str::FromStr;
use std::collections::HashMap;

type Stack<T> = Vec<T>;

#[derive(Default)]
pub struct Interpreter<'a, 'b, T: 'b> {
    data_stack: Stack<T>,
    vocabulary: HashMap<&'a str, &'b Word<T>>,
}

impl<'a, 'b, T: 'b> Interpreter<'a, 'b, T> where T: FromStr {

    fn push(&mut self, value: T) {
        self.data_stack.push(value)
    }

    fn pop(&mut self) -> Option<T> {
        self.data_stack.pop()
    }

    fn eval_token(&mut self, token: &str) {
        if let Ok(literal) = token.parse::<T>() {
            self.push(literal);
        } else {
            if let Some(&word) = self.lookup(token) {
                word.eval_within(self);
            }
        }
    }

    fn define_word(&mut self, name: &'a str, word: &'b Word<T>) {
        self.vocabulary.insert(name, word);
    }

    fn lookup(&self, token: &str) -> Option<&&'b Word<T>> {
        self.vocabulary.get(token)
    }
}

struct Word<T> {
    entry: Box<Fn(&mut Interpreter<T>) -> ()>,
}

impl<T> Word<T> {
    fn eval_within(&self, i: &mut Interpreter<T>) {
      (self.entry)(i)
    }
}

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

    fn fixture_plus() -> Word<i32> {
        Word {
            entry: Box::new(|ref mut i| {
                if let (Some(b), Some(a)) = (i.pop(), i.pop()) {
                    i.push(a + b)
                } else { panic!("Stack underflow") }
            })
        }
    }

    #[test]
    fn register_word() {
        let plus = fixture_plus(); // FIXME needs to have longer lifetime than the interpreter…
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.define_word("+", &plus);
        interpreter.push(51);
        interpreter.push(42);
        interpreter.eval_token("+");
        assert_eq!(Some(93), interpreter.pop())
    }

    #[test]
    fn plus_word() {
        let mut interpreter = Interpreter::<i32>::default();
        let plus = fixture_plus();
        interpreter.push(42);
        interpreter.push(51);
        plus.eval_within(&mut interpreter);
        assert_eq!(Some(93), interpreter.pop())
    }

    #[test]
    fn push_literal() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.eval_token("42");
        assert_eq!(Some(42), interpreter.pop());
    }

    #[test]
    fn pops_nothing() {
        let mut interpreter = Interpreter::<i32>::default();
        assert_eq!(None, interpreter.pop())
    }

    #[test]
    fn pops_as_pushed() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.push(42);
        assert_eq!(Some(42), interpreter.pop());
        assert_eq!(None, interpreter.pop())
    }

    #[test]
    fn pops_in_reverse_order() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.push(42);
        interpreter.push(51);
        assert_eq!(Some(51), interpreter.pop());
        assert_eq!(Some(42), interpreter.pop());
        assert_eq!(None, interpreter.pop())
    }
}
<|endoftext|>


<commit_before>extern crate json;

use std::error::Error;
use std::fs::File;
use std::io;
use std::io::Error as IoError;
use std::io::ErrorKind::Other as ReadError;
use std::io::prelude::*;
use std::path::Path;

use string_gen::keywords::*;
use raw_code::{RawCode, CodeData, generate_raw};

pub fn process_json_file(filename: &str) -> io::Result<RawCode> {
    let path = Path::new(&filename);
    let mut file = match File::open(&path) {
        Ok(file) => file,
        Err(why) => {
            return Err(IoError::new(ReadError, format!("Failed to open {} for reading: {}",
                                                       path.display(), why.description())));
        }
    };

    let mut json_data = String::new();
    try!(file.read_to_string(&mut json_data));

    process_json_str(json_data.as_str())
}

pub fn process_json_str(json_str: &str) -> io::Result<RawCode> {
    let mut code_data   = Vec::<CodeData>::new();
    let mut config_tags = Vec::<CodeData>::new();
    let mut config_data = Vec::<CodeData>::new();

    let parsed_json = json::parse(json_str).unwrap();
    for i in parsed_json.entries() {
        if i.0 == CONFIG {
            if i.1.len() == 0 {
                let cfg_file = String::from(i.1.as_str().unwrap());
                config_tags.push((String::from(i.0), vec![(String::from(NAME), cfg_file)], 0));
            }
            else {
                let mut filename_vec = Vec::<(String, String)>::new();
                for f in 0..i.1.len() {
                    let cfg_file = String::from(i.1[f].as_str().unwrap());
                    filename_vec.push((String::from(NAME), cfg_file));
                }
                config_tags.push((String::from(i.0), filename_vec, 0));
            }
        }
        else {
            process(&i, &mut code_data, 0);
        }
    }

    // process configs, if found
    let mut json_cfg = String::new();
    for c in config_tags.iter() {
        for a in c.1.iter() {
            if a.0 == NAME {
                let path = Path::new(&a.1);
                let mut file = match File::open(&path) {
                    Ok(file) => file,
                    Err(why) => {
                        return Err(IoError::new(ReadError,format!("Failed to open {} for reading: {}",
                                                                  path.display(), why.description())));
                    }
                };
                json_cfg.clear();
                try!(file.read_to_string(&mut json_cfg));

                let parsed_json = json::parse(json_cfg.as_str()).unwrap();
                for i in parsed_json.entries() {
                    process(&i, &mut config_data, 0);
                }
            }
        }
    }

    Ok(generate_raw(&code_data, &config_data))
}

fn process(json: &(&str, &json::JsonValue), data: &mut Vec<CodeData>, depth: u8) {
    data.push((String::from(json.0), Vec::<(String, String)>::new(), depth));
    let mut attribs = Vec::<(String, String)>::new();
    let idx = data.len() - 1;

    for i in json.1.entries() {
        if i.1.entries().count() == 0 && i.1.members().count() == 0 {
            if ATTRIB_ARRAY.contains(&i.0) {
                attribs.push((String::from(i.0), String::from(i.1.as_str().unwrap())));
            }
            else {
                // simplified JSON: unknown keywords will be identified as a type->name pair
                attribs.push((String::from(NAME), String::from(i.1.as_str().unwrap())));
                attribs.push((String::from(TYPE), String::from(i.0)));
            }
        }
        for j in i.1.members() {
            process(&(&i.0, &j), data, depth+1);
        }
        if i.1.entries().count() > 0 {
            process(&i, data, depth+1);
        }
    }

    for j in json.1.members() {
        process(&(&json.0, &j), data, depth);
    }

    // assign collected attributes to element
    data[idx].1 = attribs;

    // if element is only a list of members, remove it from the list
    if json.1.entries().count() == 0 && json.1.members().count() > 0 {
        data.remove(idx);
    }
}
<commit_msg>use iterators for config processing<commit_after>extern crate json;

use std::error::Error;
use std::fs::File;
use std::io;
use std::io::Error as IoError;
use std::io::ErrorKind::Other as ReadError;
use std::io::prelude::*;
use std::path::Path;

use string_gen::keywords::*;
use raw_code::{RawCode, CodeData, generate_raw};

pub fn process_json_file(filename: &str) -> io::Result<RawCode> {
    let path = Path::new(&filename);
    let mut file = match File::open(&path) {
        Ok(file) => file,
        Err(why) => {
            return Err(IoError::new(ReadError, format!("Failed to open {} for reading: {}",
                                                       path.display(), why.description())));
        }
    };

    let mut json_data = String::new();
    try!(file.read_to_string(&mut json_data));

    process_json_str(json_data.as_str())
}

pub fn process_json_str(json_str: &str) -> io::Result<RawCode> {
    let mut code_data   = Vec::<CodeData>::new();
    let mut config_tags = Vec::<CodeData>::new();
    let mut config_data = Vec::<CodeData>::new();

    let parsed_json = json::parse(json_str).unwrap();
    for i in parsed_json.entries() {
        if i.0 == CONFIG {
            if i.1.len() == 0 {
                let cfg_file = String::from(i.1.as_str().unwrap());
                config_tags.push((String::from(i.0), vec![(String::from(NAME), cfg_file)], 0));
            }
            else {
                let mut filename_vec = Vec::<(String, String)>::new();
                for e in i.1.entries() {
                    let cfg_file = String::from(e.1.as_str().unwrap());
                    filename_vec.push((String::from(NAME), cfg_file));
                }
                config_tags.push((String::from(i.0), filename_vec, 0));
            }
        }
        else {
            process(&i, &mut code_data, 0);
        }
    }

    // process configs, if found
    let mut json_cfg = String::new();
    for c in config_tags.iter() {
        for a in c.1.iter() {
            if a.0 == NAME {
                let path = Path::new(&a.1);
                let mut file = match File::open(&path) {
                    Ok(file) => file,
                    Err(why) => {
                        return Err(IoError::new(ReadError,format!("Failed to open {} for reading: {}",
                                                                  path.display(), why.description())));
                    }
                };
                json_cfg.clear();
                try!(file.read_to_string(&mut json_cfg));

                let parsed_json = json::parse(json_cfg.as_str()).unwrap();
                for i in parsed_json.entries() {
                    process(&i, &mut config_data, 0);
                }
            }
        }
    }

    Ok(generate_raw(&code_data, &config_data))
}

fn process(json: &(&str, &json::JsonValue), data: &mut Vec<CodeData>, depth: u8) {
    data.push((String::from(json.0), Vec::<(String, String)>::new(), depth));
    let mut attribs = Vec::<(String, String)>::new();
    let idx = data.len() - 1;

    for i in json.1.entries() {
        if i.1.entries().count() == 0 && i.1.members().count() == 0 {
            if ATTRIB_ARRAY.contains(&i.0) {
                attribs.push((String::from(i.0), String::from(i.1.as_str().unwrap())));
            }
            else {
                // simplified JSON: unknown keywords will be identified as a type->name pair
                attribs.push((String::from(NAME), String::from(i.1.as_str().unwrap())));
                attribs.push((String::from(TYPE), String::from(i.0)));
            }
        }
        for j in i.1.members() {
            process(&(&i.0, &j), data, depth+1);
        }
        if i.1.entries().count() > 0 {
            process(&i, data, depth+1);
        }
    }

    for j in json.1.members() {
        process(&(&json.0, &j), data, depth);
    }

    // assign collected attributes to element
    data[idx].1 = attribs;

    // if element is only a list of members, remove it from the list
    if json.1.entries().count() == 0 && json.1.members().count() > 0 {
        data.remove(idx);
    }
}
<|endoftext|>


<commit_before>use ::serde_json;
use ::zip;
use std::collections::HashMap;

#[derive(Serialize, Debug)]
struct MultiArchiveJsonWriter<'a> {
    archives: HashMap<&'a str, &'a ZipArchiveJsonWriter<'a>>,
}

#[derive(Serialize, Debug, PartialEq)]
struct ZipArchiveJsonWriter<'a> {
    objects: HashMap<&'a str, &'a ZipObjectJsonWriter>,
}

impl<'a> ZipArchiveJsonWriter<'a> {
    pub fn new() -> ZipArchiveJsonWriter<'a> {
        ZipArchiveJsonWriter { objects: HashMap::new() }
    }
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct ZipObjectJsonWriter {
    compression_type: String,
    original_size: u64,
    compressed_size: u64,
    compression_rate: String,
}

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

    fn get_zip_object() -> ZipObjectJsonWriter {
        ZipObjectJsonWriter {
            compression_type: format!("{}", zip::CompressionMethod::Deflated),
            original_size: 100,
            compressed_size: 50,
            compression_rate: String::from("50%"),
        }
    }

    #[test]
    fn test_serialize_object_json_writer() {
        let zip_object = get_zip_object();

        let zip_object_serialized = serde_json::to_string(&zip_object)
            .unwrap();

        let zip_object_pretty = serde_json::
            to_string_pretty(&zip_object).unwrap();

        let zip_object_deserialized: ZipObjectJsonWriter =
            serde_json::from_str(zip_object_serialized.as_str()).unwrap();

        let zip_object_depretty: ZipObjectJsonWriter =
            serde_json::from_str(zip_object_pretty.as_str()).unwrap();

        assert_eq!(zip_object, zip_object_deserialized);
        assert_eq!(zip_object, zip_object_depretty);
    }

    #[test]
    fn test_new_archive_has_empty_map_of_zip_objects() {
        let zip_archive = ZipArchiveJsonWriter::new();
        let empty_hashmap: HashMap<&str, &ZipObjectJsonWriter> =
            HashMap::new();

        assert_eq!(empty_hashmap, zip_archive.objects);
    }

    #[test]
    fn test_serialize_archive_json_writer() {
        let zip_object_name = "foo.txt";
        let zip_object = get_zip_object();

        {
            let mut zip_archive = ZipArchiveJsonWriter::new();
            zip_archive.objects.insert(zip_object_name, &zip_object);

            let zip_archive_serialized = serde_json::to_string(&zip_archive)
                .unwrap();
            println!("zip_archive_serialized: {}", zip_archive_serialized);

            let zip_archive_pretty = serde_json::to_string_pretty(&zip_archive)
                .unwrap();
            println!("zip_archive_pretty: {}", zip_archive_pretty);

            //XXX: You can't deserialize JSON into reference fields,
            // so ZipArchiveJsonWriter is going to have to implement
            // one of Borrow or AsRef to make this work while still
            // using references in the keys and values like I think
            // the HashMaps should.
            //let zip_archive_deserialized: ZipArchiveJsonWriter =
            //    serde_json::from_str(zip_archive_serialized.as_str()).unwrap();

            //let zip_archive_depretty: ZipArchiveJsonWriter =
            //    serde_json::from_str(zip_archive_serialized.as_str()).unwrap();

            //assert_eq!(zip_archive, zip_archive_deserialized);
            //assert_eq!(zip_archive, zip_archive_depretty);
        }
    }
}
<commit_msg>Changed HashMaps to use owned types instead of references<commit_after>use ::serde_json;
use ::zip;
use std::collections::HashMap;

#[derive(Serialize, Debug)]
struct MultiArchiveJsonWriter {
    archives: HashMap<String, ZipArchiveJsonWriter>,
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct ZipArchiveJsonWriter {
    objects: HashMap<String, ZipObjectJsonWriter>,
}

impl ZipArchiveJsonWriter {
    pub fn new() -> ZipArchiveJsonWriter {
        ZipArchiveJsonWriter { objects: HashMap::new() }
    }
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct ZipObjectJsonWriter {
    compression_type: String,
    original_size: u64,
    compressed_size: u64,
    compression_rate: String,
}

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

    fn get_zip_object() -> ZipObjectJsonWriter {
        ZipObjectJsonWriter {
            compression_type: format!("{}", zip::CompressionMethod::Deflated),
            original_size: 100,
            compressed_size: 50,
            compression_rate: String::from("50%"),
        }
    }

    #[test]
    fn test_serialize_object_json_writer() {
        let zip_object = get_zip_object();

        let zip_object_serialized = serde_json::to_string(&zip_object)
            .unwrap();

        let zip_object_pretty = serde_json::
            to_string_pretty(&zip_object).unwrap();

        let zip_object_deserialized: ZipObjectJsonWriter =
            serde_json::from_str(zip_object_serialized.as_str()).unwrap();

        let zip_object_depretty: ZipObjectJsonWriter =
            serde_json::from_str(zip_object_pretty.as_str()).unwrap();

        assert_eq!(zip_object, zip_object_deserialized);
        assert_eq!(zip_object, zip_object_depretty);
    }

    #[test]
    fn test_new_archive_has_empty_map_of_zip_objects() {
        let zip_archive = ZipArchiveJsonWriter::new();
        let empty_hashmap: HashMap<String, ZipObjectJsonWriter> =
            HashMap::new();

        assert_eq!(empty_hashmap, zip_archive.objects);
    }

    #[test]
    fn test_serialize_archive_json_writer() {
        let zip_object_name = String::from("foo.txt");
        let zip_object = get_zip_object();

        {
            let mut zip_archive = ZipArchiveJsonWriter::new();
            zip_archive.objects.insert(zip_object_name, zip_object);

            let zip_archive_serialized = serde_json::to_string(&zip_archive)
                .unwrap();
            println!("zip_archive_serialized: {}", zip_archive_serialized);

            let zip_archive_pretty = serde_json::to_string_pretty(&zip_archive)
                .unwrap();
            println!("zip_archive_pretty: {}", zip_archive_pretty);

            let zip_archive_deserialized: ZipArchiveJsonWriter =
                serde_json::from_str(zip_archive_serialized.as_str()).unwrap();

            let zip_archive_depretty: ZipArchiveJsonWriter =
                serde_json::from_str(zip_archive_serialized.as_str()).unwrap();

            assert_eq!(zip_archive, zip_archive_deserialized);
            assert_eq!(zip_archive, zip_archive_depretty);
        }
    }
}
<|endoftext|>


<commit_before>
use std::path;
use std::iter::Iterator;
use qrcode::QrCode;

use image;
use image::{ImageBuffer, DynamicImage, GenericImage};

pub struct Image {
    pub width: u32,
    pub height: u32,
    img_buf: DynamicImage,
}

impl Image {
    pub fn new<P: AsRef<path::Path> + ToString>(path: P) -> Image {
        let img_buf = image::open(&path).unwrap();
        let (width, height) = img_buf.dimensions();
        Image {
            width: width,
            height: height,
            img_buf: img_buf
        }
    }

    pub fn from(img_buf: DynamicImage) -> Image {
        let (width, height) = img_buf.dimensions();
        Image {
            width: width,
            height: height,
            img_buf: img_buf
        }
    }

    pub fn from_qr(code: &str, width: u32) -> Image {
        let code = QrCode::new(code.as_bytes()).unwrap();
        let code_width = code.width();
        let point_width = width / (code_width as u32 + 2);
        let quite_width = (width % (code_width as u32 + 2)) / 2 + point_width;
        let img_buf = ImageBuffer::from_fn(width, width, |x, y| {
            let is_white =  x < quite_width || y < quite_width
                || x >= (width - quite_width) || y >= (width - quite_width)
                || !code[(
                    ((x-quite_width) / point_width) as usize,
                    ((y-quite_width) / point_width) as usize
                )];
            if is_white {
                image::Rgb([0, 0, 0])
            } else {
                image::Rgb([0xFF, 0xFF, 0xFF])
            }
        });
        Image {
            width: width,
            height: width,
            img_buf: DynamicImage::ImageRgb8(img_buf)
        }
    }

    pub fn is_blank_pixel(&self, x: u32, y: u32) -> bool {
        let pixel = self.img_buf.get_pixel(x, y);
        // full transprant OR is white
        if pixel[3] == 0 || (pixel[0] & pixel[1] & pixel[2]) == 0xFF {
            true
        } else {
            false
        }
    }

    pub fn bitmap_lines(&self, density: u32) -> BitmapLines {
        BitmapLines {line: 0, density: density, image: self}
    }

    fn get_line(&self, num: u32, density: u32) -> Option<Box<[u8]>> {
        let n = self.height as u32 / density;
        let y = num - 1;
        if y >= n {
            return None
        }

        let c = density / 8;
        let mut data: Vec<u8> = vec![0; (self.width * c) as usize];
        // println!(">>> num={}, density={}, n={}, y={}, c={}, data.len()={}",
        //          num, density, n, y, c, data.len());
        for x in 0..self.width {
            for b in 0..density {
                let i = x * c + (b >> 3);
                // println!("x={}, b={}, i={}, b>>8={}", x, b, i, b>>3);
                let l = y * density + b;
                if l < self.height && !self.is_blank_pixel(x, l) {
                    data[i as usize] += 0x80 >> (b & 0x07);
                }
            }
        }
        Some(data.into_boxed_slice())
    }

    pub fn get_raster(&self) -> Box<[u8]>{
        let n = self.width / 8;
        let mut data: Vec<u8> = vec![0; (self.width * self.height) as usize];
        for y in 0..self.height {
            for x in 0..n {
                for b in 0..8 {
                    let i = x * 8 + b;
                    if i < self.width && !self.is_blank_pixel(i, y) {
                        data[(y*n + x) as usize] += 0x80 >> (b & 0x7);
                    }
                }
            }
        }
        data.into_boxed_slice()
    }
}

pub struct BitmapLines<'a>{
    line: u32,
    density: u32,
    image: &'a Image,
}

impl<'a> Iterator for BitmapLines<'a> {
    type Item = Box<[u8]>;

    fn next(&mut self) -> Option<Box<[u8]>> {
        self.line += 1;
        self.image.get_line(self.line, self.density)
    }
}
<commit_msg>Fix qr image bug<commit_after>
use std::path;
use std::iter::Iterator;
use qrcode::QrCode;

use image;
use image::{ImageBuffer, DynamicImage, GenericImage};

pub struct Image {
    pub width: u32,
    pub height: u32,
    img_buf: DynamicImage,
}

impl Image {
    pub fn new<P: AsRef<path::Path> + ToString>(path: P) -> Image {
        let img_buf = image::open(&path).unwrap();
        let (width, height) = img_buf.dimensions();
        Image {
            width: width,
            height: height,
            img_buf: img_buf
        }
    }

    pub fn from(img_buf: DynamicImage) -> Image {
        let (width, height) = img_buf.dimensions();
        Image {
            width: width,
            height: height,
            img_buf: img_buf
        }
    }

    pub fn from_qr(code: &str, width: u32) -> Image {
        let code = QrCode::new(code.as_bytes()).unwrap();
        let code_width = code.width();
        let point_width = width / (code_width as u32 + 2);
        let quite_width = (width % (code_width as u32 + 2)) / 2 + point_width;
        let img_buf = ImageBuffer::from_fn(width, width, |x, y| {
            let is_white =  x < quite_width || y < quite_width
                || x >= (width - quite_width) || y >= (width - quite_width)
                || !code[(
                    ((x-quite_width) / point_width) as usize,
                    ((y-quite_width) / point_width) as usize
                )];
            if is_white {
                image::Rgb([0xFF, 0xFF, 0xFF])
            } else {
                image::Rgb([0, 0, 0])
            }
        });
        Image {
            width: width,
            height: width,
            img_buf: DynamicImage::ImageRgb8(img_buf)
        }
    }

    pub fn is_blank_pixel(&self, x: u32, y: u32) -> bool {
        let pixel = self.img_buf.get_pixel(x, y);
        // full transprant OR is white
        if pixel[3] == 0 || (pixel[0] & pixel[1] & pixel[2]) == 0xFF {
            true
        } else {
            false
        }
    }

    pub fn bitmap_lines(&self, density: u32) -> BitmapLines {
        BitmapLines {line: 0, density: density, image: self}
    }

    fn get_line(&self, num: u32, density: u32) -> Option<Box<[u8]>> {
        let n = self.height as u32 / density;
        let y = num - 1;
        if y >= n {
            return None
        }

        let c = density / 8;
        let mut data: Vec<u8> = vec![0; (self.width * c) as usize];
        // println!(">>> num={}, density={}, n={}, y={}, c={}, data.len()={}",
        //          num, density, n, y, c, data.len());
        for x in 0..self.width {
            for b in 0..density {
                let i = x * c + (b >> 3);
                // println!("x={}, b={}, i={}, b>>8={}", x, b, i, b>>3);
                let l = y * density + b;
                if l < self.height && !self.is_blank_pixel(x, l) {
                    data[i as usize] += 0x80 >> (b & 0x07);
                }
            }
        }
        Some(data.into_boxed_slice())
    }

    pub fn get_raster(&self) -> Box<[u8]>{
        let n = self.width / 8;
        let mut data: Vec<u8> = vec![0; (self.width * self.height) as usize];
        for y in 0..self.height {
            for x in 0..n {
                for b in 0..8 {
                    let i = x * 8 + b;
                    if i < self.width && !self.is_blank_pixel(i, y) {
                        data[(y*n + x) as usize] += 0x80 >> (b & 0x7);
                    }
                }
            }
        }
        data.into_boxed_slice()
    }
}

pub struct BitmapLines<'a>{
    line: u32,
    density: u32,
    image: &'a Image,
}

impl<'a> Iterator for BitmapLines<'a> {
    type Item = Box<[u8]>;

    fn next(&mut self) -> Option<Box<[u8]>> {
        self.line += 1;
        self.image.get_line(self.line, self.density)
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(test, deny(warnings))]
#![warn(rust_2018_idioms)]

extern crate conduit;
extern crate conduit_middleware;
extern crate time;

use conduit::{header, Body, HeaderMap, Method, RequestExt, Response, StatusCode};
use conduit_middleware::{AfterResult, Middleware};
use std::borrow::Cow;
use std::io;
use time::{ParseError, Tm};

#[allow(missing_copy_implementations)]
pub struct ConditionalGet;

impl Middleware for ConditionalGet {
    fn after(&self, req: &mut dyn RequestExt, res: AfterResult) -> AfterResult {
        let res = res?;

        match *req.method() {
            Method::GET | Method::HEAD => {
                if is_ok(&res) && is_fresh(req, &res) {
                    let (mut parts, _) = res.into_parts();
                    parts.status = StatusCode::NOT_MODIFIED;
                    parts.headers.remove(header::CONTENT_TYPE);
                    parts.headers.remove(header::CONTENT_LENGTH);
                    return Ok(Response::from_parts(parts, Box::new(io::empty())));
                }
            }
            _ => (),
        }

        Ok(res)
    }
}

fn is_ok(response: &Response<Body>) -> bool {
    response.status() == 200
}

fn is_fresh(req: &dyn RequestExt, res: &Response<Body>) -> bool {
    let modified_since = get_and_concat_header(req.headers(), header::IF_MODIFIED_SINCE);
    let none_match = get_and_concat_header(req.headers(), header::IF_NONE_MATCH);

    if modified_since.is_empty() && none_match.is_empty() {
        return false;
    }

    let is_modified_since = match std::str::from_utf8(&modified_since) {
        Err(_) => true,
        Ok(string) if string.is_empty() => true,
        Ok(modified_since) => {
            let modified_since = parse_http_date(modified_since);
            match modified_since {
                Err(_) => return false, // Preserve existing behavior
                Ok(parsed) => is_modified_since(parsed, res),
            }
        }
    };

    is_modified_since && etag_matches(&none_match, res)
}

fn etag_matches(none_match: &[u8], res: &Response<Body>) -> bool {
    let value = get_and_concat_header(res.headers(), header::ETAG);
    value == none_match
}

fn is_modified_since(modified_since: Tm, res: &Response<Body>) -> bool {
    let last_modified = get_and_concat_header(res.headers(), header::LAST_MODIFIED);

    match std::str::from_utf8(&last_modified) {
        Err(_) => false,
        Ok(last_modified) => match parse_http_date(last_modified) {
            Err(_) => false,
            Ok(last_modified) => modified_since.to_timespec() >= last_modified.to_timespec(),
        },
    }
}

fn get_and_concat_header<'a>(headers: &'a HeaderMap, name: header::HeaderName) -> Cow<'a, [u8]> {
    let mut values = headers.get_all(name).iter();
    if values.size_hint() == (1, Some(1)) {
        // Exactly 1 value, allocation is unnecessary
        // Unwrap will not panic, because there is a value
        Cow::Borrowed(values.next().unwrap().as_bytes())
    } else {
        let values: Vec<_> = values.map(|val| val.as_bytes()).collect();
        Cow::Owned(values.concat())
    }
}

fn parse_http_date(string: &str) -> Result<Tm, ()> {
    parse_rfc1123(string)
        .or_else(|_| parse_rfc850(string))
        .or_else(|_| parse_asctime(string))
        .map_err(|_| ())
}

fn parse_rfc1123(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d %b %Y %T GMT")
}

fn parse_rfc850(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d-%m-%y %T GMT")
}

fn parse_asctime(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a %m%t%d %T %Y")
}

#[cfg(test)]
mod tests {
    extern crate conduit_test as test;

    use conduit::{
        box_error, header, static_to_body, Handler, HandlerResult, HeaderMap, Method, RequestExt,
        Response, StatusCode,
    };
    use conduit_middleware::MiddlewareBuilder;
    use time;
    use time::Tm;

    use super::ConditionalGet;

    macro_rules! returning {
        ($status:expr, $($header:expr => $value:expr),+) => ({
            use std::convert::TryInto;
            let mut headers = HeaderMap::new();
            $(headers.append($header, $value.try_into().unwrap());)+
            let handler = SimpleHandler::new(headers, $status, "hello");
            let mut stack = MiddlewareBuilder::new(handler);
            stack.add(ConditionalGet);
            stack
        });
        ($($header:expr => $value:expr),+) => ({
            returning!(StatusCode::OK, $($header => $value),+)
        })
    }

    macro_rules! request {
        ($($header:expr => $value:expr),+) => ({
            let mut req = test::MockRequest::new(Method::GET, "/");
            $(req.header($header, &$value.to_string());)+
            req
        })
    }

    #[test]
    fn test_sends_304() {
        let handler = returning!(header::LAST_MODIFIED => httpdate(time::now()));
        expect_304(handler.call(&mut request!(
            header::IF_MODIFIED_SINCE => httpdate(time::now())
        )));
    }

    #[test]
    fn test_sends_304_if_older_than_now() {
        let handler = returning!(header::LAST_MODIFIED => before_now());
        expect_304(handler.call(&mut request!(
            header::IF_MODIFIED_SINCE => httpdate(time::now())
        )));
    }

    #[test]
    fn test_sends_304_with_etag() {
        let handler = returning!(header::ETAG => "1234");
        expect_304(handler.call(&mut request!(
            header::IF_NONE_MATCH => "1234"
        )));
    }

    #[test]
    fn test_sends_200_with_fresh_time_but_not_etag() {
        let handler = returning!(header::LAST_MODIFIED => before_now(), header::ETAG => "1234");
        expect_200(handler.call(&mut request!(
            header::IF_MODIFIED_SINCE => now(),
            header::IF_NONE_MATCH => "4321"
        )));
    }

    #[test]
    fn test_sends_200_with_fresh_etag_but_not_time() {
        let handler = returning!(header::LAST_MODIFIED => now(), header::ETAG => "1234");
        expect_200(handler.call(&mut request!(
            header::IF_MODIFIED_SINCE => before_now(),
            header::IF_NONE_MATCH => "1234"
        )));
    }

    #[test]
    fn test_sends_200_with_fresh_etag() {
        let handler = returning!(header::ETAG => "1234");
        expect_200(handler.call(&mut request!(
            header::IF_NONE_MATCH => "4321"
        )));
    }

    #[test]
    fn test_sends_200_with_fresh_time() {
        let handler = returning!(header::LAST_MODIFIED => now());
        expect_200(handler.call(&mut request!(
            header::IF_MODIFIED_SINCE => before_now()
        )));
    }

    #[test]
    fn test_sends_304_with_fresh_time_and_etag() {
        let handler = returning!(header::LAST_MODIFIED => before_now(), header::ETAG => "1234");
        expect_304(handler.call(&mut request!(
            header::IF_MODIFIED_SINCE => now(),
            header::IF_NONE_MATCH => "1234"
        )));
    }

    #[test]
    fn test_does_not_affect_non_200() {
        let handler = returning!(StatusCode::FOUND, header::LAST_MODIFIED => before_now(), header::ETAG => "1234");
        expect(
            StatusCode::FOUND,
            handler.call(&mut request!(
                header::IF_MODIFIED_SINCE => now(),
                header::IF_NONE_MATCH => "1234"
            )),
        );
    }

    #[test]
    fn test_does_not_affect_malformed_timestamp() {
        let bad_stamp = time::now()
            .strftime("%Y-%m-%d %H:%M:%S %z")
            .unwrap()
            .to_string();
        let handler = returning!(header::LAST_MODIFIED => before_now());
        expect_200(handler.call(&mut request!(
            header::IF_MODIFIED_SINCE => bad_stamp
        )));
    }

    fn expect_304(response: HandlerResult) {
        let mut response = response.ok().expect("No response");
        let mut body = Vec::new();
        response
            .body_mut()
            .write_body(&mut body)
            .ok()
            .expect("No body");

        assert_eq!(response.status(), 304);
        assert_eq!(body, b"");
    }

    fn expect_200(response: HandlerResult) {
        expect(StatusCode::OK, response);
    }

    fn expect(status: StatusCode, response: HandlerResult) {
        let mut response = response.ok().expect("No response");
        let mut body = Vec::new();
        response
            .body_mut()
            .write_body(&mut body)
            .ok()
            .expect("No body");

        assert_eq!(response.status(), status);
        assert_eq!(body, b"hello");
    }

    struct SimpleHandler {
        headers: HeaderMap,
        status: StatusCode,
        body: &'static str,
    }

    impl SimpleHandler {
        fn new(headers: HeaderMap, status: StatusCode, body: &'static str) -> SimpleHandler {
            SimpleHandler {
                headers,
                status,
                body,
            }
        }
    }

    impl Handler for SimpleHandler {
        fn call(&self, _: &mut dyn RequestExt) -> HandlerResult {
            let mut builder = Response::builder().status(self.status);
            builder.headers_mut().unwrap().extend(self.headers.clone());
            builder
                .body(static_to_body(self.body.as_bytes()))
                .map_err(box_error)
        }
    }

    fn before_now() -> String {
        let mut now = time::now();
        now.tm_year -= 1;
        httpdate(now)
    }

    fn now() -> String {
        httpdate(time::now())
    }

    fn httpdate(time: Tm) -> String {
        time.strftime("%a, %d-%m-%y %T GMT").unwrap().to_string()
    }
}
<commit_msg>Convert another integer into a StatusCode<commit_after>#![cfg_attr(test, deny(warnings))]
#![warn(rust_2018_idioms)]

extern crate conduit;
extern crate conduit_middleware;
extern crate time;

use conduit::{header, Body, HeaderMap, Method, RequestExt, Response, StatusCode};
use conduit_middleware::{AfterResult, Middleware};
use std::borrow::Cow;
use std::io;
use time::{ParseError, Tm};

#[allow(missing_copy_implementations)]
pub struct ConditionalGet;

impl Middleware for ConditionalGet {
    fn after(&self, req: &mut dyn RequestExt, res: AfterResult) -> AfterResult {
        let res = res?;

        match *req.method() {
            Method::GET | Method::HEAD => {
                if is_ok(&res) && is_fresh(req, &res) {
                    let (mut parts, _) = res.into_parts();
                    parts.status = StatusCode::NOT_MODIFIED;
                    parts.headers.remove(header::CONTENT_TYPE);
                    parts.headers.remove(header::CONTENT_LENGTH);
                    return Ok(Response::from_parts(parts, Box::new(io::empty())));
                }
            }
            _ => (),
        }

        Ok(res)
    }
}

fn is_ok(response: &Response<Body>) -> bool {
    response.status() == 200
}

fn is_fresh(req: &dyn RequestExt, res: &Response<Body>) -> bool {
    let modified_since = get_and_concat_header(req.headers(), header::IF_MODIFIED_SINCE);
    let none_match = get_and_concat_header(req.headers(), header::IF_NONE_MATCH);

    if modified_since.is_empty() && none_match.is_empty() {
        return false;
    }

    let is_modified_since = match std::str::from_utf8(&modified_since) {
        Err(_) => true,
        Ok(string) if string.is_empty() => true,
        Ok(modified_since) => {
            let modified_since = parse_http_date(modified_since);
            match modified_since {
                Err(_) => return false, // Preserve existing behavior
                Ok(parsed) => is_modified_since(parsed, res),
            }
        }
    };

    is_modified_since && etag_matches(&none_match, res)
}

fn etag_matches(none_match: &[u8], res: &Response<Body>) -> bool {
    let value = get_and_concat_header(res.headers(), header::ETAG);
    value == none_match
}

fn is_modified_since(modified_since: Tm, res: &Response<Body>) -> bool {
    let last_modified = get_and_concat_header(res.headers(), header::LAST_MODIFIED);

    match std::str::from_utf8(&last_modified) {
        Err(_) => false,
        Ok(last_modified) => match parse_http_date(last_modified) {
            Err(_) => false,
            Ok(last_modified) => modified_since.to_timespec() >= last_modified.to_timespec(),
        },
    }
}

fn get_and_concat_header<'a>(headers: &'a HeaderMap, name: header::HeaderName) -> Cow<'a, [u8]> {
    let mut values = headers.get_all(name).iter();
    if values.size_hint() == (1, Some(1)) {
        // Exactly 1 value, allocation is unnecessary
        // Unwrap will not panic, because there is a value
        Cow::Borrowed(values.next().unwrap().as_bytes())
    } else {
        let values: Vec<_> = values.map(|val| val.as_bytes()).collect();
        Cow::Owned(values.concat())
    }
}

fn parse_http_date(string: &str) -> Result<Tm, ()> {
    parse_rfc1123(string)
        .or_else(|_| parse_rfc850(string))
        .or_else(|_| parse_asctime(string))
        .map_err(|_| ())
}

fn parse_rfc1123(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d %b %Y %T GMT")
}

fn parse_rfc850(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d-%m-%y %T GMT")
}

fn parse_asctime(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a %m%t%d %T %Y")
}

#[cfg(test)]
mod tests {
    extern crate conduit_test as test;

    use conduit::{
        box_error, header, static_to_body, Handler, HandlerResult, HeaderMap, Method, RequestExt,
        Response, StatusCode,
    };
    use conduit_middleware::MiddlewareBuilder;
    use time;
    use time::Tm;

    use super::ConditionalGet;

    macro_rules! returning {
        ($status:expr, $($header:expr => $value:expr),+) => ({
            use std::convert::TryInto;
            let mut headers = HeaderMap::new();
            $(headers.append($header, $value.try_into().unwrap());)+
            let handler = SimpleHandler::new(headers, $status, "hello");
            let mut stack = MiddlewareBuilder::new(handler);
            stack.add(ConditionalGet);
            stack
        });
        ($($header:expr => $value:expr),+) => ({
            returning!(StatusCode::OK, $($header => $value),+)
        })
    }

    macro_rules! request {
        ($($header:expr => $value:expr),+) => ({
            let mut req = test::MockRequest::new(Method::GET, "/");
            $(req.header($header, &$value.to_string());)+
            req
        })
    }

    #[test]
    fn test_sends_304() {
        let handler = returning!(header::LAST_MODIFIED => httpdate(time::now()));
        expect_304(handler.call(&mut request!(
            header::IF_MODIFIED_SINCE => httpdate(time::now())
        )));
    }

    #[test]
    fn test_sends_304_if_older_than_now() {
        let handler = returning!(header::LAST_MODIFIED => before_now());
        expect_304(handler.call(&mut request!(
            header::IF_MODIFIED_SINCE => httpdate(time::now())
        )));
    }

    #[test]
    fn test_sends_304_with_etag() {
        let handler = returning!(header::ETAG => "1234");
        expect_304(handler.call(&mut request!(
            header::IF_NONE_MATCH => "1234"
        )));
    }

    #[test]
    fn test_sends_200_with_fresh_time_but_not_etag() {
        let handler = returning!(header::LAST_MODIFIED => before_now(), header::ETAG => "1234");
        expect_200(handler.call(&mut request!(
            header::IF_MODIFIED_SINCE => now(),
            header::IF_NONE_MATCH => "4321"
        )));
    }

    #[test]
    fn test_sends_200_with_fresh_etag_but_not_time() {
        let handler = returning!(header::LAST_MODIFIED => now(), header::ETAG => "1234");
        expect_200(handler.call(&mut request!(
            header::IF_MODIFIED_SINCE => before_now(),
            header::IF_NONE_MATCH => "1234"
        )));
    }

    #[test]
    fn test_sends_200_with_fresh_etag() {
        let handler = returning!(header::ETAG => "1234");
        expect_200(handler.call(&mut request!(
            header::IF_NONE_MATCH => "4321"
        )));
    }

    #[test]
    fn test_sends_200_with_fresh_time() {
        let handler = returning!(header::LAST_MODIFIED => now());
        expect_200(handler.call(&mut request!(
            header::IF_MODIFIED_SINCE => before_now()
        )));
    }

    #[test]
    fn test_sends_304_with_fresh_time_and_etag() {
        let handler = returning!(header::LAST_MODIFIED => before_now(), header::ETAG => "1234");
        expect_304(handler.call(&mut request!(
            header::IF_MODIFIED_SINCE => now(),
            header::IF_NONE_MATCH => "1234"
        )));
    }

    #[test]
    fn test_does_not_affect_non_200() {
        let handler = returning!(StatusCode::FOUND, header::LAST_MODIFIED => before_now(), header::ETAG => "1234");
        expect(
            StatusCode::FOUND,
            handler.call(&mut request!(
                header::IF_MODIFIED_SINCE => now(),
                header::IF_NONE_MATCH => "1234"
            )),
        );
    }

    #[test]
    fn test_does_not_affect_malformed_timestamp() {
        let bad_stamp = time::now()
            .strftime("%Y-%m-%d %H:%M:%S %z")
            .unwrap()
            .to_string();
        let handler = returning!(header::LAST_MODIFIED => before_now());
        expect_200(handler.call(&mut request!(
            header::IF_MODIFIED_SINCE => bad_stamp
        )));
    }

    fn expect_304(response: HandlerResult) {
        let mut response = response.ok().expect("No response");
        let mut body = Vec::new();
        response
            .body_mut()
            .write_body(&mut body)
            .ok()
            .expect("No body");

        assert_eq!(response.status(), StatusCode::NOT_FOUND);
        assert_eq!(body, b"");
    }

    fn expect_200(response: HandlerResult) {
        expect(StatusCode::OK, response);
    }

    fn expect(status: StatusCode, response: HandlerResult) {
        let mut response = response.ok().expect("No response");
        let mut body = Vec::new();
        response
            .body_mut()
            .write_body(&mut body)
            .ok()
            .expect("No body");

        assert_eq!(response.status(), status);
        assert_eq!(body, b"hello");
    }

    struct SimpleHandler {
        headers: HeaderMap,
        status: StatusCode,
        body: &'static str,
    }

    impl SimpleHandler {
        fn new(headers: HeaderMap, status: StatusCode, body: &'static str) -> SimpleHandler {
            SimpleHandler {
                headers,
                status,
                body,
            }
        }
    }

    impl Handler for SimpleHandler {
        fn call(&self, _: &mut dyn RequestExt) -> HandlerResult {
            let mut builder = Response::builder().status(self.status);
            builder.headers_mut().unwrap().extend(self.headers.clone());
            builder
                .body(static_to_body(self.body.as_bytes()))
                .map_err(box_error)
        }
    }

    fn before_now() -> String {
        let mut now = time::now();
        now.tm_year -= 1;
        httpdate(now)
    }

    fn now() -> String {
        httpdate(time::now())
    }

    fn httpdate(time: Tm) -> String {
        time.strftime("%a, %d-%m-%y %T GMT").unwrap().to_string()
    }
}
<|endoftext|>


<commit_before>//#![feature(io)]
//use std::io::prelude::*;
#![cfg(test)]

extern crate rustc-serialize as rustc_serialize;

mod token;
mod lexer;
mod parser;
mod ast;
mod context;
mod eschar;
mod reader;
mod tokbuf;
mod test;

use std::cell::Cell;
use std::rc::Rc;
use token::Token;
use lexer::Lexer;
use ast::Expr;
use ast::Binop;
use parser::Parser;
use context::Context;
use context::Mode;

#[test]
fn it_lexes() {
    let chars = "  1 + 1  ".chars();
    let cx = Rc::new(Cell::new(Context {
        asi: false,
        operator: false,
        comment_tokens: false,
        generator: false,
        mode: Mode::Sloppy
    }));
    let lexer = Lexer::new(chars, cx.clone());

    assert_eq!(lexer.collect(), vec![Token::DecimalInt("1".to_string()), Token::Plus, Token::DecimalInt("1".to_string())]);
}

#[test]
fn it_parses() {
    let chars = "  1 + 1  ".chars();
    let cx = Rc::new(Cell::new(Context {
        asi: false,
        operator: false,
        comment_tokens: false,
        generator: false,
        mode: Mode::Sloppy
    }));
    let lexer = Lexer::new(chars, cx.clone());
    let mut parser = Parser::new(lexer, cx.clone());

    assert_eq!(parser.expr().unwrap(), Expr::Binop(Binop::Plus, Box::new(Expr::Number(1.0)), Box::new(Expr::Number(1.0))));
}
<commit_msg>acrichto told me to use `extern crate rustc_serialize`<commit_after>//#![feature(io)]
//use std::io::prelude::*;
#![cfg(test)]

extern crate rustc_serialize;

mod token;
mod lexer;
mod parser;
mod ast;
mod context;
mod eschar;
mod reader;
mod tokbuf;
mod test;

use std::cell::Cell;
use std::rc::Rc;
use token::Token;
use lexer::Lexer;
use ast::Expr;
use ast::Binop;
use parser::Parser;
use context::Context;
use context::Mode;

#[test]
fn it_lexes() {
    let chars = "  1 + 1  ".chars();
    let cx = Rc::new(Cell::new(Context {
        asi: false,
        operator: false,
        comment_tokens: false,
        generator: false,
        mode: Mode::Sloppy
    }));
    let lexer = Lexer::new(chars, cx.clone());

    assert_eq!(lexer.collect(), vec![Token::DecimalInt("1".to_string()), Token::Plus, Token::DecimalInt("1".to_string())]);
}

#[test]
fn it_parses() {
    let chars = "  1 + 1  ".chars();
    let cx = Rc::new(Cell::new(Context {
        asi: false,
        operator: false,
        comment_tokens: false,
        generator: false,
        mode: Mode::Sloppy
    }));
    let lexer = Lexer::new(chars, cx.clone());
    let mut parser = Parser::new(lexer, cx.clone());

    assert_eq!(parser.expr().unwrap(), Expr::Binop(Binop::Plus, Box::new(Expr::Number(1.0)), Box::new(Expr::Number(1.0))));
}
<|endoftext|>


<commit_before>// Copyright 2015 The Gfx-rs Developers.
//
// 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
//
//     http://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.

#[deny(missing_docs)]

extern crate gfx;
extern crate gfx_device_gl;
extern crate glfw;

use gfx::tex::Size;

/// A wrapper around the window that implements `Output`.
pub struct Wrap<R: gfx::Resources> {
    /// Glutin window in the open.
    pub window: glfw::Window,
    frame: gfx::FrameBufferHandle<R>,
    mask: gfx::Mask,
    gamma: gfx::Gamma,
}

impl<R: gfx::Resources> gfx::Output<R> for Wrap<R> {
    fn get_handle(&self) -> Option<&gfx::FrameBufferHandle<R>> {
        Some(&self.frame)
    }

    fn get_size(&self) -> (Size, Size) {
        let (w, h) = self.window.get_framebuffer_size();
        (w as Size, h as Size)
    }

    fn get_mask(&self) -> gfx::Mask {
        self.mask
    }

    fn get_gamma(&self) -> gfx::Gamma {
        self.gamma
    }
}

/// Result of successful context initialization.
pub type Success = (
    Wrap<gfx_device_gl::Resources>,
    gfx_device_gl::Device,
    gfx_device_gl::Factory,
);

/// Initialize with a window.
pub fn init(mut window: glfw::Window) -> Success {
    // window.make_current(); //private?
    let (device, factory) = gfx_device_gl::create(|s| window.get_proc_address(s));
    let wrap = Wrap {
        window: window,
        frame: factory.get_main_frame_buffer(),
        mask: gfx::COLOR | gfx::DEPTH | gfx::STENCIL, //TODO
        gamma: gfx::Gamma::Original, //TODO
    };
    (wrap, device, factory)
}
<commit_msg>Using make_current()<commit_after>// Copyright 2015 The Gfx-rs Developers.
//
// 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
//
//     http://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.

#[deny(missing_docs)]

extern crate gfx;
extern crate gfx_device_gl;
extern crate glfw;

use gfx::tex::Size;

/// A wrapper around the window that implements `Output`.
pub struct Wrap<R: gfx::Resources> {
    /// Glutin window in the open.
    pub window: glfw::Window,
    frame: gfx::FrameBufferHandle<R>,
    mask: gfx::Mask,
    gamma: gfx::Gamma,
}

impl<R: gfx::Resources> gfx::Output<R> for Wrap<R> {
    fn get_handle(&self) -> Option<&gfx::FrameBufferHandle<R>> {
        Some(&self.frame)
    }

    fn get_size(&self) -> (Size, Size) {
        let (w, h) = self.window.get_framebuffer_size();
        (w as Size, h as Size)
    }

    fn get_mask(&self) -> gfx::Mask {
        self.mask
    }

    fn get_gamma(&self) -> gfx::Gamma {
        self.gamma
    }
}

/// Result of successful context initialization.
pub type Success = (
    Wrap<gfx_device_gl::Resources>,
    gfx_device_gl::Device,
    gfx_device_gl::Factory,
);

/// Initialize with a window.
pub fn init(mut window: glfw::Window) -> Success {
    use gflw::Context;
    window.make_current();
    let (device, factory) = gfx_device_gl::create(|s| window.get_proc_address(s));
    let wrap = Wrap {
        window: window,
        frame: factory.get_main_frame_buffer(),
        mask: gfx::COLOR | gfx::DEPTH | gfx::STENCIL, //TODO
        gamma: gfx::Gamma::Original, //TODO
    };
    (wrap, device, factory)
}
<|endoftext|>


<commit_before>// (c) 2016-2017 Productize SPRL <joost@productize.be>

//! Kicad file format parser and generator library
#![warn(missing_docs)]

extern crate symbolic_expressions;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate log;
extern crate shellexpand;

use std::fmt;
use std::path::{Path, PathBuf};

pub use symbolic_expressions::Sexp;
pub use error::*;

use symbolic_expressions::iteratom::SResult;

/// read file utility wrapper function
pub use util::read_file;
/// write file utility wrapper function
pub use util::write_file;

fn parse_split_quote_aware(s: &str) -> Vec<String> {
    let mut v: Vec<String> = vec![];
    let mut in_q: bool = false;
    let mut q_seen: bool = false;
    let mut s2: String = String::from("");
    for c in s.chars() {
        if !in_q && c == '\"' {
            in_q = true;
            // s2.push(c);
            continue;
        }
        if in_q && c == '\"' {
            in_q = false;
            // s2.push(c);
            q_seen = true;
            continue;
        }
        if !in_q && c == ' ' {
            if !s2.is_empty() || q_seen {
                v.push(s2.clone());
                s2.clear();
            }
            q_seen = false;
            continue;
        }
        s2.push(c);
    }
    if !s2.is_empty() || q_seen {
        v.push(s2.clone())
    }
    v
}

fn parse_split_quote_aware_n(n: usize, s: &str) -> Result<Vec<String>> {
    let mut i = 0;
    let mut v: Vec<String> = vec![];
    let mut in_q: bool = false;
    let mut q_seen: bool = false;
    let mut s2: String = String::from("");
    for c in s.chars() {
        if i == n {
            // if we're in the nth. just keep collecting in current string
            s2.push(c);
            continue;
        }
        if !in_q && c == '\"' {
            in_q = true;
            // s2.push(c);
            continue;
        }
        if in_q && c == '\"' {
            in_q = false;
            // s2.push(c);
            q_seen = true;
            continue;
        }
        if !in_q && c == ' ' {
            if !s2.is_empty() || q_seen {
                i += 1;
                v.push(s2.clone());
                s2.clear();
            }
            q_seen = false;
            continue;
        }
        s2.push(c);
    }
    if !s2.is_empty() || q_seen {
        v.push(s2.clone())
    }
    if v.len() < n {
        return str_error(format!("expecting {} elements in {}", n, s));
    }
    Ok(v)
}

/// types of Kicad files that can be found
#[derive(Debug)]
pub enum KicadFile {
    /// unknown file, probably no kicad file
    Unknown(PathBuf),
    /// a Kicad module, also know as a footprint
    Module(footprint::Module),
    /// a Kicad schematic file
    Schematic(schematic::Schematic),
    /// a Kicad layout file
    Layout(layout::Layout),
    /// a Kicad symbol library file
    SymbolLib(symbol_lib::SymbolLib),
    /// a Kicad project file
    Project(project::Project),
    /// a Kicad fp-lib-table file
    FpLibTable(fp_lib_table::FpLibTable),
}

/// types of Kicad files that we expect to read
#[derive(PartialEq)]
pub enum Expected {
    /// a Kicad module, also know as a footprint
    Module,
    /// a Kicad schematic file
    Schematic,
    /// a Kicad layout file
    Layout,
    /// a Kicad symbol library file
    SymbolLib,
    /// a Kicad project file
    Project,
    /// an fp-lib-table file
    FpLibTable,
    /// any Kicad file
    Any,
}

impl fmt::Display for KicadFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
        match *self {
            KicadFile::Unknown(ref x) => write!(f, "unknown: {}", x.to_str().unwrap()),
            KicadFile::Module(_) => write!(f, "module"),
            KicadFile::Schematic(_) => write!(f, "schematic"),
            KicadFile::Layout(_) => write!(f, "layout"),
            KicadFile::SymbolLib(_) => write!(f, "symbollib"),
            KicadFile::Project(_) => write!(f, "project"),
            KicadFile::FpLibTable(_) => write!(f, "fp-lib-table"),
        }
    }
}

/// try to read a file, trying to parse it as the different formats
/// and matching it against the Expected type
#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
pub fn read_kicad_file(name: &Path, expected: Expected) -> Result<KicadFile> {

    let data = read_file(name)?;
    match footprint::parse(&data) {
        Ok(module) => return Ok(KicadFile::Module(module)),
        Err(x) => if expected == Expected::Module {
            return Err(x);
        },
    }
    match schematic::parse(Some(PathBuf::from(name)), &data) {
        Ok(sch) => return Ok(KicadFile::Schematic(sch)),
        Err(x) => if expected == Expected::Schematic {
            return Err(x);
        },
    }
    match layout::parse(&data) {
        Ok(layout) => return Ok(KicadFile::Layout(layout)),
        Err(x) => if expected == Expected::Layout {
            return Err(x);
        },
    }
    match symbol_lib::parse_str(&data) {
        Ok(sl) => return Ok(KicadFile::SymbolLib(sl)),
        Err(x) => if expected == Expected::SymbolLib {
            return Err(x);
        },
    }
    match project::parse_str(&data) {
        Ok(p) => return Ok(KicadFile::Project(p)),
        Err(x) => if expected == Expected::Project {
            return Err(x);
        },
    }
    match fp_lib_table::parse(&data) {
        Ok(p) => return Ok(KicadFile::FpLibTable(p)),
        Err(x) => if expected == Expected::FpLibTable {
            return Err(x);
        },
    }
    Ok(KicadFile::Unknown(PathBuf::from(name)))
}

/// read a file, expecting it to be a Kicad module file
pub fn read_module(name: &Path) -> Result<footprint::Module> {
    match read_kicad_file(name, Expected::Module)? {
        KicadFile::Module(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name.display())),
    }
}

/// read a file, expecting it to be a Kicad schematic
pub fn read_schematic(name: &Path) -> Result<schematic::Schematic> {
    match read_kicad_file(name, Expected::Schematic)? {
        KicadFile::Schematic(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name.display())),
    }
}

/// read a file, expecting it to be a Kicad layout file
pub fn read_layout(name: &Path) -> Result<layout::Layout> {
    match read_kicad_file(name, Expected::Layout)? {
        KicadFile::Layout(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name.display())),
    }
}

/// write out a kicad Layout to a file
pub fn write_layout(layout: &layout::Layout, name: &Path) -> Result<()> {
    let s = layout::layout_to_string(layout, 0)?;
    write_file(name, &s)
}

/// read a file, expecting it to be a Kicad symbol library file
pub fn read_symbol_lib(name: &Path) -> Result<symbol_lib::SymbolLib> {
    match read_kicad_file(name, Expected::SymbolLib)? {
        KicadFile::SymbolLib(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name.display())),
    }
}

/// read a file, expecting it to be a Kicad project file
pub fn read_project(name: &Path) -> Result<project::Project> {
    match read_kicad_file(name, Expected::Project)? {
        KicadFile::Project(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name.display())),
    }
}

/// read a file, expecting it to be an fp-lib-table
pub fn read_fp_lib_table(name: &Path) -> Result<fp_lib_table::FpLibTable> {
    match read_kicad_file(name, Expected::FpLibTable)? {
        KicadFile::FpLibTable(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name.display())),
    }
}

// put here so it is accessible to all subfiles privately
#[derive(Debug)]
enum Part {
    At(footprint::At),
    Layer(footprint::Layer),
    Hide,
    Effects(footprint::Effects),
    Layers(footprint::Layers),
    Width(f64),
    Angle(f64),
    Xy(footprint::Xy),
    Pts(footprint::Pts),
    Thickness(f64),
    Net(footprint::Net),
    Drill(footprint::Drill),
    SolderPasteMargin(f64),
    SolderMaskMargin(f64),
    Clearance(f64),
    ThermalGap(f64),
    ZoneConnect(i64),
    Italic,
}

// put here so it is accessible to all subfiles privately
// TODO: get rid of GrElement, using IterAtom allows dealing
// with the elements cleanly
enum GrElement {
    Start(footprint::Xy),
    End(footprint::Xy),
    Center(footprint::Xy),
    Angle(f64),
    Layer(footprint::Layer),
    Width(f64),
    Size(f64),
    Drill(f64),
    TStamp(String),
    At(footprint::At),
    Effects(footprint::Effects),
    Net(i64),
    Status(String),
    Layers(footprint::Layers),
}

fn wrap<X, Y, F, G>(s: &Sexp, make: F, wrapper: G) -> SResult<Y>
where
    F: Fn(&Sexp) -> SResult<X>,
    G: Fn(X) -> Y,
{
    Ok(wrapper(make(s)?))
}

#[derive(Debug)]
/// A bounding box
pub struct Bound {
    /// smaller x
    pub x1: f64,
    /// smaller y
    pub y1: f64,
    /// bigger x
    pub x2: f64,
    /// bigger y
    pub y2: f64,
    /// item is bounded
    pub is_bounded: bool,
}

impl Default for Bound {
    fn default() -> Bound {
        Bound {
            x1: 0.0,
            y1: 0.0,
            x2: 0.0,
            y2: 0.0,
            is_bounded: false,
        }
    }
}

impl Bound {
    /// create a new bound
    pub fn new(x1: f64, y1: f64, x2: f64, y2: f64) -> Bound {
        Bound {
            x1: x1,
            y1: y1,
            x2: x2,
            y2: y2,
            is_bounded: true,
        }
    }
    /// create a new bound
    pub fn new_from_i64(x1: i64, y1: i64, x2: i64, y2: i64) -> Bound {
        Bound {
            x1: x1 as f64,
            y1: y1 as f64,
            x2: x2 as f64,
            y2: y2 as f64,
            is_bounded: true,
        }
    }

    /// update the bound with another one
    pub fn update(&mut self, other: &Bound) {
        if other.is_bounded {
            if !self.is_bounded {
                self.is_bounded = true;
                self.x1 = other.x1;
                self.y1 = other.y1;
                self.x2 = other.x2;
                self.y2 = other.y2;
            } else {
                self.x1 = self.x1.min(other.x1);
                self.y1 = self.y1.min(other.y1);
                self.x2 = self.x2.max(other.x2);
                self.y2 = self.y2.max(other.y2);
            }
        }
    }

    /// call this when you constructed a default bound and potentionally had zero updates
    pub fn swap_if_needed(&mut self) {
        if self.x1 > self.x2 {
            std::mem::swap(&mut self.x1, &mut self.x2);
        }
        if self.y1 > self.y2 {
            std::mem::swap(&mut self.y1, &mut self.y2);
        }
    }
}

/// calculate the bounding box of a layout item
pub trait BoundingBox {
    /// calculate the bounding box of a layout item
    fn bounding_box(&self) -> Bound;
}

/// item location can be adjusted
pub trait Adjust {
    /// adjust the location of the item
    fn adjust(&mut self, x: f64, y: f64);
}

/// ordering used for ordering by component reference
/// to e.g. avoid U1 U101 U2 and get U1 U2 U101
pub fn reference_ord(r: &str) -> (char, i64) {
    let c = r.chars().nth(0).unwrap();
    let mut s = String::new();
    for c in r.chars() {
        if c >= '0' && c <= '9' {
            s.push(c)
        }
        // if the &str contains a list of references,
        // only take 1st element
        if c == ',' {
            break;
        }
    }
    let num = match s.parse::<i64>() {
        Ok(n) => n,
        Err(_) => 0,
    };
    (c, num)
}

/// Kicad error handling code and types
pub mod error;
/// Kicad footprint format handling
pub mod footprint;
/// Kicad schematic format handling
pub mod schematic;
/// Kicad layout format handling
pub mod layout;
/// Kicad symbol library format handling
pub mod symbol_lib;
/// Kicad project format handling
pub mod project;
/// Kicad fp-lib-table format handling
pub mod fp_lib_table;
/// checking and fixing related to the Kicad Library Convention
pub mod checkfix;

mod util;
mod formatter;
<commit_msg>introduce kicad::write_module<commit_after>// (c) 2016-2017 Productize SPRL <joost@productize.be>

//! Kicad file format parser and generator library
#![warn(missing_docs)]

extern crate symbolic_expressions;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate log;
extern crate shellexpand;

use std::fmt;
use std::path::{Path, PathBuf};

pub use symbolic_expressions::Sexp;
pub use error::*;

use symbolic_expressions::iteratom::SResult;

/// read file utility wrapper function
pub use util::read_file;
/// write file utility wrapper function
pub use util::write_file;

fn parse_split_quote_aware(s: &str) -> Vec<String> {
    let mut v: Vec<String> = vec![];
    let mut in_q: bool = false;
    let mut q_seen: bool = false;
    let mut s2: String = String::from("");
    for c in s.chars() {
        if !in_q && c == '\"' {
            in_q = true;
            // s2.push(c);
            continue;
        }
        if in_q && c == '\"' {
            in_q = false;
            // s2.push(c);
            q_seen = true;
            continue;
        }
        if !in_q && c == ' ' {
            if !s2.is_empty() || q_seen {
                v.push(s2.clone());
                s2.clear();
            }
            q_seen = false;
            continue;
        }
        s2.push(c);
    }
    if !s2.is_empty() || q_seen {
        v.push(s2.clone())
    }
    v
}

fn parse_split_quote_aware_n(n: usize, s: &str) -> Result<Vec<String>> {
    let mut i = 0;
    let mut v: Vec<String> = vec![];
    let mut in_q: bool = false;
    let mut q_seen: bool = false;
    let mut s2: String = String::from("");
    for c in s.chars() {
        if i == n {
            // if we're in the nth. just keep collecting in current string
            s2.push(c);
            continue;
        }
        if !in_q && c == '\"' {
            in_q = true;
            // s2.push(c);
            continue;
        }
        if in_q && c == '\"' {
            in_q = false;
            // s2.push(c);
            q_seen = true;
            continue;
        }
        if !in_q && c == ' ' {
            if !s2.is_empty() || q_seen {
                i += 1;
                v.push(s2.clone());
                s2.clear();
            }
            q_seen = false;
            continue;
        }
        s2.push(c);
    }
    if !s2.is_empty() || q_seen {
        v.push(s2.clone())
    }
    if v.len() < n {
        return str_error(format!("expecting {} elements in {}", n, s));
    }
    Ok(v)
}

/// types of Kicad files that can be found
#[derive(Debug)]
pub enum KicadFile {
    /// unknown file, probably no kicad file
    Unknown(PathBuf),
    /// a Kicad module, also know as a footprint
    Module(footprint::Module),
    /// a Kicad schematic file
    Schematic(schematic::Schematic),
    /// a Kicad layout file
    Layout(layout::Layout),
    /// a Kicad symbol library file
    SymbolLib(symbol_lib::SymbolLib),
    /// a Kicad project file
    Project(project::Project),
    /// a Kicad fp-lib-table file
    FpLibTable(fp_lib_table::FpLibTable),
}

/// types of Kicad files that we expect to read
#[derive(PartialEq)]
pub enum Expected {
    /// a Kicad module, also know as a footprint
    Module,
    /// a Kicad schematic file
    Schematic,
    /// a Kicad layout file
    Layout,
    /// a Kicad symbol library file
    SymbolLib,
    /// a Kicad project file
    Project,
    /// an fp-lib-table file
    FpLibTable,
    /// any Kicad file
    Any,
}

impl fmt::Display for KicadFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
        match *self {
            KicadFile::Unknown(ref x) => write!(f, "unknown: {}", x.to_str().unwrap()),
            KicadFile::Module(_) => write!(f, "module"),
            KicadFile::Schematic(_) => write!(f, "schematic"),
            KicadFile::Layout(_) => write!(f, "layout"),
            KicadFile::SymbolLib(_) => write!(f, "symbollib"),
            KicadFile::Project(_) => write!(f, "project"),
            KicadFile::FpLibTable(_) => write!(f, "fp-lib-table"),
        }
    }
}

/// try to read a file, trying to parse it as the different formats
/// and matching it against the Expected type
#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
pub fn read_kicad_file(name: &Path, expected: Expected) -> Result<KicadFile> {

    let data = read_file(name)?;
    match footprint::parse(&data) {
        Ok(module) => return Ok(KicadFile::Module(module)),
        Err(x) => if expected == Expected::Module {
            return Err(x);
        },
    }
    match schematic::parse(Some(PathBuf::from(name)), &data) {
        Ok(sch) => return Ok(KicadFile::Schematic(sch)),
        Err(x) => if expected == Expected::Schematic {
            return Err(x);
        },
    }
    match layout::parse(&data) {
        Ok(layout) => return Ok(KicadFile::Layout(layout)),
        Err(x) => if expected == Expected::Layout {
            return Err(x);
        },
    }
    match symbol_lib::parse_str(&data) {
        Ok(sl) => return Ok(KicadFile::SymbolLib(sl)),
        Err(x) => if expected == Expected::SymbolLib {
            return Err(x);
        },
    }
    match project::parse_str(&data) {
        Ok(p) => return Ok(KicadFile::Project(p)),
        Err(x) => if expected == Expected::Project {
            return Err(x);
        },
    }
    match fp_lib_table::parse(&data) {
        Ok(p) => return Ok(KicadFile::FpLibTable(p)),
        Err(x) => if expected == Expected::FpLibTable {
            return Err(x);
        },
    }
    Ok(KicadFile::Unknown(PathBuf::from(name)))
}

/// read a file, expecting it to be a Kicad module file
pub fn read_module(name: &Path) -> Result<footprint::Module> {
    match read_kicad_file(name, Expected::Module)? {
        KicadFile::Module(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name.display())),
    }
}

/// read a file, expecting it to be a Kicad schematic
pub fn read_schematic(name: &Path) -> Result<schematic::Schematic> {
    match read_kicad_file(name, Expected::Schematic)? {
        KicadFile::Schematic(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name.display())),
    }
}

/// read a file, expecting it to be a Kicad layout file
pub fn read_layout(name: &Path) -> Result<layout::Layout> {
    match read_kicad_file(name, Expected::Layout)? {
        KicadFile::Layout(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name.display())),
    }
}

/// write out a kicad Layout to a file
pub fn write_layout(layout: &layout::Layout, name: &Path) -> Result<()> {
    let s = layout::layout_to_string(layout, 0)?;
    write_file(name, &s)
}

pub fn write_module(module: &footprint::Module, name: &Path) -> Result<()> {
    let s = footprint::module_to_string(&module, 0)?;
    write_file(&name,&s)
}

/// read a file, expecting it to be a Kicad symbol library file
pub fn read_symbol_lib(name: &Path) -> Result<symbol_lib::SymbolLib> {
    match read_kicad_file(name, Expected::SymbolLib)? {
        KicadFile::SymbolLib(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name.display())),
    }
}

/// read a file, expecting it to be a Kicad project file
pub fn read_project(name: &Path) -> Result<project::Project> {
    match read_kicad_file(name, Expected::Project)? {
        KicadFile::Project(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name.display())),
    }
}

/// read a file, expecting it to be an fp-lib-table
pub fn read_fp_lib_table(name: &Path) -> Result<fp_lib_table::FpLibTable> {
    match read_kicad_file(name, Expected::FpLibTable)? {
        KicadFile::FpLibTable(mo) => Ok(mo),
        x => str_error(format!("unexpected {} in {}", x, name.display())),
    }
}

// put here so it is accessible to all subfiles privately
#[derive(Debug)]
enum Part {
    At(footprint::At),
    Layer(footprint::Layer),
    Hide,
    Effects(footprint::Effects),
    Layers(footprint::Layers),
    Width(f64),
    Angle(f64),
    Xy(footprint::Xy),
    Pts(footprint::Pts),
    Thickness(f64),
    Net(footprint::Net),
    Drill(footprint::Drill),
    SolderPasteMargin(f64),
    SolderMaskMargin(f64),
    Clearance(f64),
    ThermalGap(f64),
    ZoneConnect(i64),
    Italic,
}

// put here so it is accessible to all subfiles privately
// TODO: get rid of GrElement, using IterAtom allows dealing
// with the elements cleanly
enum GrElement {
    Start(footprint::Xy),
    End(footprint::Xy),
    Center(footprint::Xy),
    Angle(f64),
    Layer(footprint::Layer),
    Width(f64),
    Size(f64),
    Drill(f64),
    TStamp(String),
    At(footprint::At),
    Effects(footprint::Effects),
    Net(i64),
    Status(String),
    Layers(footprint::Layers),
}

fn wrap<X, Y, F, G>(s: &Sexp, make: F, wrapper: G) -> SResult<Y>
where
    F: Fn(&Sexp) -> SResult<X>,
    G: Fn(X) -> Y,
{
    Ok(wrapper(make(s)?))
}

#[derive(Debug)]
/// A bounding box
pub struct Bound {
    /// smaller x
    pub x1: f64,
    /// smaller y
    pub y1: f64,
    /// bigger x
    pub x2: f64,
    /// bigger y
    pub y2: f64,
    /// item is bounded
    pub is_bounded: bool,
}

impl Default for Bound {
    fn default() -> Bound {
        Bound {
            x1: 0.0,
            y1: 0.0,
            x2: 0.0,
            y2: 0.0,
            is_bounded: false,
        }
    }
}

impl Bound {
    /// create a new bound
    pub fn new(x1: f64, y1: f64, x2: f64, y2: f64) -> Bound {
        Bound {
            x1: x1,
            y1: y1,
            x2: x2,
            y2: y2,
            is_bounded: true,
        }
    }
    /// create a new bound
    pub fn new_from_i64(x1: i64, y1: i64, x2: i64, y2: i64) -> Bound {
        Bound {
            x1: x1 as f64,
            y1: y1 as f64,
            x2: x2 as f64,
            y2: y2 as f64,
            is_bounded: true,
        }
    }

    /// update the bound with another one
    pub fn update(&mut self, other: &Bound) {
        if other.is_bounded {
            if !self.is_bounded {
                self.is_bounded = true;
                self.x1 = other.x1;
                self.y1 = other.y1;
                self.x2 = other.x2;
                self.y2 = other.y2;
            } else {
                self.x1 = self.x1.min(other.x1);
                self.y1 = self.y1.min(other.y1);
                self.x2 = self.x2.max(other.x2);
                self.y2 = self.y2.max(other.y2);
            }
        }
    }

    /// call this when you constructed a default bound and potentionally had zero updates
    pub fn swap_if_needed(&mut self) {
        if self.x1 > self.x2 {
            std::mem::swap(&mut self.x1, &mut self.x2);
        }
        if self.y1 > self.y2 {
            std::mem::swap(&mut self.y1, &mut self.y2);
        }
    }
}

/// calculate the bounding box of a layout item
pub trait BoundingBox {
    /// calculate the bounding box of a layout item
    fn bounding_box(&self) -> Bound;
}

/// item location can be adjusted
pub trait Adjust {
    /// adjust the location of the item
    fn adjust(&mut self, x: f64, y: f64);
}

/// ordering used for ordering by component reference
/// to e.g. avoid U1 U101 U2 and get U1 U2 U101
pub fn reference_ord(r: &str) -> (char, i64) {
    let c = r.chars().nth(0).unwrap();
    let mut s = String::new();
    for c in r.chars() {
        if c >= '0' && c <= '9' {
            s.push(c)
        }
        // if the &str contains a list of references,
        // only take 1st element
        if c == ',' {
            break;
        }
    }
    let num = match s.parse::<i64>() {
        Ok(n) => n,
        Err(_) => 0,
    };
    (c, num)
}

/// Kicad error handling code and types
pub mod error;
/// Kicad footprint format handling
pub mod footprint;
/// Kicad schematic format handling
pub mod schematic;
/// Kicad layout format handling
pub mod layout;
/// Kicad symbol library format handling
pub mod symbol_lib;
/// Kicad project format handling
pub mod project;
/// Kicad fp-lib-table format handling
pub mod fp_lib_table;
/// checking and fixing related to the Kicad Library Convention
pub mod checkfix;

mod util;
mod formatter;
<|endoftext|>


<commit_before>use crate::base128;
use crate::parser::{ParseError, ParseErrorKind, ParseResult};
use alloc::vec::Vec;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub(crate) enum TagClass {
    Universal = 0b00,
    Application = 0b01,
    ContextSpecific = 0b10,
    Private = 0b11,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Tag {
    value: u32,
    constructed: bool,
    class: TagClass,
}

pub(crate) const CONSTRUCTED: u32 = 0x20;

impl Tag {
    /// Parses a `Tag` from bytes and returns either the `Tag and the
    /// remaining bytes from the input or an error.
    pub fn from_bytes(mut data: &[u8]) -> ParseResult<(Tag, &[u8])> {
        let tag = match data.first() {
            Some(&b) => b as u32,
            None => return Err(ParseError::new(ParseErrorKind::ShortData)),
        };
        data = &data[1..];
        let mut value = tag & 0x1f;
        let constructed = tag & CONSTRUCTED == CONSTRUCTED;
        let class = match tag >> 6 {
            0b00 => TagClass::Universal,
            0b01 => TagClass::Application,
            0b10 => TagClass::ContextSpecific,
            0b11 => TagClass::Private,
            _ => unreachable!(),
        };

        // Long form tag
        if value == 0x1f {
            let result = base128::read_base128_int(data)
                .map_err(|_| ParseError::new(ParseErrorKind::InvalidTag))?;
            // Rust 1.47 doesn't support writing `(value, data) = ...;`
            value = result.0;
            data = result.1;
            // Tags must be encoded in minimal form.
            if value < 0x1f {
                return Err(ParseError::new(ParseErrorKind::InvalidTag));
            }
        }

        Ok((
            Tag {
                value,
                constructed,
                class,
            },
            data,
        ))
    }

    pub(crate) const fn new(tag: u32, class: TagClass, constructed: bool) -> Tag {
        Tag {
            value: tag,
            constructed,
            class,
        }
    }

    /// This is `pub` for use in tests but is not considered part of the
    /// supported API.
    #[doc(hidden)]
    pub const fn primitive(tag: u32) -> Tag {
        Tag::new(tag, TagClass::Universal, false)
    }

    pub(crate) const fn constructed(tag: u32) -> Tag {
        Tag::new(tag, TagClass::Universal, true)
    }

    /// Returns the tag's representation (including tag class and constructed
    /// bits) as a `u8` if the `value` component fits in a short form
    /// (value < 31) or `None` if this is a long-form tag.
    pub fn as_u8(&self) -> Option<u8> {
        if self.value >= 0x1f {
            return None;
        }
        Some(
            ((self.class as u8) << 6)
                | if self.constructed {
                    CONSTRUCTED as u8
                } else {
                    0
                }
                | (self.value as u8),
        )
    }

    pub(crate) fn write_bytes(&self, dest: &mut Vec<u8>) {
        let mut b = ((self.class as u8) << 6)
            | if self.constructed {
                CONSTRUCTED as u8
            } else {
                0
            };
        if self.value >= 0x1f {
            b |= 0x1f;
            dest.push(b);
            let len = base128::base128_length(self.value);
            let orig_len = dest.len();
            dest.resize(dest.len() + len, 0);
            base128::write_base128_int(&mut dest[orig_len..], self.value);
        } else {
            b |= self.value as u8;
            dest.push(b);
        }
    }

    pub(crate) const fn is_constructed(&self) -> bool {
        self.constructed
    }
}

#[cfg(test)]
mod tests {
    use super::{Tag, TagClass};

    #[test]
    fn test_as_u8() {
        for (t, expected) in &[
            (Tag::new(5, TagClass::Application, true), Some(0x65)),
            (Tag::new(0x1f, TagClass::Universal, false), None),
        ] {
            assert_eq!(&t.as_u8(), expected);
        }
    }
}
<commit_msg>fixed a typo in a doc comment (#273)<commit_after>use crate::base128;
use crate::parser::{ParseError, ParseErrorKind, ParseResult};
use alloc::vec::Vec;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub(crate) enum TagClass {
    Universal = 0b00,
    Application = 0b01,
    ContextSpecific = 0b10,
    Private = 0b11,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Tag {
    value: u32,
    constructed: bool,
    class: TagClass,
}

pub(crate) const CONSTRUCTED: u32 = 0x20;

impl Tag {
    /// Parses a `Tag` from bytes and returns either the `Tag` and the
    /// remaining bytes from the input or an error.
    pub fn from_bytes(mut data: &[u8]) -> ParseResult<(Tag, &[u8])> {
        let tag = match data.first() {
            Some(&b) => b as u32,
            None => return Err(ParseError::new(ParseErrorKind::ShortData)),
        };
        data = &data[1..];
        let mut value = tag & 0x1f;
        let constructed = tag & CONSTRUCTED == CONSTRUCTED;
        let class = match tag >> 6 {
            0b00 => TagClass::Universal,
            0b01 => TagClass::Application,
            0b10 => TagClass::ContextSpecific,
            0b11 => TagClass::Private,
            _ => unreachable!(),
        };

        // Long form tag
        if value == 0x1f {
            let result = base128::read_base128_int(data)
                .map_err(|_| ParseError::new(ParseErrorKind::InvalidTag))?;
            // Rust 1.47 doesn't support writing `(value, data) = ...;`
            value = result.0;
            data = result.1;
            // Tags must be encoded in minimal form.
            if value < 0x1f {
                return Err(ParseError::new(ParseErrorKind::InvalidTag));
            }
        }

        Ok((
            Tag {
                value,
                constructed,
                class,
            },
            data,
        ))
    }

    pub(crate) const fn new(tag: u32, class: TagClass, constructed: bool) -> Tag {
        Tag {
            value: tag,
            constructed,
            class,
        }
    }

    /// This is `pub` for use in tests but is not considered part of the
    /// supported API.
    #[doc(hidden)]
    pub const fn primitive(tag: u32) -> Tag {
        Tag::new(tag, TagClass::Universal, false)
    }

    pub(crate) const fn constructed(tag: u32) -> Tag {
        Tag::new(tag, TagClass::Universal, true)
    }

    /// Returns the tag's representation (including tag class and constructed
    /// bits) as a `u8` if the `value` component fits in a short form
    /// (value < 31) or `None` if this is a long-form tag.
    pub fn as_u8(&self) -> Option<u8> {
        if self.value >= 0x1f {
            return None;
        }
        Some(
            ((self.class as u8) << 6)
                | if self.constructed {
                    CONSTRUCTED as u8
                } else {
                    0
                }
                | (self.value as u8),
        )
    }

    pub(crate) fn write_bytes(&self, dest: &mut Vec<u8>) {
        let mut b = ((self.class as u8) << 6)
            | if self.constructed {
                CONSTRUCTED as u8
            } else {
                0
            };
        if self.value >= 0x1f {
            b |= 0x1f;
            dest.push(b);
            let len = base128::base128_length(self.value);
            let orig_len = dest.len();
            dest.resize(dest.len() + len, 0);
            base128::write_base128_int(&mut dest[orig_len..], self.value);
        } else {
            b |= self.value as u8;
            dest.push(b);
        }
    }

    pub(crate) const fn is_constructed(&self) -> bool {
        self.constructed
    }
}

#[cfg(test)]
mod tests {
    use super::{Tag, TagClass};

    #[test]
    fn test_as_u8() {
        for (t, expected) in &[
            (Tag::new(5, TagClass::Application, true), Some(0x65)),
            (Tag::new(0x1f, TagClass::Universal, false), None),
        ] {
            assert_eq!(&t.as_u8(), expected);
        }
    }
}
<|endoftext|>


<commit_before>#![feature(asm)]
#![feature(no_std)]
#![feature(const_fn)]
#![feature(core_str_ext)]
#![no_std]

mod intrinsics;
mod hypercall;

pub mod defs;

pub mod memory;
pub mod event;
pub mod sched;

pub mod console;

pub mod arch;

extern "C" {
    // This symbol must be present in code using libxen
    pub static shared_info: self::defs::SharedInfo;
}
<commit_msg>libxen: shared_info is now mutable<commit_after>#![feature(asm)]
#![feature(no_std)]
#![feature(const_fn)]
#![feature(core_str_ext)]
#![no_std]

mod intrinsics;
mod hypercall;

pub mod defs;

pub mod memory;
pub mod event;
pub mod sched;

pub mod console;

pub mod arch;

extern "C" {
    // This symbol must be present in code using libxen
    pub static mut shared_info: self::defs::SharedInfo;
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate glob;
#[macro_use] extern crate log;
extern crate semver;
extern crate toml;
#[macro_use] extern crate version;

extern crate libimagrt;
extern crate libimagstore;
extern crate libimagutil;

use std::process::exit;

use libimagrt::runtime::Runtime;
use libimagstore::store::FileLockEntry;
use libimagutil::trace::trace_error;

mod ui;

use ui::build_ui;

fn main() {
    let name = "imag-todo";
    let version = &version!()[..];
    let about = "Interface with taskwarrior";
    let ui = build_ui(Runtime::get_default_cli_builder(name, version, about));
    let rt = {
        let rt = Runtime::new(ui);
        if rt.is_ok() {
            rt.unwrap()
        } else {
            println!("Could not set up Runtime");
            println!("{:?}", rt.unwrap_err());
            exit(1);
        }
    };

    let scmd = rt.cli().subcommand_name();
    match scmd {
        Some("tw-hook") => {
            let subcmd = rt.cli().subcommand_matches("tw-hook").unwrap();
            if subcmd.is_present("add") {
                println!("To be implemented");
                //
                // TODO @Kevin: import function aus task_hookrs benutzen, um
                //              stdin auszulesen, und dann auf dem
                //              task_hookrs::task::Task den Trait für die
                //              Umwandlung aufrufen.
                //
            }
            else if subcmd.is_present("delete") {
                println!("To be implemented");
                //
                // Functionality to delete Entry in the store
                //
            }
            else {
                // Should not be possible, as one argument is required via
                // ArgGroup
                panic!("Reached unreachable Code");
            }
        },
        Some("exec") => {
        },
        _ => println!("Nothing implemented yet"),
    }
}
<commit_msg>cmd query<commit_after>extern crate clap;
extern crate glob;
#[macro_use] extern crate log;
extern crate semver;
extern crate toml;
#[macro_use] extern crate version;

extern crate libimagrt;
extern crate libimagstore;
extern crate libimagutil;

use std::process::exit;

use libimagrt::runtime::Runtime;
use libimagstore::store::FileLockEntry;
use libimagutil::trace::trace_error;

mod ui;

use ui::build_ui;

fn main() {
    let name = "imag-todo";
    let version = &version!()[..];
    let about = "Interface with taskwarrior";
    let ui = build_ui(Runtime::get_default_cli_builder(name, version, about));
    let rt = {
        let rt = Runtime::new(ui);
        if rt.is_ok() {
            rt.unwrap()
        } else {
            println!("Could not set up Runtime");
            println!("{:?}", rt.unwrap_err());
            exit(1);
        }
    };

    let scmd = rt.cli().subcommand_name();
    match scmd {
        Some("tw-hook") => {
            let subcmd = rt.cli().subcommand_matches("tw-hook").unwrap();
            if subcmd.is_present("add") {
                println!("To be implemented");
                //
                // TODO @Kevin: import function aus task_hookrs benutzen, um
                //              stdin auszulesen, und dann auf dem
                //              task_hookrs::task::Task den Trait für die
                //              Umwandlung aufrufen.
                //
            }
            else if subcmd.is_present("delete") {
                println!("To be implemented");
                //
                // Functionality to delete Entry in the store
                //
            }
            else {
                // Should not be possible, as one argument is required via
                // ArgGroup
                panic!("Reached unreachable Code");
            }
        },
        Some("exec") => {
            let subcmd = rt.cli().subcommand_matches("exec").unwrap();
            let itr = subcmd.values_of_os("add").unwrap();
            if subcmd.is_present("command") {
                let string = subcmd.value_of("command").unwrap();
                println!("{:?}", string);
                else {
                    panic!("Reached unreachable Code");
                }
            },
                _ => println!("Nothing implemented yet"),
        }
    }
}

<|endoftext|>