<commit_before>#![feature(proc_macro)]

extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

#[macro_use]
extern crate quote;

pub mod schema;

use std::borrow::Cow;
use std::error::Error;

use serde_json::Value;

use schema::{Schema, simpleTypes};

use quote::{Tokens, ToTokens};

struct Ident<S>(S);

impl<S: AsRef<str>> ToTokens for Ident<S> {
    fn to_tokens(&self, tokens: &mut Tokens) {
        tokens.append(self.0.as_ref())
    }
}

const ONE_OR_MANY: &'static str = r#"
use std::ops::{Deref, DerefMut};

#[derive(Clone, PartialEq, Debug)]
pub enum OneOrMany<T> {
    One(Box<T>),
    Many(Vec<T>),
}

impl<T> Deref for OneOrMany<T> {
    type Target = [T];
    fn deref(&self) -> &[T] {
        match *self {
            OneOrMany::One(ref v) => unsafe { ::std::slice::from_raw_parts(&**v, 1) },
            OneOrMany::Many(ref v) => v,
        }
    }
}

impl<T> DerefMut for OneOrMany<T> {
    fn deref_mut(&mut self) -> &mut [T] {
        match *self {
            OneOrMany::One(ref mut v) => unsafe { ::std::slice::from_raw_parts_mut(&mut **v, 1) },
            OneOrMany::Many(ref mut v) => v,
        }
    }
}

impl<T> Default for OneOrMany<T> {
    fn default() -> OneOrMany<T> {
        OneOrMany::Many(Vec::new())
    }
}

impl<T> serde::Deserialize for OneOrMany<T>
    where T: serde::Deserialize
{
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
        where D: serde::Deserializer
    {
        T::deserialize(deserializer)
            .map(|one| OneOrMany::One(Box::new(one)))
            .or_else(|_| Vec::<T>::deserialize(deserializer).map(OneOrMany::Many))
    }
}

impl<T> serde::Serialize for OneOrMany<T>
    where T: serde::Serialize
{
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: serde::Serializer
    {
        match *self {
            OneOrMany::One(ref one) => one.serialize(serializer),
            OneOrMany::Many(ref many) => many.serialize(serializer),
        }
    }
}
"#;

fn rename_keyword(prefix: &str, s: &str) -> Option<Tokens> {
    if ["type", "struct", "enum"].iter().any(|&keyword| keyword == s) {
        let n = Ident(format!("{}_", s));
        let prefix = Ident(prefix);
        Some(quote!{
            #[serde(rename = #s)]
            #prefix #n
        })
    } else {
        None
    }
}

fn field(s: &str) -> Tokens {
    if let Some(t) = rename_keyword("pub", s) {
        t
    } else {
        let mut snake = String::new();
        let mut chars = s.chars();
        let mut prev_was_upper = false;
        while let Some(c) = chars.next() {
            if c.is_uppercase() {
                if !prev_was_upper {
                    snake.push('_');
                }
                snake.extend(c.to_lowercase());
                prev_was_upper = true;
            } else {
                snake.push(c);
                prev_was_upper = false;
            }
        }
        if snake != s || snake.contains(|c: char| c == '$' || c == '#') {
            let field = if snake == "$ref" {
                Ident("ref_".into())
            } else {
                Ident(snake.replace('$', "").replace('#', ""))
            };

            quote!{
                #[serde(rename = #s)]
                pub #field
            }
        } else {
            let field = Ident(s);
            quote!( pub #field )
        }
    }
}

fn merge(result: &mut Schema, r: &Schema) {
    use std::collections::hash_map::Entry;

    for (k, v) in &r.properties {
        match result.properties.entry(k.clone()) {
            Entry::Vacant(entry) => {
                entry.insert(v.clone());
            }
            Entry::Occupied(mut entry) => merge(entry.get_mut(), v),
        }
    }
}

struct FieldExpander<'a, 'r: 'a> {
    default: bool,
    expander: &'a mut Expander<'r>,
}

impl<'a, 'r> FieldExpander<'a, 'r> {
    fn expand_fields(&mut self, type_name: &str, schema: &Schema) -> Vec<Tokens> {
        let schema = self.expander.schema(schema);
        schema.properties
            .iter()
            .map(|(field_name, value)| {
                let key = field(field_name);
                let required =
                    schema.required.iter().flat_map(|a| a.iter()).any(|req| req == field_name);
                let field_type = self.expander.expand_type(type_name, required, value);
                if !field_type.typ.starts_with("Option<") {
                    self.default = false;
                }
                let typ = Ident(field_type.typ);
                if field_type.default {
                    quote!( #[serde(default)] #key : #typ )
                } else {
                    quote!( #key : #typ )
                }
            })
            .collect()
    }
}

struct Expander<'r> {
    root_name: Option<&'r str>,
    root: &'r Schema,
    needs_one_or_many: bool,
}

struct FieldType {
    typ: String,
    default: bool,
}

impl<S> From<S> for FieldType
    where S: Into<String>
{
    fn from(s: S) -> FieldType {
        FieldType {
            typ: s.into(),
            default: false,
        }
    }
}

impl<'r> Expander<'r> {
    fn new(root_name: Option<&'r str>, root: &'r Schema) -> Expander<'r> {
        Expander {
            root_name: root_name,
            root: root,
            needs_one_or_many: false,
        }
    }

    fn type_ref(&self, s: &str) -> String {
        if s == "#" {
            self.root_name.expect("Root name").into()
        } else {
            s.split('/').last().expect("Component").into()
        }
    }

    fn schema(&self, schema: &'r Schema) -> Cow<'r, Schema> {
        let result = match schema.all_of.as_ref().and_then(|array| array.first()) {
            Some(result) => {
                schema.all_of
                    .iter()
                    .skip(1)
                    .fold(Cow::Borrowed(result), |mut result, def| {
                        merge(result.to_mut(), &self.schema(&def[0]));
                        result
                    })
            }
            None => Cow::Borrowed(schema),
        };
        if let Some(ref ref_) = result.ref_ {
            return Cow::Borrowed(self.schema_ref(ref_));
        }
        result
    }

    fn schema_ref(&self, s: &str) -> &'r Schema {
        s.split('/').fold(self.root, |schema, comp| {
            if comp == "#" {
                self.root
            } else if comp == "definitions" {
                schema
            } else {
                schema.definitions
                    .get(comp)
                    .unwrap_or_else(|| panic!("Expected definition: `{}` {}", s, comp))
            }
        })
    }

    fn expand_type(&mut self, type_name: &str, required: bool, typ: &Schema) -> FieldType {
        let mut result = self.expand_type_(typ);
        if type_name == result.typ {
            result.typ = format!("Box<{}>", result.typ)
        }
        if !required && !result.default {
            result.typ = format!("Option<{}>", result.typ)
        }
        result
    }

    fn expand_type_(&mut self, typ: &Schema) -> FieldType {
        if let Some(ref ref_) = typ.ref_ {
            self.type_ref(ref_).into()
        } else if typ.any_of.as_ref().map_or(false, |a| a.len() == 2) {
            let any_of = typ.any_of.as_ref().unwrap();
            let simple = self.schema(&any_of[0]);
            let array = self.schema(&any_of[1]);
            if let simpleTypes::array = array.type_[0] {
                if simple == self.schema(&array.items[0]) {
                    self.needs_one_or_many = true;
                    return FieldType {
                        typ: format!("OneOrMany<{}>", self.expand_type_(&any_of[0]).typ),
                        default: true,
                    };
                }
            }
            return "serde_json::Value".into();
        } else if typ.type_.len() == 1 {
            match typ.type_[0] {
                simpleTypes::string => {
                    if !typ.enum_.as_ref().map_or(false, |e| e.is_empty()) {
                        "serde_json::Value".into()
                    } else {
                        "String".into()
                    }
                }
                simpleTypes::integer => "i64".into(),
                simpleTypes::boolean => "bool".into(),
                simpleTypes::number => "f64".into(),
                simpleTypes::object if typ.additional_properties.is_some() => {
                    let prop = serde_json::from_value(typ.additional_properties.clone().unwrap())
                        .unwrap();
                    let result =
                        format!("::std::collections::HashMap<String, {}>", self.expand_type_(&prop).typ);
                    FieldType {
                        typ: result,
                        default: typ.default == Some(Value::Object(Default::default())),
                    }
                }
                simpleTypes::array => {
                    let item_type = typ.items.get(0).map_or("serde_json::Value".into(),
                                                            |item| self.expand_type_(item).typ);
                    format!("Vec<{}>", item_type).into()
                }
                _ => "serde_json::Value".into(),
            }
        } else {
            "serde_json::Value".into()
        }
    }

    pub fn expand_definitions(&mut self, schema: &Schema) -> Vec<Tokens> {
        let mut types = Vec::new();
        for (name, def) in &schema.definitions {
            types.push(self.expand_schema(name, def));
        }
        types
    }

    pub fn expand_schema(&mut self, name: &str, schema: &Schema) -> Tokens {
        let (fields, default) = {
            let mut field_expander = FieldExpander {
                default: true,
                expander: self,
            };
            let fields = field_expander.expand_fields(name, schema);
            (fields, field_expander.default)
        };

        let name = Ident(name);
        if !fields.is_empty() {
            if default {
                quote! {
                    #[derive(Clone, PartialEq, Debug, Default, Deserialize, Serialize)]
                    pub struct #name {
                        #(#fields),*
                    }
                }
            } else {
                quote! {
                    #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
                    pub struct #name {
                        #(#fields),*
                    }
                }
            }
        } else if schema.enum_.as_ref().map_or(false, |e| !e.is_empty()) {
            let variants = schema.enum_.as_ref().map_or(&[][..], |v| v).iter().map(|v| {
                match *v {
                    Value::String(ref v) => {
                        rename_keyword("", v).unwrap_or_else(|| {
                            let v = Ident(v);
                            quote!(#v)
                        })
                    }
                    _ => panic!("Expected string"),
                }
            });
            quote! {
                #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
                pub enum #name {
                    #(#variants),*
                }
            }
        } else {
            let typ = Ident(self.expand_type("", true, schema).typ);
            quote! {
                pub type #name = #typ;
            }
        }
    }

    pub fn expand(&mut self, schema: &Schema) -> Tokens {
        let mut types = self.expand_definitions(schema);
        if let Some(name) = self.root_name {
            types.push(self.expand_schema(name, schema));
        }

        let one_or_many = Ident(if self.needs_one_or_many {
            ONE_OR_MANY
        } else {
            ""
        });

        quote! {
            #one_or_many

            #( #types )*
        }
    }
}

pub fn generate(root_name: Option<&str>, s: &str) -> Result<String, Box<Error>> {
    use std::process::{Command, Stdio};
    use std::io::Write;

    let schema = serde_json::from_str(s).unwrap();
    let mut expander = Expander::new(root_name, &schema);
    let output = expander.expand(&schema).to_string();
    let mut child =
        try!(Command::new("rustfmt").stdin(Stdio::piped()).stdout(Stdio::piped()).spawn());
    try!(child.stdin.as_mut().expect("stdin").write_all(output.as_bytes()));
    let output = try!(child.wait_with_output());
    assert!(output.status.success());
    Ok(try!(String::from_utf8(output.stdout)))
}

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

    use std::fs::File;
    use std::io::Write;
    use std::path::PathBuf;
    use std::process::{Command, Stdio};

    #[test]
    fn generate_schema() {
        let s = include_str!("schema.json");

        let s = generate(Some("Schema"), s).unwrap().to_string();

        verify_compile("schema", &s);

        assert!(s.contains("pub struct Schema"), "{}", s);
        assert!(s.contains("pub type positiveInteger = i64"));
        assert!(s.contains("pub type_: OneOrMany<simpleTypes>"));

        let result = Command::new("rustc")
            .args(&["-L",
                    "target/debug/deps/",
                    "-o",
                    "target/debug/schema-test",
                    "tests/support/schema-test.rs"])
            .status()
            .unwrap();

        assert!(result.success());
        let result = Command::new("./target/debug/schema-test")
            .status()
            .unwrap();

        assert!(result.success());
    }

    fn verify_compile(name: &str, s: &str) {

        let mut filename = PathBuf::from("target/debug");
        filename.push(&format!("{}.rs", name));
        {
            let mut file = File::create(&filename).unwrap();
            let header = r#"
            #![feature(proc_macro)]

            extern crate serde;
            #[macro_use]
            extern crate serde_derive;
            extern crate serde_json;
            "#;
            file.write_all(header.as_bytes()).unwrap();
            file.write_all(s.as_bytes()).unwrap();
        }
        println!("{}", filename.display());
        let child = Command::new("rustc")
            .args(&["-L",
                    "target/debug/deps/",
                    "--crate-type=rlib",
                    "-o",
                    &format!("target/debug/deps/lib{}.rlib", name),
                    filename.to_str().unwrap()])
            .stderr(Stdio::piped())
            .spawn()
            .unwrap();

        let output = child.wait_with_output().unwrap();
        let error = String::from_utf8(output.stderr).unwrap();
        assert!(output.status.success(), "{}", error);
    }

    #[test]
    fn builds_with_rustc() {
        let s = include_str!("../tests/debugserver-schema.json");

        let s = generate(None, s).unwrap().to_string();

        verify_compile("debug-server", &s)
    }
}
<commit_msg>fix: Accidental ! operators<commit_after>#![feature(proc_macro)]

extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

#[macro_use]
extern crate quote;

pub mod schema;

use std::borrow::Cow;
use std::error::Error;

use serde_json::Value;

use schema::{Schema, simpleTypes};

use quote::{Tokens, ToTokens};

struct Ident<S>(S);

impl<S: AsRef<str>> ToTokens for Ident<S> {
    fn to_tokens(&self, tokens: &mut Tokens) {
        tokens.append(self.0.as_ref())
    }
}

const ONE_OR_MANY: &'static str = r#"
use std::ops::{Deref, DerefMut};

#[derive(Clone, PartialEq, Debug)]
pub enum OneOrMany<T> {
    One(Box<T>),
    Many(Vec<T>),
}

impl<T> Deref for OneOrMany<T> {
    type Target = [T];
    fn deref(&self) -> &[T] {
        match *self {
            OneOrMany::One(ref v) => unsafe { ::std::slice::from_raw_parts(&**v, 1) },
            OneOrMany::Many(ref v) => v,
        }
    }
}

impl<T> DerefMut for OneOrMany<T> {
    fn deref_mut(&mut self) -> &mut [T] {
        match *self {
            OneOrMany::One(ref mut v) => unsafe { ::std::slice::from_raw_parts_mut(&mut **v, 1) },
            OneOrMany::Many(ref mut v) => v,
        }
    }
}

impl<T> Default for OneOrMany<T> {
    fn default() -> OneOrMany<T> {
        OneOrMany::Many(Vec::new())
    }
}

impl<T> serde::Deserialize for OneOrMany<T>
    where T: serde::Deserialize
{
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
        where D: serde::Deserializer
    {
        T::deserialize(deserializer)
            .map(|one| OneOrMany::One(Box::new(one)))
            .or_else(|_| Vec::<T>::deserialize(deserializer).map(OneOrMany::Many))
    }
}

impl<T> serde::Serialize for OneOrMany<T>
    where T: serde::Serialize
{
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: serde::Serializer
    {
        match *self {
            OneOrMany::One(ref one) => one.serialize(serializer),
            OneOrMany::Many(ref many) => many.serialize(serializer),
        }
    }
}
"#;

fn rename_keyword(prefix: &str, s: &str) -> Option<Tokens> {
    if ["type", "struct", "enum"].iter().any(|&keyword| keyword == s) {
        let n = Ident(format!("{}_", s));
        let prefix = Ident(prefix);
        Some(quote!{
            #[serde(rename = #s)]
            #prefix #n
        })
    } else {
        None
    }
}

fn field(s: &str) -> Tokens {
    if let Some(t) = rename_keyword("pub", s) {
        t
    } else {
        let mut snake = String::new();
        let mut chars = s.chars();
        let mut prev_was_upper = false;
        while let Some(c) = chars.next() {
            if c.is_uppercase() {
                if !prev_was_upper {
                    snake.push('_');
                }
                snake.extend(c.to_lowercase());
                prev_was_upper = true;
            } else {
                snake.push(c);
                prev_was_upper = false;
            }
        }
        if snake != s || snake.contains(|c: char| c == '$' || c == '#') {
            let field = if snake == "$ref" {
                Ident("ref_".into())
            } else {
                Ident(snake.replace('$', "").replace('#', ""))
            };

            quote!{
                #[serde(rename = #s)]
                pub #field
            }
        } else {
            let field = Ident(s);
            quote!( pub #field )
        }
    }
}

fn merge(result: &mut Schema, r: &Schema) {
    use std::collections::hash_map::Entry;

    for (k, v) in &r.properties {
        match result.properties.entry(k.clone()) {
            Entry::Vacant(entry) => {
                entry.insert(v.clone());
            }
            Entry::Occupied(mut entry) => merge(entry.get_mut(), v),
        }
    }
}

struct FieldExpander<'a, 'r: 'a> {
    default: bool,
    expander: &'a mut Expander<'r>,
}

impl<'a, 'r> FieldExpander<'a, 'r> {
    fn expand_fields(&mut self, type_name: &str, schema: &Schema) -> Vec<Tokens> {
        let schema = self.expander.schema(schema);
        schema.properties
            .iter()
            .map(|(field_name, value)| {
                let key = field(field_name);
                let required =
                    schema.required.iter().flat_map(|a| a.iter()).any(|req| req == field_name);
                let field_type = self.expander.expand_type(type_name, required, value);
                if !field_type.typ.starts_with("Option<") {
                    self.default = false;
                }
                let typ = Ident(field_type.typ);
                if field_type.default {
                    quote!( #[serde(default)] #key : #typ )
                } else {
                    quote!( #key : #typ )
                }
            })
            .collect()
    }
}

struct Expander<'r> {
    root_name: Option<&'r str>,
    root: &'r Schema,
    needs_one_or_many: bool,
}

struct FieldType {
    typ: String,
    default: bool,
}

impl<S> From<S> for FieldType
    where S: Into<String>
{
    fn from(s: S) -> FieldType {
        FieldType {
            typ: s.into(),
            default: false,
        }
    }
}

impl<'r> Expander<'r> {
    fn new(root_name: Option<&'r str>, root: &'r Schema) -> Expander<'r> {
        Expander {
            root_name: root_name,
            root: root,
            needs_one_or_many: false,
        }
    }

    fn type_ref(&self, s: &str) -> String {
        if s == "#" {
            self.root_name.expect("Root name").into()
        } else {
            s.split('/').last().expect("Component").into()
        }
    }

    fn schema(&self, schema: &'r Schema) -> Cow<'r, Schema> {
        let result = match schema.all_of.as_ref().and_then(|array| array.first()) {
            Some(result) => {
                schema.all_of
                    .iter()
                    .skip(1)
                    .fold(Cow::Borrowed(result), |mut result, def| {
                        merge(result.to_mut(), &self.schema(&def[0]));
                        result
                    })
            }
            None => Cow::Borrowed(schema),
        };
        if let Some(ref ref_) = result.ref_ {
            return Cow::Borrowed(self.schema_ref(ref_));
        }
        result
    }

    fn schema_ref(&self, s: &str) -> &'r Schema {
        s.split('/').fold(self.root, |schema, comp| {
            if comp == "#" {
                self.root
            } else if comp == "definitions" {
                schema
            } else {
                schema.definitions
                    .get(comp)
                    .unwrap_or_else(|| panic!("Expected definition: `{}` {}", s, comp))
            }
        })
    }

    fn expand_type(&mut self, type_name: &str, required: bool, typ: &Schema) -> FieldType {
        let mut result = self.expand_type_(typ);
        if type_name == result.typ {
            result.typ = format!("Box<{}>", result.typ)
        }
        if !required && !result.default {
            result.typ = format!("Option<{}>", result.typ)
        }
        result
    }

    fn expand_type_(&mut self, typ: &Schema) -> FieldType {
        if let Some(ref ref_) = typ.ref_ {
            self.type_ref(ref_).into()
        } else if typ.any_of.as_ref().map_or(false, |a| a.len() == 2) {
            let any_of = typ.any_of.as_ref().unwrap();
            let simple = self.schema(&any_of[0]);
            let array = self.schema(&any_of[1]);
            if let simpleTypes::array = array.type_[0] {
                if simple == self.schema(&array.items[0]) {
                    self.needs_one_or_many = true;
                    return FieldType {
                        typ: format!("OneOrMany<{}>", self.expand_type_(&any_of[0]).typ),
                        default: true,
                    };
                }
            }
            return "serde_json::Value".into();
        } else if typ.type_.len() == 1 {
            match typ.type_[0] {
                simpleTypes::string => {
                    if typ.enum_.as_ref().map_or(false, |e| e.is_empty()) {
                        "serde_json::Value".into()
                    } else {
                        "String".into()
                    }
                }
                simpleTypes::integer => "i64".into(),
                simpleTypes::boolean => "bool".into(),
                simpleTypes::number => "f64".into(),
                simpleTypes::object if typ.additional_properties.is_some() => {
                    let prop = serde_json::from_value(typ.additional_properties.clone().unwrap())
                        .unwrap();
                    let result =
                        format!("::std::collections::HashMap<String, {}>", self.expand_type_(&prop).typ);
                    FieldType {
                        typ: result,
                        default: typ.default == Some(Value::Object(Default::default())),
                    }
                }
                simpleTypes::array => {
                    let item_type = typ.items.get(0).map_or("serde_json::Value".into(),
                                                            |item| self.expand_type_(item).typ);
                    format!("Vec<{}>", item_type).into()
                }
                _ => "serde_json::Value".into(),
            }
        } else {
            "serde_json::Value".into()
        }
    }

    pub fn expand_definitions(&mut self, schema: &Schema) -> Vec<Tokens> {
        let mut types = Vec::new();
        for (name, def) in &schema.definitions {
            types.push(self.expand_schema(name, def));
        }
        types
    }

    pub fn expand_schema(&mut self, name: &str, schema: &Schema) -> Tokens {
        let (fields, default) = {
            let mut field_expander = FieldExpander {
                default: true,
                expander: self,
            };
            let fields = field_expander.expand_fields(name, schema);
            (fields, field_expander.default)
        };

        let name = Ident(name);
        if !fields.is_empty() {
            if default {
                quote! {
                    #[derive(Clone, PartialEq, Debug, Default, Deserialize, Serialize)]
                    pub struct #name {
                        #(#fields),*
                    }
                }
            } else {
                quote! {
                    #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
                    pub struct #name {
                        #(#fields),*
                    }
                }
            }
        } else if schema.enum_.as_ref().map_or(false, |e| !e.is_empty()) {
            let variants = schema.enum_.as_ref().map_or(&[][..], |v| v).iter().map(|v| {
                match *v {
                    Value::String(ref v) => {
                        rename_keyword("", v).unwrap_or_else(|| {
                            let v = Ident(v);
                            quote!(#v)
                        })
                    }
                    _ => panic!("Expected string"),
                }
            });
            quote! {
                #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
                pub enum #name {
                    #(#variants),*
                }
            }
        } else {
            let typ = Ident(self.expand_type("", true, schema).typ);
            quote! {
                pub type #name = #typ;
            }
        }
    }

    pub fn expand(&mut self, schema: &Schema) -> Tokens {
        let mut types = self.expand_definitions(schema);
        if let Some(name) = self.root_name {
            types.push(self.expand_schema(name, schema));
        }

        let one_or_many = Ident(if self.needs_one_or_many {
            ONE_OR_MANY
        } else {
            ""
        });

        quote! {
            #one_or_many

            #( #types )*
        }
    }
}

pub fn generate(root_name: Option<&str>, s: &str) -> Result<String, Box<Error>> {
    use std::process::{Command, Stdio};
    use std::io::Write;

    let schema = serde_json::from_str(s).unwrap();
    let mut expander = Expander::new(root_name, &schema);
    let output = expander.expand(&schema).to_string();
    let mut child =
        try!(Command::new("rustfmt").stdin(Stdio::piped()).stdout(Stdio::piped()).spawn());
    try!(child.stdin.as_mut().expect("stdin").write_all(output.as_bytes()));
    let output = try!(child.wait_with_output());
    assert!(output.status.success());
    Ok(try!(String::from_utf8(output.stdout)))
}

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

    use std::fs::File;
    use std::io::Write;
    use std::path::PathBuf;
    use std::process::{Command, Stdio};

    #[test]
    fn generate_schema() {
        let s = include_str!("schema.json");

        let s = generate(Some("Schema"), s).unwrap().to_string();

        verify_compile("schema", &s);

        assert!(s.contains("pub struct Schema"), "{}", s);
        assert!(s.contains("pub type positiveInteger = i64"));
        assert!(s.contains("pub type_: OneOrMany<simpleTypes>"));

        let result = Command::new("rustc")
            .args(&["-L",
                    "target/debug/deps/",
                    "-o",
                    "target/debug/schema-test",
                    "tests/support/schema-test.rs"])
            .status()
            .unwrap();

        assert!(result.success());
        let result = Command::new("./target/debug/schema-test")
            .status()
            .unwrap();

        assert!(result.success());
    }

    fn verify_compile(name: &str, s: &str) {

        let mut filename = PathBuf::from("target/debug");
        filename.push(&format!("{}.rs", name));
        {
            let mut file = File::create(&filename).unwrap();
            let header = r#"
            #![feature(proc_macro)]

            extern crate serde;
            #[macro_use]
            extern crate serde_derive;
            extern crate serde_json;
            "#;
            file.write_all(header.as_bytes()).unwrap();
            file.write_all(s.as_bytes()).unwrap();
        }
        println!("{}", filename.display());
        let child = Command::new("rustc")
            .args(&["-L",
                    "target/debug/deps/",
                    "--crate-type=rlib",
                    "-o",
                    &format!("target/debug/deps/lib{}.rlib", name),
                    filename.to_str().unwrap()])
            .stderr(Stdio::piped())
            .spawn()
            .unwrap();

        let output = child.wait_with_output().unwrap();
        let error = String::from_utf8(output.stderr).unwrap();
        assert!(output.status.success(), "{}", error);
    }

    #[test]
    fn builds_with_rustc() {
        let s = include_str!("../tests/debugserver-schema.json");

        let s = generate(None, s).unwrap().to_string();

        verify_compile("debug-server", &s)
    }
}
<|endoftext|>


<commit_before>//! The `ipnetwork` crate provides a set of APIs to work with IP CIDRs in
//! Rust. Implementation for IPv4 is more or less stable, IPv6 implementation
//! is still WIP.
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]
#![crate_type = "lib"]

use std::fmt;
use std::net::IpAddr;

mod ipv4;
mod ipv6;
mod common;

use std::str::FromStr;

pub use ipv4::{Ipv4Network, ipv4_mask_to_prefix};
pub use ipv6::{Ipv6Network, ipv6_mask_to_prefix};
pub use common::IpNetworkError;

/// Represents a generic network range. This type can have two variants:
/// the v4 and the v6 case.
#[derive(Debug,Clone,Copy,Hash,PartialEq,Eq)]
pub enum IpNetwork {
    V4(Ipv4Network),
    V6(Ipv6Network),
}

impl IpNetwork {
    /// Constructs a new `IpNetwork` from a given `IpAddr` and a prefix denoting the
    /// network size. If the prefix is larger than 32 (for IPv4) or 128 (for IPv6), this
    /// will raise an `IpNetworkError::InvalidPrefix` error. Support for IPv6 is not
    /// complete yet.
    pub fn new(ip: IpAddr, prefix: u8) -> Result<IpNetwork, IpNetworkError> {
        match ip {
            IpAddr::V4(a) => Ok(IpNetwork::V4(Ipv4Network::new(a, prefix)?)),
            IpAddr::V6(a) => Ok(IpNetwork::V6(Ipv6Network::new(a, prefix)?)),
        }
    }

    /// Returns the IP part of a given `IpNetwork`
    pub fn ip(&self) -> IpAddr {
        match *self {
            IpNetwork::V4(ref a) => IpAddr::V4(a.ip()),
            IpNetwork::V6(ref a) => IpAddr::V6(a.ip()),
        }
    }

    /// Returns the prefix of the given `IpNetwork`
    ///
    /// # Example
    /// ```
    /// use ipnetwork::IpNetwork;
    ///
    /// assert_eq!(IpNetwork::V4("10.9.0.32/16".parse().unwrap()).prefix(), 16u8);
    /// assert_eq!(IpNetwork::V6("ff01::0/32".parse().unwrap()).prefix(), 32u8);
    /// ```
    pub fn prefix(&self) -> u8 {
        match *self {
            IpNetwork::V4(ref a) => a.prefix(),
            IpNetwork::V6(ref a) => a.prefix(),
        }
    }

    /// Returns the mask of the given `IpNetwork`
    ///
    /// # Example
    /// ```
    /// use ipnetwork::IpNetwork;
    ///
    /// assert_eq!(IpNetwork::V4("10.9.0.32/16".parse().unwrap()).mask(), 16u8);
    /// assert_eq!(IpNetwork::V6("ff01::0/32".parse().unwrap()).mask(), 32u8);
    ///```
    pub fn mask(&self) -> IpAddr {
        match *self {
            IpNetwork::V4(ref a) => IpAddr::V4(a.mask()),
            IpNetwork::V6(ref a) => IpAddr::V6(a.mask()),
        }
    }

    /// Returns true if the IP in this `IpNetwork` is a valid IPv4 address,
    /// false if it's a valid IPv6 address.
    ///
    /// # Example
    ///
    ///```
    /// use ipnetwork::IpNetwork;
    ///
    /// let v4: IpNetwork = IpNetwork::V4("10.9.0.32/16".parse().unwrap());
    /// assert_eq!(v4.is_ipv4(), true);
    /// assert_eq!(v4.is_ipv6(), false);
    ///```
    pub fn is_ipv4(&self) -> bool {
        match *self {
            IpNetwork::V4(_) => true,
            IpNetwork::V6(_) => false,
        }
    }

    /// Returns true if the IP in this `IpNetwork` is a valid IPv6 address,
    /// false if it's a valid IPv4 address.
    ///
    /// # Example
    ///
    ///```
    /// use ipnetwork::IpNetwork;
    ///
    /// let v6: IpNetwork = IpNetwork::V6("ff01::0/32".parse().unwrap());
    /// assert_eq!(v6.is_ipv6(), true);
    /// assert_eq!(v6.is_ipv4(), false);
    ///```
    pub fn is_ipv6(&self) -> bool {
        match *self {
            IpNetwork::V4(_) => false,
            IpNetwork::V6(_) => true,
        }
    }
}

/// Constructs a new `IpNetwork` from a given &str with a prefix denoting the
/// network size.  If the prefix is larger than 32 (for IPv4) or 128 (for IPv6), this
/// will raise an `IpNetworkError::InvalidPrefix` error.
/// # Examples
///
/// ```
/// use std::net::Ipv4Addr;
/// use ipnetwork::Ipv4Network;
/// use ipnetwork::IpNetwork;
///
/// let expected = IpNetwork::V4(Ipv4Network::new(Ipv4Addr::new(10, 1, 9, 32), 16).unwrap());
/// let from_cidr: IpNetwork = "10.1.9.32/16".parse().unwrap();
/// assert_eq!(expected.ip(), from_cidr.ip());
/// assert_eq!(expected.prefix(), from_cidr.prefix());
impl FromStr for IpNetwork {
    type Err = IpNetworkError;
    fn from_str(s: &str) -> Result<IpNetwork, IpNetworkError> {
        let v4addr: Result<Ipv4Network, IpNetworkError> = s.parse();
        let v6addr: Result<Ipv6Network, IpNetworkError> = s.parse();

        if v4addr.is_ok() {
            Ok(IpNetwork::V4(v4addr.unwrap()))
        } else if v6addr.is_ok() {
            Ok(IpNetwork::V6(v6addr.unwrap()))
        } else {
            Err(IpNetworkError::InvalidAddr(s.to_string()))
        }
    }
}

impl From<Ipv4Network> for IpNetwork {
    fn from(v4: Ipv4Network) -> IpNetwork {
        IpNetwork::V4(v4)
    }
}

impl From<Ipv6Network> for IpNetwork {
    fn from(v6: Ipv6Network) -> IpNetwork {
        IpNetwork::V6(v6)
    }
}

impl fmt::Display for IpNetwork {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IpNetwork::V4(net) => net.fmt(f),
            IpNetwork::V6(net) => net.fmt(f),
        }
    }
}

/// Converts a `IpAddr` network mask into a prefix.
/// If the mask is invalid this will return an `IpNetworkError::InvalidPrefix`.
pub fn ip_mask_to_prefix(mask: IpAddr) -> Result<u8, IpNetworkError> {
    match mask {
        IpAddr::V4(mask) => ipv4_mask_to_prefix(mask),
        IpAddr::V6(mask) => ipv6_mask_to_prefix(mask),
    }
}
<commit_msg>Simplify IpNetwork::from_str impl and update docs<commit_after>//! The `ipnetwork` crate provides a set of APIs to work with IP CIDRs in
//! Rust. Implementation for IPv4 is more or less stable, IPv6 implementation
//! is still WIP.
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]
#![crate_type = "lib"]

use std::fmt;
use std::net::IpAddr;

mod ipv4;
mod ipv6;
mod common;

use std::str::FromStr;

pub use ipv4::{Ipv4Network, ipv4_mask_to_prefix};
pub use ipv6::{Ipv6Network, ipv6_mask_to_prefix};
pub use common::IpNetworkError;

/// Represents a generic network range. This type can have two variants:
/// the v4 and the v6 case.
#[derive(Debug,Clone,Copy,Hash,PartialEq,Eq)]
pub enum IpNetwork {
    V4(Ipv4Network),
    V6(Ipv6Network),
}

impl IpNetwork {
    /// Constructs a new `IpNetwork` from a given `IpAddr` and a prefix denoting the
    /// network size. If the prefix is larger than 32 (for IPv4) or 128 (for IPv6), this
    /// will raise an `IpNetworkError::InvalidPrefix` error. Support for IPv6 is not
    /// complete yet.
    pub fn new(ip: IpAddr, prefix: u8) -> Result<IpNetwork, IpNetworkError> {
        match ip {
            IpAddr::V4(a) => Ok(IpNetwork::V4(Ipv4Network::new(a, prefix)?)),
            IpAddr::V6(a) => Ok(IpNetwork::V6(Ipv6Network::new(a, prefix)?)),
        }
    }

    /// Returns the IP part of a given `IpNetwork`
    pub fn ip(&self) -> IpAddr {
        match *self {
            IpNetwork::V4(ref a) => IpAddr::V4(a.ip()),
            IpNetwork::V6(ref a) => IpAddr::V6(a.ip()),
        }
    }

    /// Returns the prefix of the given `IpNetwork`
    ///
    /// # Example
    /// ```
    /// use ipnetwork::IpNetwork;
    ///
    /// assert_eq!(IpNetwork::V4("10.9.0.32/16".parse().unwrap()).prefix(), 16u8);
    /// assert_eq!(IpNetwork::V6("ff01::0/32".parse().unwrap()).prefix(), 32u8);
    /// ```
    pub fn prefix(&self) -> u8 {
        match *self {
            IpNetwork::V4(ref a) => a.prefix(),
            IpNetwork::V6(ref a) => a.prefix(),
        }
    }

    /// Returns the mask of the given `IpNetwork`
    ///
    /// # Example
    /// ```
    /// use ipnetwork::IpNetwork;
    ///
    /// assert_eq!(IpNetwork::V4("10.9.0.32/16".parse().unwrap()).mask(), 16u8);
    /// assert_eq!(IpNetwork::V6("ff01::0/32".parse().unwrap()).mask(), 32u8);
    ///```
    pub fn mask(&self) -> IpAddr {
        match *self {
            IpNetwork::V4(ref a) => IpAddr::V4(a.mask()),
            IpNetwork::V6(ref a) => IpAddr::V6(a.mask()),
        }
    }

    /// Returns true if the IP in this `IpNetwork` is a valid IPv4 address,
    /// false if it's a valid IPv6 address.
    ///
    /// # Example
    ///
    ///```
    /// use ipnetwork::IpNetwork;
    ///
    /// let v4: IpNetwork = IpNetwork::V4("10.9.0.32/16".parse().unwrap());
    /// assert_eq!(v4.is_ipv4(), true);
    /// assert_eq!(v4.is_ipv6(), false);
    ///```
    pub fn is_ipv4(&self) -> bool {
        match *self {
            IpNetwork::V4(_) => true,
            IpNetwork::V6(_) => false,
        }
    }

    /// Returns true if the IP in this `IpNetwork` is a valid IPv6 address,
    /// false if it's a valid IPv4 address.
    ///
    /// # Example
    ///
    ///```
    /// use ipnetwork::IpNetwork;
    ///
    /// let v6: IpNetwork = IpNetwork::V6("ff01::0/32".parse().unwrap());
    /// assert_eq!(v6.is_ipv6(), true);
    /// assert_eq!(v6.is_ipv4(), false);
    ///```
    pub fn is_ipv6(&self) -> bool {
        match *self {
            IpNetwork::V4(_) => false,
            IpNetwork::V6(_) => true,
        }
    }
}

/// Tries to parse the given string into a `IpNetwork`. Will first try to parse
/// it as an `Ipv4Network` and if that fails as an `Ipv6Network`. If both
/// fails it will return an `InvalidAddr` error.
///
/// # Examples
///
/// ```
/// use std::net::Ipv4Addr;
/// use ipnetwork::{IpNetwork, Ipv4Network};
///
/// let expected = IpNetwork::V4(Ipv4Network::new(Ipv4Addr::new(10, 1, 9, 32), 16).unwrap());
/// let from_cidr: IpNetwork = "10.1.9.32/16".parse().unwrap();
/// assert_eq!(expected, from_cidr);
/// ```
impl FromStr for IpNetwork {
    type Err = IpNetworkError;
    fn from_str(s: &str) -> Result<IpNetwork, IpNetworkError> {
        if let Ok(net) = Ipv4Network::from_str(s) {
            Ok(IpNetwork::V4(net))
        } else if let Ok(net) = Ipv6Network::from_str(s) {
            Ok(IpNetwork::V6(net))
        } else {
            Err(IpNetworkError::InvalidAddr(s.to_string()))
        }
    }
}

impl From<Ipv4Network> for IpNetwork {
    fn from(v4: Ipv4Network) -> IpNetwork {
        IpNetwork::V4(v4)
    }
}

impl From<Ipv6Network> for IpNetwork {
    fn from(v6: Ipv6Network) -> IpNetwork {
        IpNetwork::V6(v6)
    }
}

impl fmt::Display for IpNetwork {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IpNetwork::V4(net) => net.fmt(f),
            IpNetwork::V6(net) => net.fmt(f),
        }
    }
}

/// Converts a `IpAddr` network mask into a prefix.
/// If the mask is invalid this will return an `IpNetworkError::InvalidPrefix`.
pub fn ip_mask_to_prefix(mask: IpAddr) -> Result<u8, IpNetworkError> {
    match mask {
        IpAddr::V4(mask) => ipv4_mask_to_prefix(mask),
        IpAddr::V6(mask) => ipv6_mask_to_prefix(mask),
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_name = "string_cache"]
#![crate_type = "rlib"]

#![feature(phase, macro_rules)]

extern crate sync;
extern crate debug;

#[cfg(test)]
extern crate test;

#[phase(plugin)]
extern crate phf_mac;
extern crate phf;

#[phase(plugin)]
extern crate string_cache_macros;

pub mod atom;

// A private module so that macro-expanded idents like
// `::string_cache::atom::Atom` will also work in this crate.
//
// `libstd` uses the same trick.
#[doc(hidden)]
mod string_cache {
    pub use atom;
}
<commit_msg>Re-export atom::Atom at top level<commit_after>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_name = "string_cache"]
#![crate_type = "rlib"]

#![feature(phase, macro_rules)]

extern crate sync;
extern crate debug;

#[cfg(test)]
extern crate test;

#[phase(plugin)]
extern crate phf_mac;
extern crate phf;

#[phase(plugin)]
extern crate string_cache_macros;

pub use atom::Atom;

pub mod atom;

// A private module so that macro-expanded idents like
// `::string_cache::atom::Atom` will also work in this crate.
//
// `libstd` uses the same trick.
#[doc(hidden)]
mod string_cache {
    pub use atom;
}
<|endoftext|>


<commit_before>//! High performance XML reader/writer.
//!
//! ## Description
//!
//! - `Reader`: a low level xml pull-reader where buffer allocation/clearing is left to user
//! - `Writer`: a xml writer. Can be nested with readers if you want to transform xmls
//!
//! ## Examples
//!
//! ### Reader
//!
//! ```rust
//! use quick_xml::Reader;
//! use quick_xml::events::Event;
//!
//! let xml = r#"<tag1 att1 = "test">
//!                 <tag2><!--Test comment-->Test</tag2>
//!                 <tag2>
//!                     Test 2
//!                 </tag2>
//!             </tag1>"#;
//!
//! let mut reader = Reader::from_str(xml);
//! reader.trim_text(true);
//!
//! let mut count = 0;
//! let mut txt = Vec::new();
//! let mut buf = Vec::new();
//!
//! // The `Reader` does not implement `Iterator` because it outputs borrowed data (`Cow`s)
//! loop {
//!     match reader.read_event(&mut buf) {
//!     // for triggering namespaced events, use this instead:
//!     // match reader.read_namespaced_event(&mut buf) {
//!         Ok(Event::Start(ref e)) => {
//!         // for namespaced:
//!         // Ok((ref namespace_value, Event::Start(ref e)))
//!             match e.name() {
//!                 b"tag1" => println!("attributes values: {:?}",
//!                                     e.attributes().map(|a| a.unwrap().value)
//!                                     .collect::<Vec<_>>()),
//!                 b"tag2" => count += 1,
//!                 _ => (),
//!             }
//!         },
//!         // unescape and decode the text event using the reader encoding
//!         Ok(Event::Text(e)) => txt.push(e.unescape_and_decode(&reader).unwrap()),
//!         Ok(Event::Eof) => break, // exits the loop when reaching end of file
//!         Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
//!         _ => (), // There are several other `Event`s we do not consider here
//!     }
//!
//!     // if we don't keep a borrow elsewhere, we can clear the buffer to keep memory usage low
//!     buf.clear();
//! }
//! ```
//!
//! ### Writer
//!
//! ```rust
//! use quick_xml::Writer;
//! use quick_xml::events::{Event, BytesEnd, BytesStart};
//! use quick_xml::Reader;
//! use std::io::Cursor;
//! use std::iter;
//!
//! let xml = r#"<this_tag k1="v1" k2="v2"><child>text</child></this_tag>"#;
//! let mut reader = Reader::from_str(xml);
//! reader.trim_text(true);
//! let mut writer = Writer::new(Cursor::new(Vec::new()));
//! let mut buf = Vec::new();
//! loop {
//!     match reader.read_event(&mut buf) {
//!         Ok(Event::Start(ref e)) if e.name() == b"this_tag" => {
//!
//!             // crates a new element ... alternatively we could reuse `e` by calling
//!             // `e.into_owned()`
//!             let mut elem = BytesStart::owned(b"my_elem".to_vec(), "my_elem".len());
//!
//!             // collect existing attributes
//!             elem.extend_attributes(e.attributes().map(|attr| attr.unwrap()));
//!
//!             // copy existing attributes, adds a new my-key="some value" attribute
//!             elem.push_attribute(("my-key", "some value"));
//!
//!             // writes the event to the writer
//!             assert!(writer.write_event(Event::Start(elem)).is_ok());
//!         },
//!         Ok(Event::End(ref e)) if e.name() == b"this_tag" => {
//!             assert!(writer.write_event(Event::End(BytesEnd::borrowed(b"my_elem"))).is_ok());
//!         },
//!         Ok(Event::Eof) => break,
//!         Ok(e) => assert!(writer.write_event(e).is_ok()),
//!         // or using the buffer
//!         // Ok(e) => assert!(writer.write(&buf).is_ok()),
//!         Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
//!     }
//!     buf.clear();
//! }
//!
//! let result = writer.into_inner().into_inner();
//! let expected = r#"<my_elem k1="v1" k2="v2" my-key="some value"><child>text</child></my_elem>"#;
//! assert_eq!(result, expected.as_bytes());
//! ```
//!
//! # Features
//!
//! quick-xml supports 2 additional features, non activated by default:
//! - `encoding`: support non utf8 xmls
//! - `serialize`: support serde `Serialize`/`Deserialize`
#![forbid(unsafe_code)]
#![deny(missing_docs)]
#![recursion_limit = "1024"]

#[cfg(feature = "encoding_rs")]
extern crate encoding_rs;
extern crate memchr;
#[cfg(feature = "serialize")]
extern crate serde;
#[cfg(all(test, feature = "serialize"))]
extern crate serde_value;

#[cfg(feature = "serialize")]
pub mod de;
mod errors;
mod escapei;
pub mod escape {
    //! Manage xml character escapes
    pub(crate) use escapei::{do_unescape, EscapeError};
    pub use escapei::{escape, unescape, unescape_with};
}
pub mod events;
mod reader;
#[cfg(feature = "serialize")]
pub mod se;
mod utils;
mod writer;

// reexports
#[cfg(feature = "serialize")]
pub use errors::serialize::DeError;
pub use errors::{Error, Result};
pub use reader::Reader;
pub use writer::Writer;
<commit_msg>Crate documentation<commit_after>//! High performance XML reader/writer.
//!
//! ## Description
//!
//! quick-xml contains two modes of operation:
//!
//! A streaming API based on the [StAX] model. This is suited for larger XML documents which
//! cannot completely read into memory at once.
//!
//! The user has to expicitely _ask_ for the next XML event, similar
//! to a database cursor.
//! This is achieved by the following two structs:
//!
//! - [`Reader`]: A low level XML pull-reader where buffer allocation/clearing is left to user.
//! - [`Writer`]: A XML writer. Can be nested with readers if you want to transform XMLs.
//!
//! Especially for nested XML elements, the user must keep track _where_ (how deep) in the XML document
//! the current event is located. This is needed as the
//!
//! Furthermore, quick-xml also contains optional [Serde] support to directly serialize and deserialize from
//! structs, without having to deal with the XML events.
//!
//! ## Examples
//!
//! ### Reader
//!
//! ```rust
//! use quick_xml::Reader;
//! use quick_xml::events::Event;
//!
//! let xml = r#"<tag1 att1 = "test">
//!                 <tag2><!--Test comment-->Test</tag2>
//!                 <tag2>
//!                     Test 2
//!                 </tag2>
//!             </tag1>"#;
//!
//! let mut reader = Reader::from_str(xml);
//! reader.trim_text(true);
//!
//! let mut count = 0;
//! let mut txt = Vec::new();
//! let mut buf = Vec::new();
//!
//! // The `Reader` does not implement `Iterator` because it outputs borrowed data (`Cow`s)
//! loop {
//!     match reader.read_event(&mut buf) {
//!     // for triggering namespaced events, use this instead:
//!     // match reader.read_namespaced_event(&mut buf) {
//!         Ok(Event::Start(ref e)) => {
//!         // for namespaced:
//!         // Ok((ref namespace_value, Event::Start(ref e)))
//!             match e.name() {
//!                 b"tag1" => println!("attributes values: {:?}",
//!                                     e.attributes().map(|a| a.unwrap().value)
//!                                     .collect::<Vec<_>>()),
//!                 b"tag2" => count += 1,
//!                 _ => (),
//!             }
//!         },
//!         // unescape and decode the text event using the reader encoding
//!         Ok(Event::Text(e)) => txt.push(e.unescape_and_decode(&reader).unwrap()),
//!         Ok(Event::Eof) => break, // exits the loop when reaching end of file
//!         Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
//!         _ => (), // There are several other `Event`s we do not consider here
//!     }
//!
//!     // if we don't keep a borrow elsewhere, we can clear the buffer to keep memory usage low
//!     buf.clear();
//! }
//! ```
//!
//! ### Writer
//!
//! ```rust
//! use quick_xml::Writer;
//! use quick_xml::events::{Event, BytesEnd, BytesStart};
//! use quick_xml::Reader;
//! use std::io::Cursor;
//! use std::iter;
//!
//! let xml = r#"<this_tag k1="v1" k2="v2"><child>text</child></this_tag>"#;
//! let mut reader = Reader::from_str(xml);
//! reader.trim_text(true);
//! let mut writer = Writer::new(Cursor::new(Vec::new()));
//! let mut buf = Vec::new();
//! loop {
//!     match reader.read_event(&mut buf) {
//!         Ok(Event::Start(ref e)) if e.name() == b"this_tag" => {
//!
//!             // crates a new element ... alternatively we could reuse `e` by calling
//!             // `e.into_owned()`
//!             let mut elem = BytesStart::owned(b"my_elem".to_vec(), "my_elem".len());
//!
//!             // collect existing attributes
//!             elem.extend_attributes(e.attributes().map(|attr| attr.unwrap()));
//!
//!             // copy existing attributes, adds a new my-key="some value" attribute
//!             elem.push_attribute(("my-key", "some value"));
//!
//!             // writes the event to the writer
//!             assert!(writer.write_event(Event::Start(elem)).is_ok());
//!         },
//!         Ok(Event::End(ref e)) if e.name() == b"this_tag" => {
//!             assert!(writer.write_event(Event::End(BytesEnd::borrowed(b"my_elem"))).is_ok());
//!         },
//!         Ok(Event::Eof) => break,
//!         Ok(e) => assert!(writer.write_event(e).is_ok()),
//!         // or using the buffer
//!         // Ok(e) => assert!(writer.write(&buf).is_ok()),
//!         Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
//!     }
//!     buf.clear();
//! }
//!
//! let result = writer.into_inner().into_inner();
//! let expected = r#"<my_elem k1="v1" k2="v2" my-key="some value"><child>text</child></my_elem>"#;
//! assert_eq!(result, expected.as_bytes());
//! ```
//!
//! # Features
//!
//! quick-xml supports 2 additional features, non activated by default:
//! - `encoding`: support non utf8 XMLs
//! - `serialize`: support serde `Serialize`/`Deserialize`
//!
//! [StAX]: https://en.wikipedia.org/wiki/StAX
//! [Serde]: https://serde.rs/
#![forbid(unsafe_code)]
#![deny(missing_docs)]
#![recursion_limit = "1024"]

#[cfg(feature = "encoding_rs")]
extern crate encoding_rs;
extern crate memchr;
#[cfg(feature = "serialize")]
extern crate serde;
#[cfg(all(test, feature = "serialize"))]
extern crate serde_value;

#[cfg(feature = "serialize")]
pub mod de;
mod errors;
mod escapei;
pub mod escape {
    //! Manage xml character escapes
    pub(crate) use escapei::{do_unescape, EscapeError};
    pub use escapei::{escape, unescape, unescape_with};
}
pub mod events;
mod reader;
#[cfg(feature = "serialize")]
pub mod se;
mod utils;
mod writer;

// reexports
#[cfg(feature = "serialize")]
pub use errors::serialize::DeError;
pub use errors::{Error, Result};
pub use reader::Reader;
pub use writer::Writer;
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::collections::HashMap;
use std::rc::Rc;

// Metadata for an histogram.
#[allow(dead_code)]
struct Metadata {

    // The name of the histogram. Must be unique in the application.
    name: String,

    // A list of e-mails to alert of evolutions in the histogram. Alerts
    // are handled by the server component.
    alerts: Vec<String>,

    // A human-readable description for the histogram.
    description: String,

    // If provided, stop recording after a given version of the
    // application.
    expires_in_version: Option<String>,
}

trait HistogramBase {
    // FIXME: In the future, this trait will know about
    // (de)serializing both the content of an histogram
    // and its metadata.
}
trait Histogram<T> : HistogramBase {
    fn record(&mut self, T);
}

trait KeyedHistogramBase {
    // FIXME: In the future, this trait will know about
    // (de)serializing both the content of an histogram
    // and its metadata.
}

struct KeyedHistogram<K, H, T> where H : Histogram<T> {
    placeholder: PhantomData<T>,
    family: HashMap<K, Rc<H>>
}

impl<K, H, T> KeyedHistogramBase for KeyedHistogram<K, H, T> where H: Histogram<T>{
}

// This histogram type allows you to record a single value. This type
// is useful if you need to track whether a feature was ever used
// during a session. You only need to add a single line of code which
// sets the flag when the feature is used because the histogram is
// initialized with a default value of false (flag not set).
pub struct Flag {
    encountered: bool
}

#[allow(dead_code)]
impl Flag {
    fn new(mut telemetry: Telemetry, meta: Metadata) -> Rc<Flag> {
        let histogram = Rc::new(Flag { encountered: false });
        telemetry.register_flat(meta, histogram.clone());
        histogram
    }

    fn new_keyed<K>(mut telemetry: Telemetry, meta: Metadata) -> KeyedHistogram<K, Flag, ()> {
        // FIXME: Construct data structure.
        // FIXME: Register.
        unreachable!()
    }
}

impl Histogram<()> for Flag {
    fn record(&mut self, _: ()) {
        self.encountered = true;
        // FIXME: Store data.
        unreachable!()
    }
}

impl HistogramBase for Flag {
}

// These histograms only record boolean values. Multiple boolean
// entries can be recorded in the same histogram during a single
// browsing session, e.g. if a histogram is measuring user choices in
// a dialog box with options "Yes" or "No", a new boolean value is
// added every time the dialog is displayed.
pub struct Boolean; // FIXME: Define.

#[allow(dead_code)]
impl Boolean {
    fn new(_: Metadata) -> Rc<Boolean> {
        // FIXME: Construct data structure.
        // FIXME: Register.
        unreachable!()
    }
}

impl Histogram<bool> for Boolean {
    fn record(&mut self, _: bool) {
        unreachable!() // TODO
    }
}

impl HistogramBase for Boolean {
}

// This histogram type is used when you want to record a count of
// something. It only stores a single value and it can only be
// incremented by one with each add/accumulate call.
pub struct Count; // TODO

#[allow(dead_code)]
impl Count {
    fn new(_: Metadata) -> Rc<Count> {
        // FIXME: Construct data structure.
        // FIXME: Register.
        unreachable!()
    }
}

impl Histogram<()> for Count {
    fn record(&mut self, _: ()) {
        unreachable!() // TODO
    }
}

impl HistogramBase for Count {
}

// This histogram type is intended for storing "enum" values. An
// enumerated histogram consists of a fixed number of "buckets", each
// of which is associated with a consecutive integer value (the
// bucket's "label"). Each bucket corresponds to an enum value and
// counts the number of times its particular enum value was
// recorded. You might use this type of histogram if, for example, you
// wanted to track the relative popularity of SSL handshake
// types. Whenever the browser started an SSL handshake, it would
// record one of a limited number of enum values which uniquely
// identifies the handshake type.
pub struct Enumerated<T> where T: AsU32<T> { // TODO
    placeholder: PhantomData<T>
}

#[allow(dead_code)]
impl<T> Enumerated<T> where T: AsU32<T> {
    fn new(_: Metadata, max_value: u32) -> Enumerated<T> {
        unreachable!() // TODO
    }
}

// A type (typically, an enumeration) that can be represented as a
// number.
pub trait AsU32<T> {
    fn as_u32(T) -> u32 {
        unreachable!() // TODO
    }
    fn from_u32(u32) -> Option<T> {
        unreachable!() // TODO
    }
}

impl<T: AsU32<T>> Histogram<T> for Enumerated<T> {
    fn record(&mut self, _: T) {
        unreachable!() // TODO
    }
}

impl<T> HistogramBase for Enumerated<T> {
}

#[allow(dead_code)]
impl AsU32<u32> {
    fn as_u32(value: u32) -> u32 {
        value
    }
    fn from_u32(value: u32) -> Option<u32> {
        Some(value)
    }
}

// Linear histograms are similar to enumerated histograms, except each
// bucket is associated with a range of values instead of a single
// enum value. The range of values covered by each bucket increases
// linearly from the previous bucket, e.g. one bucket might count the
// number of occurrences of values between 0 to 9, the next bucket
// would cover values 10-19, the next 20-29, etc. This bucket type is
// useful if there aren't orders of magnitude differences between the
// minimum and maximum values stored in the histogram, e.g. if the
// values you are storing are percentages 0-100%.
//
// For the sake of type-safety (and in particular to help avoid errors
// with inconsistent units), by default, linear histograms do not
// accept raw integers, but rather `AsU32`.
pub struct Linear<T> where T: AsU32<T> { // TODO
    placeholder: PhantomData<T>
}

#[allow(unused_variables)]
impl<T> Linear<T> where T: AsU32<T> {
    fn new(mut telemetry: Telemetry, meta: Metadata, min: u32, high: u32, buckets: u16) -> Rc<Linear<T>> {
        unreachable!() // TODO
    }
}

impl<T> Histogram<u32> for Linear<T> where T:AsU32<T> {
    fn record(&mut self, _: u32) {
        unreachable!() // TODO
    }
}

impl<T> HistogramBase for Linear<T> {
}

// Exponential histograms are similar to linear histograms but the
// range of values covered by each bucket increases exponentially. As
// an example of its use, consider the timings of an I/O operation
// whose duration might normally fall in the range of 0ms-50ms but
// extreme cases might have durations in seconds or minutes. For such
// measurements, you would want finer-grained bucketing in the normal
// range but coarser-grained bucketing for the extremely large
// values. An exponential histogram fits this requirement since it has
// "narrow" buckets near the minimum value and significantly "wider"
// buckets near the maximum value.
//
// For the sake of type-safety (and in particular to help avoid errors
// with inconsistent units), by default, exponential histograms do not
// accept raw integers, but rather `AsU32`.
pub struct Exponential<T> where T: AsU32<T> { // TODO
    placeholder: PhantomData<T>
}

#[allow(unused_variables)]
impl<T> Exponential<T> where T: AsU32<T> {
    fn new(mut telemetry: Telemetry, meta: Metadata, min: u32, high: u32, buckets: u16) -> Rc<Exponential<T>> {
        unreachable!() // TODO
    }
}

impl<T> Histogram<u32> for Exponential<T> where T:AsU32<T> {
    fn record(&mut self, _: u32) {
        unreachable!() // TODO
    }
}

impl<T> HistogramBase for Exponential<T> {
}

#[allow(dead_code)]
struct Telemetry {
    flat_histograms: HashMap<String, Rc<HistogramBase>>,
    keyed_histograms: HashMap<String, Rc<KeyedHistogramBase>>
}

#[allow(dead_code)]
pub struct StorageSettings; // TODO
#[allow(dead_code)]
pub struct ServerSettings; // TODO

#[allow(dead_code)]
#[allow(unused_variables)]
impl Telemetry {
    pub fn new(version: String, _: Option<StorageSettings>, _: Option<ServerSettings>) -> Telemetry {
        unreachable!() // TODO
    }

    // If an histogram is active, record a new value to the histogram.
    // Otherwise, do nothing.
    pub fn record<T>(&mut self, _: &Histogram<T>, _: &FnOnce() -> Option<T>) {
        unreachable!() // TODO
    }
    pub fn record_keyed<K, H, T>(&mut self, _: &KeyedHistogram<K, H, T>, _: &FnOnce() -> Option<(K, T)>) {
        unreachable!() // TODO
    }

    // Activate or deactivate Telemetry.
    pub fn set_active(&mut self, _: bool) {
        unreachable!() // TODO
    }
    pub fn is_active(&self) -> bool {
        unreachable!() // TODO
    }

    // Activate or dactivate individual histograms. Ignored if Telemetry
    // is deactivated or if the histogram has expired.
    pub fn set_active_histogram<T>(&mut self, _: Histogram<T>, _: bool) {
        unreachable!() // TODO
    }
    pub fn is_active_histogram<T>(&self, _: Histogram<T>) -> bool {
        unreachable!() // TODO
    }

    // Called automatically by histogram constructors.
    fn register_flat(&mut self, meta: Metadata, histogram: Rc<HistogramBase>) {
        self.flat_histograms.insert(meta.name, histogram); // FIXME: Make sure that we register each name only once.
    }
    fn register_keyed(&mut self, meta: Metadata, histogram: Rc<KeyedHistogramBase>) {
        self.keyed_histograms.insert(meta.name, histogram); // FIXME: Make sure that we register each name only once.
    }

    // Export the list of histograms to a json document that may be
    // uploaded to a Telemetry server.
    pub fn export_histograms(&self) -> String {
        unreachable!() // TODO
    }
}

<commit_msg>Cleanup, more doc<commit_after>use std::marker::PhantomData;
use std::collections::HashMap;
use std::rc::Rc;

extern crate rustc_serialize;
use rustc_serialize::json::Json;

//
// Telemetry is a mechanism used to capture metrics in an application,
// and either store the data locally or upload to a server for
// statistical analysis.
//
// Examples of usage:
// - capturing the speed of an operation;
// - finding out if users are actually using a feature;
// - finding out how the duration of a session;
// - determine the operating system on which the application is executed;
// - determining the configuration of the application;
// - capturing the operations that slow down the application;
// - determining the amount of I/O performed by the application;
// - ...
//
// The abstraction used by this library is the Histogram. Each
// Histogram serves to capture a specific measurement, store it
// locally and/or upload it to the server. Several types of Histograms
// are provided, suited to distinct kinds of measures.
//

#[allow(dead_code)]
#[allow(unused_variables)]
impl Telemetry {
    // Instantiate telemetry for a given product version.
    pub fn new(version: String, _: Option<StorageSettings>, _: Option<ServerSettings>) -> Telemetry {
        unreachable!() // TODO
    }

    //
    // If an histogram is active, record a new value to the histogram.
    // Otherwise, do nothing. For a histogram to be active, the
    // following conditions must be met:
    // - Telemetry must be active;
    // - the histogram must not have been deactivated with `set_active_histogram`
    // - the histogram must not have expired.
    //
    pub fn record<T, F>(&mut self, histogram: &mut Histogram<T>, closure: F) where F: FnOnce() -> Option<T>{
        if !self.is_active {
            return;
        }
        // FIXME: Handle other cases in which the histogram may be deactivated.
        match closure() {
            Some(x) => histogram.record(x),
            None => {}
        }
    }
    pub fn record_keyed<K, H, T>(&mut self, _: &KeyedHistogram<K, H, T>, _: &FnOnce() -> Option<(K, T)>) {
        unreachable!() // TODO
    }

    // Activate or deactivate Telemetry. If Telemetry is deactivated,
    // calling `record`/`record_keyed` will have no effect.
    pub fn set_active(&mut self, value: bool) {
        self.is_active = value
    }
    pub fn is_active(&self) -> bool {
        self.is_active
    }

    // Activate or dactivate individual histograms. Ignored if Telemetry
    // is deactivated or if the histogram has expired.
    pub fn set_histogram_active<T>(&mut self, _: Histogram<T>, _: bool) {
        unreachable!() // TODO
    }
    pub fn is_histogram_active<T>(&self, _: Histogram<T>) -> bool {
        unreachable!() // TODO
    }

    // Export the list of histograms to a json document that may be
    // uploaded to a Telemetry server. This list does not contain the
    // values, only the metadata needed by the server to make sense of
    // data that has been uploaded.
    pub fn export_histograms(&self) -> Json {
        unreachable!() // TODO
    }

    // Called automatically by histogram constructors.
    fn register_flat(&mut self, meta: Metadata, histogram: Rc<HistogramBase>) {
        let previous = self.flat_histograms.insert(meta.name, histogram);
        assert!(previous.is_none());
    }
    fn register_keyed(&mut self, meta: Metadata, histogram: Rc<KeyedHistogramBase>) {
        let previous = self.keyed_histograms.insert(meta.name, histogram);
        assert!(previous.is_none());
    }
}

// Metadata for an histogram.
#[allow(dead_code)]
struct Metadata {
    // The name of the histogram. Must be unique in the application.
    name: String,

    // A list of e-mails to alert of evolutions in the histogram. Alerts
    // are handled by the server component.
    alerts: Vec<String>,

    // A human-readable description for the histogram. Don't forget to
    // include labels and units, if your measurement has any.
    description: String,

    // If provided, stop recording after a given version of the
    // application.
    expires_in_version: Option<String>,
}

trait HistogramBase {
    // FIXME: In the future, this trait will know about
    // (de)serializing both the content of an histogram
    // and its metadata, as well as how to (de)activate
    // the histogram.
}
trait Histogram<T> : HistogramBase {
    fn record(&mut self, T);
}

trait KeyedHistogramBase {
    // FIXME: In the future, this trait will know about
    // (de)serializing both the content of an histogram
    // and its metadata.
}

struct KeyedHistogram<K, H, T> where H : Histogram<T> {
    placeholder: PhantomData<T>,
    family: HashMap<K, Rc<H>>
}

impl<K, H, T> KeyedHistogramBase for KeyedHistogram<K, H, T> where H: Histogram<T>{
}

// This histogram type allows you to record a single value. This type
// is useful if you need to track whether a feature was ever used
// during a session. You only need to add a single line of code which
// sets the flag when the feature is used because the histogram is
// initialized with a default value of false (flag not set).
pub struct Flag {
    encountered: bool
}

#[allow(dead_code)]
impl Flag {
    fn new(mut telemetry: Telemetry, meta: Metadata) -> Rc<Flag> {
        let histogram = Rc::new(Flag { encountered: false });
        telemetry.register_flat(meta, histogram.clone());
        histogram
    }

    fn new_keyed<K>(mut telemetry: Telemetry, meta: Metadata) -> KeyedHistogram<K, Flag, ()> {
        // FIXME: Construct data structure.
        // FIXME: Register.
        unreachable!()
    }
}

impl Histogram<()> for Flag {
    fn record(&mut self, _: ()) {
        self.encountered = true
    }
}

impl HistogramBase for Flag {
}

// These histograms only record boolean values. Multiple boolean
// entries can be recorded in the same histogram during a single
// browsing session, e.g. if a histogram is measuring user choices in
// a dialog box with options "Yes" or "No", a new boolean value is
// added every time the dialog is displayed.
pub struct Boolean {
    value: bool
}

#[allow(dead_code)]
impl Boolean {
    fn new(_: Metadata) -> Rc<Boolean> {
        // FIXME: Construct data structure.
        // FIXME: Register.
        unreachable!()
    }
}

impl Histogram<bool> for Boolean {
    fn record(&mut self, value: bool) {
        self.value = value
    }
}

impl HistogramBase for Boolean {
}

// This histogram type is used when you want to record a count of
// something. It only stores a single value and it can only be
// incremented by one with each add/accumulate call.
pub struct Count {
    value: u32
}

#[allow(dead_code)]
impl Count {
    fn new(_: Metadata) -> Rc<Count> {
        // FIXME: Construct data structure.
        // FIXME: Register.
        unreachable!()
    }
}

impl Histogram<()> for Count {
    fn record(&mut self, _: ()) {
        self.value += 1
    }
}

impl HistogramBase for Count {
}

// This histogram type is intended for storing "enum" values. An
// enumerated histogram consists of a fixed number of "buckets", each
// of which is associated with a consecutive integer value (the
// bucket's "label"). Each bucket corresponds to an enum value and
// counts the number of times its particular enum value was
// recorded. You might use this type of histogram if, for example, you
// wanted to track the relative popularity of SSL handshake
// types. Whenever the browser started an SSL handshake, it would
// record one of a limited number of enum values which uniquely
// identifies the handshake type.
pub struct Enumerated<T> where T: AsSize<T> { // TODO
    phantom: PhantomData<T>,
    values: Vec<u32>
}

#[allow(dead_code)]
impl<T> Enumerated<T> where T: AsSize<T> {
    fn new(_: Metadata, max_value: usize) -> Enumerated<T> {
        unreachable!() // TODO
    }
}

// A type (typically, an enumeration) that can be represented as a
// number.
pub trait AsSize<T> {
    fn as_usize(T) -> usize;
    fn from_usize(usize) -> Option<T>;
}

impl<T: AsSize<T>> Histogram<T> for Enumerated<T> {
    fn record(&mut self, value: T) {
        let index = T::as_usize(value);
        self.values[index] += 1
    }
}

impl<T> HistogramBase for Enumerated<T> {
}

#[allow(dead_code)]
impl AsSize<u32> {
    fn as_usize(value: u32) -> usize {
        value as usize
    }
    fn from_usize(value: usize) -> Option<u32> {
        Some(value as u32)
    }
}

// Linear histograms are similar to enumerated histograms, except each
// bucket is associated with a range of values instead of a single
// enum value. The range of values covered by each bucket increases
// linearly from the previous bucket, e.g. one bucket might count the
// number of occurrences of values between 0 to 9, the next bucket
// would cover values 10-19, the next 20-29, etc. This bucket type is
// useful if there aren't orders of magnitude differences between the
// minimum and maximum values stored in the histogram, e.g. if the
// values you are storing are percentages 0-100%.
//
// For the sake of type-safety (and in particular to help avoid errors
// with inconsistent units), by default, linear histograms do not
// accept raw integers, but rather `AsSize`.
pub struct Linear<T> where T: AsSize<T> { // TODO
    placeholder: PhantomData<T>
}

#[allow(unused_variables)]
impl<T> Linear<T> where T: AsSize<T> {
    fn new(mut telemetry: Telemetry, meta: Metadata, min: u32, high: u32, buckets: u16) -> Rc<Linear<T>> {
        unreachable!() // TODO
    }
}

impl<T> Histogram<u32> for Linear<T> where T:AsSize<T> {
    fn record(&mut self, _: u32) {
        unreachable!() // TODO
    }
}

impl<T> HistogramBase for Linear<T> {
}

// Exponential histograms are similar to linear histograms but the
// range of values covered by each bucket increases exponentially. As
// an example of its use, consider the timings of an I/O operation
// whose duration might normally fall in the range of 0ms-50ms but
// extreme cases might have durations in seconds or minutes. For such
// measurements, you would want finer-grained bucketing in the normal
// range but coarser-grained bucketing for the extremely large
// values. An exponential histogram fits this requirement since it has
// "narrow" buckets near the minimum value and significantly "wider"
// buckets near the maximum value.
//
// For the sake of type-safety (and in particular to help avoid errors
// with inconsistent units), by default, exponential histograms do not
// accept raw integers, but rather `AsSize`.
pub struct Exponential<T> where T: AsSize<T> { // TODO
    placeholder: PhantomData<T>
}

#[allow(unused_variables)]
impl<T> Exponential<T> where T: AsSize<T> {
    fn new(mut telemetry: Telemetry, meta: Metadata, min: u32, high: u32, buckets: u16) -> Rc<Exponential<T>> {
        unreachable!() // TODO
    }
}

impl<T> Histogram<u32> for Exponential<T> where T:AsSize<T> {
    fn record(&mut self, _: u32) {
        unreachable!() // TODO
    }
}

impl<T> HistogramBase for Exponential<T> {
}

#[allow(dead_code)]
struct Telemetry {
    flat_histograms: HashMap<String, Rc<HistogramBase>>,
    keyed_histograms: HashMap<String, Rc<KeyedHistogramBase>>,
    is_active: bool,
}

#[allow(dead_code)]
pub struct StorageSettings; // TODO
#[allow(dead_code)]
pub struct ServerSettings; // TODO
<|endoftext|>


<commit_before>//! The Liquid templating language for Rust
//!
//! __http://liquidmarkup.org/__
//!
//! ```toml
//! [dependencies]
//! liquid = "0.9"
//! ```
//!
//! ## Example
//! ```rust
//! use liquid::{Renderable, Context, Value};
//!
//! let template = liquid::parse("Liquid! {{num | minus: 2}}", Default::default()).unwrap();
//!
//! let mut context = Context::new();
//! context.set_val("num", Value::Num(4f32));
//!
//! let output = template.render(&mut context);
//! assert_eq!(output.unwrap(), Some("Liquid! 2".to_string()));
//! ```
#![crate_name = "liquid"]
#![doc(html_root_url = "https://cobalt-org.github.io/liquid-rust/")]

// Deny warnings, except in dev mode
#![deny(warnings)]
// #![deny(missing_docs)]
#![cfg_attr(feature="dev", warn(warnings))]

// Allow zero pointers for lazy_static. Otherwise clippy will complain.
#![allow(unknown_lints)]
#![allow(zero_ptr)]

extern crate regex;
extern crate chrono;
extern crate unicode_segmentation;
extern crate itertools;
extern crate url;

#[macro_use]
extern crate lazy_static;
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;

use std::collections::HashMap;
use lexer::Element;
use tags::{assign_tag, cycle_tag, include_tag, break_tag, continue_tag, comment_block, raw_block,
           for_block, if_block, unless_block, capture_block, case_block};
use std::default::Default;
use std::fs::File;
use std::io::prelude::Read;
use std::path::{PathBuf, Path};
use error::Result;

pub use value::Value;
pub use value::Object;
pub use value::Array;
pub use context::Context;
pub use template::Template;
pub use error::Error;
pub use filters::FilterError;
pub use token::Token;

pub mod lexer;
pub mod parser;

mod token;
mod error;
mod template;
mod output;
mod text;
mod tags;
mod filters;
mod value;
mod variable;
mod context;
mod path;

/// A trait for creating custom tags. This is a simple type alias for a function.
///
/// This function will be called whenever the parser encounters a tag and returns
/// a new [Renderable](trait.Renderable.html) based on its parameters. The received parameters
/// specify the name of the tag, the argument [Tokens](lexer/enum.Token.html) passed to
/// the tag and the global [`LiquidOptions`](struct.LiquidOptions.html).
///
/// ## Minimal Example
/// ```
/// # use liquid::{Renderable, LiquidOptions, Context, Error, FnTagParser};
///
/// struct HelloWorld;
///
/// impl Renderable for HelloWorld {
///     fn render(&self, _context: &mut Context) -> Result<Option<String>, Error>{
///         Ok(Some("Hello World!".to_owned()))
///     }
/// }
///
/// let mut options : LiquidOptions = Default::default();
/// options.tags.insert(
///     "hello_world".to_owned(),
///     Box::new(FnTagParser::new(|_tag_name, _arguments, _options| {
///         Ok(Box::new(HelloWorld))
///     })),
/// );
///
/// let template = liquid::parse("{{hello_world}}", options).unwrap();
/// let mut data = Context::new();
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Hello World!".to_owned()));
/// ```
pub trait ParseTag: Send + Sync + ParseTagClone {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             options: &LiquidOptions)
             -> Result<Box<Renderable>>;
}

pub trait ParseTagClone {
    fn clone_box(&self) -> Box<ParseTag>;
}

impl<T> ParseTagClone for T
    where T: 'static + ParseTag + Clone
{
    fn clone_box(&self) -> Box<ParseTag> {
        Box::new(self.clone())
    }
}

impl Clone for Box<ParseTag> {
    fn clone(&self) -> Box<ParseTag> {
        self.clone_box()
    }
}

pub type FnParseTag = fn(&str, &[Token], &LiquidOptions) -> Result<Box<Renderable>>;

#[derive(Clone)]
pub struct FnTagParser {
    pub parser: FnParseTag,
}

impl FnTagParser {
    pub fn new(parser: FnParseTag) -> Self {
        Self { parser }
    }
}

impl ParseTag for FnTagParser {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             options: &LiquidOptions)
             -> Result<Box<Renderable>> {
        (self.parser)(tag_name, arguments, options)
    }
}

/// A trait for creating custom custom block-size tags (`{% if something %}{% endif %}`).
/// This is a simple type alias for a function.
///
/// This function will be called whenever the parser encounters a block and returns
/// a new `Renderable` based on its parameters. The received parameters specify the name
/// of the block, the argument [Tokens](lexer/enum.Token.html) passed to
/// the block, a Vec of all [Elements](lexer/enum.Element.html) inside the block and
/// the global [`LiquidOptions`](struct.LiquidOptions.html).
pub trait ParseBlock: Send + Sync + ParseBlockClone {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             tokens: &[Element],
             options: &LiquidOptions)
             -> Result<Box<Renderable>>;
}

pub trait ParseBlockClone {
    fn clone_box(&self) -> Box<ParseBlock>;
}

impl<T> ParseBlockClone for T
    where T: 'static + ParseBlock + Clone
{
    fn clone_box(&self) -> Box<ParseBlock> {
        Box::new(self.clone())
    }
}

impl Clone for Box<ParseBlock> {
    fn clone(&self) -> Box<ParseBlock> {
        self.clone_box()
    }
}

pub type FnParseBlock = fn(&str, &[Token], &[Element], &LiquidOptions) -> Result<Box<Renderable>>;

#[derive(Clone)]
pub struct FnBlockParser {
    pub parser: FnParseBlock,
}

impl FnBlockParser {
    pub fn new(parser: FnParseBlock) -> Self {
        Self { parser }
    }
}

impl ParseBlock for FnBlockParser {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             tokens: &[Element],
             options: &LiquidOptions)
             -> Result<Box<Renderable>> {
        (self.parser)(tag_name, arguments, tokens, options)
    }
}

/// Any object (tag/block) that can be rendered by liquid must implement this trait.
pub trait Renderable: Send + Sync {
    /// Renders the Renderable instance given a Liquid context.
    /// The Result that is returned signals if there was an error rendering,
    /// the Option<String> that is wrapped by the Result will be None if
    /// the render has run successfully but there is no content to render.
    fn render(&self, context: &mut Context) -> Result<Option<String>>;
}

pub trait TemplateRepository: Send + Sync + TemplateRepositoryClone {
    fn read_template(&self, path: &str) -> Result<String>;
}

pub trait TemplateRepositoryClone {
    fn clone_box(&self) -> Box<TemplateRepository>;
}

impl<T> TemplateRepositoryClone for T
    where T: 'static + TemplateRepository + Clone
{
    fn clone_box(&self) -> Box<TemplateRepository> {
        Box::new(self.clone())
    }
}

impl Clone for Box<TemplateRepository> {
    fn clone(&self) -> Box<TemplateRepository> {
        self.clone_box()
    }
}

/// `TemplateRepository` to load files relative to the root
#[derive(Clone)]
pub struct LocalTemplateRepository {
    root: PathBuf,
}

impl LocalTemplateRepository {
    pub fn new(root: PathBuf) -> LocalTemplateRepository {
        LocalTemplateRepository { root: root }
    }
}

impl TemplateRepository for LocalTemplateRepository {
    fn read_template(&self, relative_path: &str) -> Result<String> {
        let path = self.root.clone().join(relative_path);

        if !path.exists() {
            return Err(Error::from(&*format!("{:?} does not exist", path)));
        }
        let mut file = try!(File::open(path));

        let mut content = String::new();
        file.read_to_string(&mut content)?;
        Ok(content)
    }
}

/// Options that `liquid::parse` takes
pub struct LiquidOptions {
    /// Holds all custom block-size tags
    pub blocks: HashMap<String, Box<ParseBlock>>,
    /// Holds all custom tags
    pub tags: HashMap<String, Box<ParseTag>>,
    /// The path to which paths in include tags should be relative to
    pub template_repository: Box<TemplateRepository>,
}

impl Default for LiquidOptions {
    fn default() -> LiquidOptions {
        LiquidOptions {
            blocks: Default::default(),
            tags: Default::default(),
            template_repository: Box::new(LocalTemplateRepository { root: PathBuf::new() }),
        }
    }
}

impl LiquidOptions {
    /// Creates a LiquidOptions instance, pre-seeded with all known
    /// tags and blocks.
    pub fn with_known_blocks() -> LiquidOptions {
        let mut options = LiquidOptions::default();
        options.register_known_blocks();
        options
    }

    /// Registers all known tags and blocks in an existing options
    /// struct
    pub fn register_known_blocks(&mut self) {
        self.register_tag("assign", Box::new(FnTagParser::new(assign_tag)));
        self.register_tag("break", Box::new(FnTagParser::new(break_tag)));
        self.register_tag("continue", Box::new(FnTagParser::new(continue_tag)));
        self.register_tag("cycle", Box::new(FnTagParser::new(cycle_tag)));
        self.register_tag("include", Box::new(FnTagParser::new(include_tag)));

        self.register_block("raw", Box::new(FnBlockParser::new(raw_block)));
        self.register_block("if", Box::new(FnBlockParser::new(if_block)));
        self.register_block("unless", Box::new(FnBlockParser::new(unless_block)));
        self.register_block("for", Box::new(FnBlockParser::new(for_block)));
        self.register_block("comment", Box::new(FnBlockParser::new(comment_block)));
        self.register_block("capture", Box::new(FnBlockParser::new(capture_block)));
        self.register_block("case", Box::new(FnBlockParser::new(case_block)));
    }

    /// Inserts a new custom block into the options object
    pub fn register_block(&mut self, name: &str, block: Box<ParseBlock>) {
        self.blocks.insert(name.to_owned(), block);
    }

    /// Inserts a new custom tag into the options object
    pub fn register_tag(&mut self, name: &str, tag: Box<ParseTag>) {
        self.tags.insert(name.to_owned(), tag);
    }
}

/// Parses a liquid template, returning a Template object.
/// # Examples
///
/// ## Minimal Template
///
/// ```
/// use liquid::{Renderable, LiquidOptions, Context};
///
/// let template = liquid::parse("Liquid!", LiquidOptions::default()).unwrap();
/// let mut data = Context::new();
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Liquid!".to_owned()));
/// ```
///
pub fn parse(text: &str, options: LiquidOptions) -> Result<Template> {
    let mut options = options;
    options.register_known_blocks();

    let tokens = try!(lexer::tokenize(text));
    parser::parse(&tokens, &options).map(Template::new)
}

/// Parse a liquid template from a file, returning a `Result<Template, Error>`.
/// # Examples
///
/// ## Minimal Template
///
/// `template.txt`:
///
/// ```text
/// "Liquid {{data}}"
/// ```
///
/// Your rust code:
///
/// ```rust,no_run
/// use liquid::{Renderable, LiquidOptions, Context, Value};
///
/// let template = liquid::parse_file("path/to/template.txt",
///                                   LiquidOptions::default()).unwrap();
/// let mut data = Context::new();
/// data.set_val("data", Value::Num(4f32));
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Liquid 4\n".to_string()));
/// ```
///
pub fn parse_file<P: AsRef<Path>>(fp: P, options: LiquidOptions) -> Result<Template> {
    let mut options = options;
    options.register_known_blocks();

    let mut f = try!(File::open(fp));
    let mut buf = String::new();
    try!(f.read_to_string(&mut buf));

    let tokens = try!(lexer::tokenize(&buf));
    parser::parse(&tokens, &options).map(Template::new)
}
<commit_msg>feat: Make LiquidOptions cloneable<commit_after>//! The Liquid templating language for Rust
//!
//! __http://liquidmarkup.org/__
//!
//! ```toml
//! [dependencies]
//! liquid = "0.9"
//! ```
//!
//! ## Example
//! ```rust
//! use liquid::{Renderable, Context, Value};
//!
//! let template = liquid::parse("Liquid! {{num | minus: 2}}", Default::default()).unwrap();
//!
//! let mut context = Context::new();
//! context.set_val("num", Value::Num(4f32));
//!
//! let output = template.render(&mut context);
//! assert_eq!(output.unwrap(), Some("Liquid! 2".to_string()));
//! ```
#![crate_name = "liquid"]
#![doc(html_root_url = "https://cobalt-org.github.io/liquid-rust/")]

// Deny warnings, except in dev mode
#![deny(warnings)]
// #![deny(missing_docs)]
#![cfg_attr(feature="dev", warn(warnings))]

// Allow zero pointers for lazy_static. Otherwise clippy will complain.
#![allow(unknown_lints)]
#![allow(zero_ptr)]

extern crate regex;
extern crate chrono;
extern crate unicode_segmentation;
extern crate itertools;
extern crate url;

#[macro_use]
extern crate lazy_static;
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;

use std::collections::HashMap;
use lexer::Element;
use tags::{assign_tag, cycle_tag, include_tag, break_tag, continue_tag, comment_block, raw_block,
           for_block, if_block, unless_block, capture_block, case_block};
use std::default::Default;
use std::fs::File;
use std::io::prelude::Read;
use std::path::{PathBuf, Path};
use error::Result;

pub use value::Value;
pub use value::Object;
pub use value::Array;
pub use context::Context;
pub use template::Template;
pub use error::Error;
pub use filters::FilterError;
pub use token::Token;

pub mod lexer;
pub mod parser;

mod token;
mod error;
mod template;
mod output;
mod text;
mod tags;
mod filters;
mod value;
mod variable;
mod context;
mod path;

/// A trait for creating custom tags. This is a simple type alias for a function.
///
/// This function will be called whenever the parser encounters a tag and returns
/// a new [Renderable](trait.Renderable.html) based on its parameters. The received parameters
/// specify the name of the tag, the argument [Tokens](lexer/enum.Token.html) passed to
/// the tag and the global [`LiquidOptions`](struct.LiquidOptions.html).
///
/// ## Minimal Example
/// ```
/// # use liquid::{Renderable, LiquidOptions, Context, Error, FnTagParser};
///
/// struct HelloWorld;
///
/// impl Renderable for HelloWorld {
///     fn render(&self, _context: &mut Context) -> Result<Option<String>, Error>{
///         Ok(Some("Hello World!".to_owned()))
///     }
/// }
///
/// let mut options : LiquidOptions = Default::default();
/// options.tags.insert(
///     "hello_world".to_owned(),
///     Box::new(FnTagParser::new(|_tag_name, _arguments, _options| {
///         Ok(Box::new(HelloWorld))
///     })),
/// );
///
/// let template = liquid::parse("{{hello_world}}", options).unwrap();
/// let mut data = Context::new();
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Hello World!".to_owned()));
/// ```
pub trait ParseTag: Send + Sync + ParseTagClone {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             options: &LiquidOptions)
             -> Result<Box<Renderable>>;
}

pub trait ParseTagClone {
    fn clone_box(&self) -> Box<ParseTag>;
}

impl<T> ParseTagClone for T
    where T: 'static + ParseTag + Clone
{
    fn clone_box(&self) -> Box<ParseTag> {
        Box::new(self.clone())
    }
}

impl Clone for Box<ParseTag> {
    fn clone(&self) -> Box<ParseTag> {
        self.clone_box()
    }
}

pub type FnParseTag = fn(&str, &[Token], &LiquidOptions) -> Result<Box<Renderable>>;

#[derive(Clone)]
pub struct FnTagParser {
    pub parser: FnParseTag,
}

impl FnTagParser {
    pub fn new(parser: FnParseTag) -> Self {
        Self { parser }
    }
}

impl ParseTag for FnTagParser {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             options: &LiquidOptions)
             -> Result<Box<Renderable>> {
        (self.parser)(tag_name, arguments, options)
    }
}

/// A trait for creating custom custom block-size tags (`{% if something %}{% endif %}`).
/// This is a simple type alias for a function.
///
/// This function will be called whenever the parser encounters a block and returns
/// a new `Renderable` based on its parameters. The received parameters specify the name
/// of the block, the argument [Tokens](lexer/enum.Token.html) passed to
/// the block, a Vec of all [Elements](lexer/enum.Element.html) inside the block and
/// the global [`LiquidOptions`](struct.LiquidOptions.html).
pub trait ParseBlock: Send + Sync + ParseBlockClone {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             tokens: &[Element],
             options: &LiquidOptions)
             -> Result<Box<Renderable>>;
}

pub trait ParseBlockClone {
    fn clone_box(&self) -> Box<ParseBlock>;
}

impl<T> ParseBlockClone for T
    where T: 'static + ParseBlock + Clone
{
    fn clone_box(&self) -> Box<ParseBlock> {
        Box::new(self.clone())
    }
}

impl Clone for Box<ParseBlock> {
    fn clone(&self) -> Box<ParseBlock> {
        self.clone_box()
    }
}

pub type FnParseBlock = fn(&str, &[Token], &[Element], &LiquidOptions) -> Result<Box<Renderable>>;

#[derive(Clone)]
pub struct FnBlockParser {
    pub parser: FnParseBlock,
}

impl FnBlockParser {
    pub fn new(parser: FnParseBlock) -> Self {
        Self { parser }
    }
}

impl ParseBlock for FnBlockParser {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             tokens: &[Element],
             options: &LiquidOptions)
             -> Result<Box<Renderable>> {
        (self.parser)(tag_name, arguments, tokens, options)
    }
}

/// Any object (tag/block) that can be rendered by liquid must implement this trait.
pub trait Renderable: Send + Sync {
    /// Renders the Renderable instance given a Liquid context.
    /// The Result that is returned signals if there was an error rendering,
    /// the Option<String> that is wrapped by the Result will be None if
    /// the render has run successfully but there is no content to render.
    fn render(&self, context: &mut Context) -> Result<Option<String>>;
}

pub trait TemplateRepository: Send + Sync + TemplateRepositoryClone {
    fn read_template(&self, path: &str) -> Result<String>;
}

pub trait TemplateRepositoryClone {
    fn clone_box(&self) -> Box<TemplateRepository>;
}

impl<T> TemplateRepositoryClone for T
    where T: 'static + TemplateRepository + Clone
{
    fn clone_box(&self) -> Box<TemplateRepository> {
        Box::new(self.clone())
    }
}

impl Clone for Box<TemplateRepository> {
    fn clone(&self) -> Box<TemplateRepository> {
        self.clone_box()
    }
}

/// `TemplateRepository` to load files relative to the root
#[derive(Clone)]
pub struct LocalTemplateRepository {
    root: PathBuf,
}

impl LocalTemplateRepository {
    pub fn new(root: PathBuf) -> LocalTemplateRepository {
        LocalTemplateRepository { root: root }
    }
}

impl TemplateRepository for LocalTemplateRepository {
    fn read_template(&self, relative_path: &str) -> Result<String> {
        let path = self.root.clone().join(relative_path);

        if !path.exists() {
            return Err(Error::from(&*format!("{:?} does not exist", path)));
        }
        let mut file = try!(File::open(path));

        let mut content = String::new();
        file.read_to_string(&mut content)?;
        Ok(content)
    }
}

/// Options that `liquid::parse` takes
#[derive(Clone)]
pub struct LiquidOptions {
    /// Holds all custom block-size tags
    pub blocks: HashMap<String, Box<ParseBlock>>,
    /// Holds all custom tags
    pub tags: HashMap<String, Box<ParseTag>>,
    /// The path to which paths in include tags should be relative to
    pub template_repository: Box<TemplateRepository>,
}

impl Default for LiquidOptions {
    fn default() -> LiquidOptions {
        LiquidOptions {
            blocks: Default::default(),
            tags: Default::default(),
            template_repository: Box::new(LocalTemplateRepository { root: PathBuf::new() }),
        }
    }
}

impl LiquidOptions {
    /// Creates a LiquidOptions instance, pre-seeded with all known
    /// tags and blocks.
    pub fn with_known_blocks() -> LiquidOptions {
        let mut options = LiquidOptions::default();
        options.register_known_blocks();
        options
    }

    /// Registers all known tags and blocks in an existing options
    /// struct
    pub fn register_known_blocks(&mut self) {
        self.register_tag("assign", Box::new(FnTagParser::new(assign_tag)));
        self.register_tag("break", Box::new(FnTagParser::new(break_tag)));
        self.register_tag("continue", Box::new(FnTagParser::new(continue_tag)));
        self.register_tag("cycle", Box::new(FnTagParser::new(cycle_tag)));
        self.register_tag("include", Box::new(FnTagParser::new(include_tag)));

        self.register_block("raw", Box::new(FnBlockParser::new(raw_block)));
        self.register_block("if", Box::new(FnBlockParser::new(if_block)));
        self.register_block("unless", Box::new(FnBlockParser::new(unless_block)));
        self.register_block("for", Box::new(FnBlockParser::new(for_block)));
        self.register_block("comment", Box::new(FnBlockParser::new(comment_block)));
        self.register_block("capture", Box::new(FnBlockParser::new(capture_block)));
        self.register_block("case", Box::new(FnBlockParser::new(case_block)));
    }

    /// Inserts a new custom block into the options object
    pub fn register_block(&mut self, name: &str, block: Box<ParseBlock>) {
        self.blocks.insert(name.to_owned(), block);
    }

    /// Inserts a new custom tag into the options object
    pub fn register_tag(&mut self, name: &str, tag: Box<ParseTag>) {
        self.tags.insert(name.to_owned(), tag);
    }
}

/// Parses a liquid template, returning a Template object.
/// # Examples
///
/// ## Minimal Template
///
/// ```
/// use liquid::{Renderable, LiquidOptions, Context};
///
/// let template = liquid::parse("Liquid!", LiquidOptions::default()).unwrap();
/// let mut data = Context::new();
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Liquid!".to_owned()));
/// ```
///
pub fn parse(text: &str, options: LiquidOptions) -> Result<Template> {
    let mut options = options;
    options.register_known_blocks();

    let tokens = try!(lexer::tokenize(text));
    parser::parse(&tokens, &options).map(Template::new)
}

/// Parse a liquid template from a file, returning a `Result<Template, Error>`.
/// # Examples
///
/// ## Minimal Template
///
/// `template.txt`:
///
/// ```text
/// "Liquid {{data}}"
/// ```
///
/// Your rust code:
///
/// ```rust,no_run
/// use liquid::{Renderable, LiquidOptions, Context, Value};
///
/// let template = liquid::parse_file("path/to/template.txt",
///                                   LiquidOptions::default()).unwrap();
/// let mut data = Context::new();
/// data.set_val("data", Value::Num(4f32));
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Liquid 4\n".to_string()));
/// ```
///
pub fn parse_file<P: AsRef<Path>>(fp: P, options: LiquidOptions) -> Result<Template> {
    let mut options = options;
    options.register_known_blocks();

    let mut f = try!(File::open(fp));
    let mut buf = String::new();
    try!(f.read_to_string(&mut buf));

    let tokens = try!(lexer::tokenize(&buf));
    parser::parse(&tokens, &options).map(Template::new)
}
<|endoftext|>