<commit_before>extern crate json_schema;
extern crate serde_json;

#[macro_use]
extern crate quote;

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

use serde_json::Value;

use json_schema::{Schema, Type};

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, Debug, PartialEq)]
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 = 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().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.allOf.first() {
            Some(result) => {
                schema.allOf
                    .iter()
                    .skip(1)
                    .fold(Cow::Borrowed(result), |mut result, def| {
                        merge(result.to_mut(), &self.schema(def));
                        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.anyOf.len() == 2 {
            let simple = self.schema(&typ.anyOf[0]);
            let array = self.schema(&typ.anyOf[1]);
            match array.items {
                Some(ref item_schema) => {
                    if array.type_[0] == Type::Array && simple == self.schema(item_schema) {
                        self.needs_one_or_many = true;
                        return format!("OneOrMany<{}>", self.expand_type_(&typ.anyOf[0]).typ)
                            .into();
                    }
                }
                _ => (),
            }
            return "serde_json::Value".into();
        } else if typ.type_.len() == 1 {
            match typ.type_[0] {
                Type::String => {
                    if !typ.enum_.is_empty() {
                        "serde_json::Value".into()
                    } else {
                        "String".into()
                    }
                }
                Type::Integer => "i64".into(),
                Type::Boolean => "bool".into(),
                Type::Number => "f64".into(),
                Type::Object if typ.additionalProperties.is_some() => {
                    let prop = typ.additionalProperties.as_ref().unwrap();
                    let result =
                        format!("::std::collections::HashMap<String, {}>", self.expand_type_(prop).typ);
                    FieldType {
                        typ: result,
                        default: typ.default == Some(Value::Object(Default::default())),
                    }
                }
                Type::Array => {
                    let item_type =
                        typ.items.as_ref().map_or("serde_json::Value".into(),
                                                  |item_schema| self.expand_type_(item_schema));
                    format!("Vec<{}>", item_type.typ).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(Default, Deserialize, Serialize)]
                    pub struct #name {
                        #(#fields),*
                    }
                }
            } else {
                quote! {
                    #[derive(Deserialize, Serialize)]
                    pub struct #name {
                        #(#fields),*
                    }
                }
            }
        } else if !schema.enum_.is_empty() {
            let variants = schema.enum_.iter().map(|v| {
                rename_keyword("", v).unwrap_or_else(|| {
                    let v = Ident(v);
                    quote!(#v)
                })
            });
            quote! {
                #[derive(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!("../../json-schema/tests/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_: Option<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!("../../json-schema/tests/debugserver-schema.json");

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

        verify_compile("debug-server", &s)
    }
}
<commit_msg>fix: Make OneOrMany fields default<commit_after>extern crate json_schema;
extern crate serde_json;

#[macro_use]
extern crate quote;

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

use serde_json::Value;

use json_schema::{Schema, Type};

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, Debug, PartialEq)]
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 = 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().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.allOf.first() {
            Some(result) => {
                schema.allOf
                    .iter()
                    .skip(1)
                    .fold(Cow::Borrowed(result), |mut result, def| {
                        merge(result.to_mut(), &self.schema(def));
                        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.anyOf.len() == 2 {
            let simple = self.schema(&typ.anyOf[0]);
            let array = self.schema(&typ.anyOf[1]);
            match array.items {
                Some(ref item_schema) => {
                    if array.type_[0] == Type::Array && simple == self.schema(item_schema) {
                        self.needs_one_or_many = true;
                        return FieldType {
                            typ: format!("OneOrMany<{}>", self.expand_type_(&typ.anyOf[0]).typ),
                            default: true,
                        };
                    }
                }
                _ => (),
            }
            return "serde_json::Value".into();
        } else if typ.type_.len() == 1 {
            match typ.type_[0] {
                Type::String => {
                    if !typ.enum_.is_empty() {
                        "serde_json::Value".into()
                    } else {
                        "String".into()
                    }
                }
                Type::Integer => "i64".into(),
                Type::Boolean => "bool".into(),
                Type::Number => "f64".into(),
                Type::Object if typ.additionalProperties.is_some() => {
                    let prop = typ.additionalProperties.as_ref().unwrap();
                    let result =
                        format!("::std::collections::HashMap<String, {}>", self.expand_type_(prop).typ);
                    FieldType {
                        typ: result,
                        default: typ.default == Some(Value::Object(Default::default())),
                    }
                }
                Type::Array => {
                    let item_type =
                        typ.items.as_ref().map_or("serde_json::Value".into(),
                                                  |item_schema| self.expand_type_(item_schema));
                    format!("Vec<{}>", item_type.typ).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(Default, Deserialize, Serialize)]
                    pub struct #name {
                        #(#fields),*
                    }
                }
            } else {
                quote! {
                    #[derive(Deserialize, Serialize)]
                    pub struct #name {
                        #(#fields),*
                    }
                }
            }
        } else if !schema.enum_.is_empty() {
            let variants = schema.enum_.iter().map(|v| {
                rename_keyword("", v).unwrap_or_else(|| {
                    let v = Ident(v);
                    quote!(#v)
                })
            });
            quote! {
                #[derive(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!("../../json-schema/tests/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!("../../json-schema/tests/debugserver-schema.json");

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

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


<commit_before>extern crate bit_vec;
extern crate rand;

mod bloomfilter;
mod countminsketch;
mod hyperloglog;
mod reservoirsampling;
mod utils;

pub use bloomfilter::BloomFilter;
pub use countminsketch::{CountMinSketch, Counter};
pub use hyperloglog::HyperLogLog;
pub use reservoirsampling::ReservoirSampling;
pub use utils::MyBuildHasherDefault;
<commit_msg>reservoirsampling: deny missing docs<commit_after>//! A collection of data structures that are based probability theory and therefore only provide
//! the correct answer if a certain probability. In exchange they have a better runtime and memory
//! complexity compared to traditional data structures.

#![deny(missing_docs)]

extern crate bit_vec;
extern crate rand;

mod bloomfilter;
mod countminsketch;
mod hyperloglog;
mod reservoirsampling;
mod utils;

pub use bloomfilter::BloomFilter;
pub use countminsketch::{CountMinSketch, Counter};
pub use hyperloglog::HyperLogLog;
pub use reservoirsampling::ReservoirSampling;
pub use utils::MyBuildHasherDefault;
<|endoftext|>


<commit_before>extern crate chrono;

use chrono::*;

#[test]
fn hours_served__rounds_up() {
    assert_eq!(hours_served(NaiveTime::from_hms(18, 30, 0), NaiveTime::from_hms(19, 29, 0)), Ok(1));
}
<commit_msg>hours_served_rounds_up() test initial pass<commit_after>extern crate chrono;

use std::io;

use chrono::*;

//// Returns Rust [Result](http://rustbyexample.com/std/result.html)
//// representing the total hours that the baby sitter will get credit for.
fn hours_served(_from: NaiveTime, _to: NaiveTime) -> Result<i32, io::Error> {
    let r: i32 = 1;
    Ok(r)
}

#[test]
fn hours_served__rounds_up() {

    let x: Result<i32, io::Error> = hours_served(NaiveTime::from_hms(18, 30, 0), NaiveTime::from_hms(19, 29, 0));
    assert_eq!(x.unwrap(), 1);
}
<|endoftext|>


<commit_before>extern crate chrono;
extern crate copy_dir;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate log;
extern crate regex;
#[macro_use]
extern crate serde_derive;
extern crate shlex;
extern crate tempdir;

#[cfg(test)]
extern crate toml;

pub mod errors;
mod config;
#[macro_use]
pub mod helpers;

use std::path::Path;
use std::fs::{self, File};
use std::io::Write;
use tempdir::TempDir;
use regex::Regex;
use chrono::Local;

use errors::*;
pub use config::Config;

const RUST_GITHUB_REPO: &'static str = "https://github.com/rust-lang/rust";

/// The main entrypoint of the program.
///
/// This will:
///
/// 1. Update the rust repo to the latest version
/// 2. Tell rustbuild to build the docs by tweaking its `config.toml`
/// 3. Iterate through each crate in `src/` and build its docs with
///    `./x.py doc src/libfoo`
/// 4. Upload the generated documentation to github pages if there were
///    no errors or if `config.error_handling.upload_with_errors` is set.
pub fn run(cfg: Config) -> Result<()> {
    info!("Starting documentation generation");

    if !cfg.stages.skip_git_update {
        update_rust_repo(&cfg.rust_dir).chain_err(|| "Failed to update the rust repo")?;
    }
    setup_rustbuild_config_file(&cfg.rust_dir)
        .chain_err(|| "Couldn't make sure the config.toml is set properly")?;

    let crates = find_internal_crates(&cfg.rust_dir)
        .chain_err(|| "Unable to get a list of the internal crates")?;

    let mut errors = Vec::new();

    info!("Generating documentation");
    for krate in crates {
        if let Err(e) = generate_docs(&krate, &cfg.rust_dir) {
            if cfg.error_handling.fail_fast {
                return Err(e);
            } else {
                warn!("Error generating docs for {}, {}", krate, e);
                errors.push((krate, e));
            }
        }
    }

    if !cfg.stages.skip_upload && (errors.is_empty() || cfg.error_handling.upload_with_errors) {
        upload_docs(&cfg.rust_dir, &cfg.git_repo).chain_err(|| "Uploading docs failed")?;
    }

    if errors.is_empty() {
        info!("Documentation generation completed successfully");
        Ok(())
    } else {
        info!(
            "Documentation generation completed with {} errors",
            errors.len()
        );

        debug!("Crates which errored:");
        for &(ref krate, _) in &errors {
            debug!("  {}", krate);
        }

        Err(ErrorKind::DocGeneration(errors).into())
    }
}

/// Generate the documentation for the specified library in a local checkout
/// of the rust repo.
fn generate_docs(name: &str, root: &Path) -> Result<()> {
    debug!("Generating docs for {}", name);
    cmd!(in root, "./x.py doc --stage 1 -v {}", name)?;

    Ok(())
}

fn upload_docs(root: &Path, git_repo: &str) -> Result<()> {
    // FIXME: should probably not hard-code this...
    let target = "x86_64-unknown-linux-gnu";

    let docs_dir = root.join("build").join(target).join("crate-docs");

    if !docs_dir.exists() {
        bail!(
            "Couldn't find {} ... were any docs even generated?",
            docs_dir.display()
        );
    }

    let temp = TempDir::new("rustc-internal-docs")?;
    cmd!("git clone {} {}", git_repo, temp.path().display())?;
    cmd!(in temp.path(), "git checkout gh-pages")?;

    debug!("Copying generated docs to {}", temp.path().display());
    helpers::recursive_copy(temp.path(), docs_dir)?;

    // Make a page to redirect people to rustc/index.html if it doesn't
    // already exist
    let index = temp.path().join("index.html");
    if !index.exists() {
        let redirect =
            r#"<meta http-equiv="refresh" content="0; URL=rustc/index.html">"#;
        File::create(index)?.write_all(redirect.as_bytes())?;
    }

    debug!("Pushing to GitHub pages");
    cmd!(in temp.path(), "git add .")?;
    cmd!(in temp.path(), r#"git commit -m "update {}""#, Local::now())?;
    cmd!(in temp.path(), "git push origin gh-pages")?;
    debug!("Docs uploaded");

    Ok(())
}

/// Do a `git clone` or `git pull` to make sure the Rust repo is up to date.
fn update_rust_repo(root: &Path) -> Result<()> {
    if !root.exists() {
        info!("Rust directory not found, cloning into {}", root.display());
        cmd!("git clone {} {}", RUST_GITHUB_REPO, root.display())?;
    } else {
        info!("Updating rust checkout");
        cmd!(in root, "git pull origin master --ff-only")?;
    }

    info!("Rust directory is up to date");
    Ok(())
}

/// Copy across the template config file from `src/bootstrap/config.toml.example`
/// if it doesn't already exist, and make sure we tell rustbuild to build *all*
/// docs.
fn setup_rustbuild_config_file(root: &Path) -> Result<()> {
    debug!("Making sure config.toml is set up correctly");

    let config_file = root.join("config.toml");
    let template = root.join("src/bootstrap/config.toml.example");

    if !config_file.exists() {
        fs::copy(template, &config_file).chain_err(
            || "Couldn't copy the template config ({})",
            template.display(),
        )?;
    }

    let mut config_contents = helpers::read_file(&config_file)?;

    let patterns = vec![
        (
            Regex::new("^#?compiler-docs .*$").unwrap(),
            "compiler-docs = true",
        ),
        (Regex::new("^#?docs .*$").unwrap(), "docs = true"),
    ];

    for (pattern, replace) in patterns {
        config_contents = pattern.replace(&config_contents, replace).into_owned();
    }

    debug!("Config file: {}", config_file.display());

    File::create(&config_file)
        .expect("Config file should already exist")
        .write_all(config_contents.as_bytes())
        .chain_err(|| "Couldn't write to config.toml")?;

    Ok(())
}

fn find_internal_crates(root: &Path) -> Result<Vec<String>> {
    debug!("Generating a list of internal crates to document");
    let output = cmd!(in root, "./x.py doc --help --verbose")?;

    let mut crates = Vec::new();

    let crate_pattern = Regex::new(r"\./x\.py doc (src/[^\s]+)").unwrap();

    for line in String::from_utf8_lossy(&output.stdout).lines() {
        if let Some(matches) = crate_pattern.captures(&line) {
            let name = &matches[1];
            trace!("Found {}", name);
            crates.push(name.to_string());
        }
    }

    Ok(crates)
}
<commit_msg>Forgot to call format!() when generating an error message<commit_after>extern crate chrono;
extern crate copy_dir;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate log;
extern crate regex;
#[macro_use]
extern crate serde_derive;
extern crate shlex;
extern crate tempdir;

#[cfg(test)]
extern crate toml;

pub mod errors;
mod config;
#[macro_use]
pub mod helpers;

use std::path::Path;
use std::fs::{self, File};
use std::io::Write;
use tempdir::TempDir;
use regex::Regex;
use chrono::Local;

use errors::*;
pub use config::Config;

const RUST_GITHUB_REPO: &'static str = "https://github.com/rust-lang/rust";

/// The main entrypoint of the program.
///
/// This will:
///
/// 1. Update the rust repo to the latest version
/// 2. Tell rustbuild to build the docs by tweaking its `config.toml`
/// 3. Iterate through each crate in `src/` and build its docs with
///    `./x.py doc src/libfoo`
/// 4. Upload the generated documentation to github pages if there were
///    no errors or if `config.error_handling.upload_with_errors` is set.
pub fn run(cfg: Config) -> Result<()> {
    info!("Starting documentation generation");

    if !cfg.stages.skip_git_update {
        update_rust_repo(&cfg.rust_dir).chain_err(|| "Failed to update the rust repo")?;
    }
    setup_rustbuild_config_file(&cfg.rust_dir)
        .chain_err(|| "Couldn't make sure the config.toml is set properly")?;

    let crates = find_internal_crates(&cfg.rust_dir)
        .chain_err(|| "Unable to get a list of the internal crates")?;

    let mut errors = Vec::new();

    info!("Generating documentation");
    for krate in crates {
        if let Err(e) = generate_docs(&krate, &cfg.rust_dir) {
            if cfg.error_handling.fail_fast {
                return Err(e);
            } else {
                warn!("Error generating docs for {}, {}", krate, e);
                errors.push((krate, e));
            }
        }
    }

    if !cfg.stages.skip_upload && (errors.is_empty() || cfg.error_handling.upload_with_errors) {
        upload_docs(&cfg.rust_dir, &cfg.git_repo).chain_err(|| "Uploading docs failed")?;
    }

    if errors.is_empty() {
        info!("Documentation generation completed successfully");
        Ok(())
    } else {
        info!(
            "Documentation generation completed with {} errors",
            errors.len()
        );

        debug!("Crates which errored:");
        for &(ref krate, _) in &errors {
            debug!("  {}", krate);
        }

        Err(ErrorKind::DocGeneration(errors).into())
    }
}

/// Generate the documentation for the specified library in a local checkout
/// of the rust repo.
fn generate_docs(name: &str, root: &Path) -> Result<()> {
    debug!("Generating docs for {}", name);
    cmd!(in root, "./x.py doc --stage 1 -v {}", name)?;

    Ok(())
}

fn upload_docs(root: &Path, git_repo: &str) -> Result<()> {
    // FIXME: should probably not hard-code this...
    let target = "x86_64-unknown-linux-gnu";

    let docs_dir = root.join("build").join(target).join("crate-docs");

    if !docs_dir.exists() {
        bail!(
            "Couldn't find {} ... were any docs even generated?",
            docs_dir.display()
        );
    }

    let temp = TempDir::new("rustc-internal-docs")?;
    cmd!("git clone {} {}", git_repo, temp.path().display())?;
    cmd!(in temp.path(), "git checkout gh-pages")?;

    debug!("Copying generated docs to {}", temp.path().display());
    helpers::recursive_copy(temp.path(), docs_dir)?;

    // Make a page to redirect people to rustc/index.html if it doesn't
    // already exist
    let index = temp.path().join("index.html");
    if !index.exists() {
        let redirect =
            r#"<meta http-equiv="refresh" content="0; URL=rustc/index.html">"#;
        File::create(index)?.write_all(redirect.as_bytes())?;
    }

    debug!("Pushing to GitHub pages");
    cmd!(in temp.path(), "git add .")?;
    cmd!(in temp.path(), r#"git commit -m "update {}""#, Local::now())?;
    cmd!(in temp.path(), "git push origin gh-pages")?;
    debug!("Docs uploaded");

    Ok(())
}

/// Do a `git clone` or `git pull` to make sure the Rust repo is up to date.
fn update_rust_repo(root: &Path) -> Result<()> {
    if !root.exists() {
        info!("Rust directory not found, cloning into {}", root.display());
        cmd!("git clone {} {}", RUST_GITHUB_REPO, root.display())?;
    } else {
        info!("Updating rust checkout");
        cmd!(in root, "git pull origin master --ff-only")?;
    }

    info!("Rust directory is up to date");
    Ok(())
}

/// Copy across the template config file from `src/bootstrap/config.toml.example`
/// if it doesn't already exist, and make sure we tell rustbuild to build *all*
/// docs.
fn setup_rustbuild_config_file(root: &Path) -> Result<()> {
    debug!("Making sure config.toml is set up correctly");

    let config_file = root.join("config.toml");
    let template = root.join("src/bootstrap/config.toml.example");

    if !config_file.exists() {
        fs::copy(&template, &config_file).chain_err(|| {
            format!("Couldn't copy the template config ({})", template.display())
        })?;
    }

    let mut config_contents = helpers::read_file(&config_file)?;

    let patterns = vec![
        (
            Regex::new("^#?compiler-docs .*$").unwrap(),
            "compiler-docs = true",
        ),
        (Regex::new("^#?docs .*$").unwrap(), "docs = true"),
    ];

    for (pattern, replace) in patterns {
        config_contents = pattern.replace(&config_contents, replace).into_owned();
    }

    debug!("Config file: {}", config_file.display());

    File::create(&config_file)
        .expect("Config file should already exist")
        .write_all(config_contents.as_bytes())
        .chain_err(|| "Couldn't write to config.toml")?;

    Ok(())
}

fn find_internal_crates(root: &Path) -> Result<Vec<String>> {
    debug!("Generating a list of internal crates to document");
    let output = cmd!(in root, "./x.py doc --help --verbose")?;

    let mut crates = Vec::new();

    let crate_pattern = Regex::new(r"\./x\.py doc (src/[^\s]+)").unwrap();

    for line in String::from_utf8_lossy(&output.stdout).lines() {
        if let Some(matches) = crate_pattern.captures(&line) {
            let name = &matches[1];
            trace!("Found {}", name);
            crates.push(name.to_string());
        }
    }

    Ok(crates)
}
<|endoftext|>


<commit_before>//! count occurrences of a given byte, or the number of UTF-8 code points, in a
//! byte slice, fast.
//!
//! This crate has the [`count`](fn.count.html) method to count byte
//! occurrences (for example newlines) in a larger `&[u8]` slice.
//!
//! For example:
//!
//! ```rust
//! assert_eq!(5, bytecount::count(b"Hello, this is the bytecount crate!", b' '));
//! ```
//!
//! Also there is a [`num_chars`](fn.num_chars.html) method to count
//! the number of UTF8 characters in a slice. It will work the same as
//! `str::chars().count()` for byte slices of correct UTF-8 character
//! sequences. The result will likely be off for invalid sequences,
//! although the result is guaranteed to be between `0` and
//! `[_]::len()`, inclusive.
//!
//! Example:
//!
//! ```rust
//!# use bytecount::num_chars;
//! let sequence = "Wenn ich ein Vöglein wär, flög ich zu Dir!";
//! assert_eq!(sequence.chars().count(),
//!            bytecount::num_chars(&sequence.bytes().collect::<Vec<u8>>()));
//! ```
//!
//! For completeness and easy comparison, the "naive" versions of both
//! count and num_chars are provided. Those are also faster if used on
//! predominantly small strings. The
//! [`naive_count_32`](fn.naive_count_32.html) method can be faster
//! still on small strings.

#![no_std]

#![deny(missing_docs)]

#[cfg(feature = "simd-accel")]
extern crate simd;

use core::{cmp, mem, slice, usize};

#[cfg(feature = "simd-accel")]
use simd::u8x16;
#[cfg(feature = "avx-accel")]
use simd::x86::sse2::Sse2U8x16;
#[cfg(feature = "avx-accel")]
use simd::x86::avx::{LowHigh128, u8x32};

trait ByteChunk: Copy {
    type Splat: Copy;
    fn splat(byte: u8) -> Self::Splat;
    fn from_splat(splat: Self::Splat) -> Self;
    fn bytewise_equal(self, other: Self::Splat) -> Self;
    fn is_leading_utf8_byte(self) -> Self;
    fn increment(self, incr: Self) -> Self;
    fn sum(&self) -> usize;
}

impl ByteChunk for usize {
    type Splat = Self;

    fn splat(byte: u8) -> Self {
        let lo = usize::MAX / 0xFF;
        lo * byte as usize
    }

    fn from_splat(splat: Self) -> Self {
        splat
    }

    fn is_leading_utf8_byte(self) -> Self {
        // a leading UTF-8 byte is one which does not start with the bits 10.
        ((!self >> 7) | (self >> 6)) & Self::splat(1)
    }

    fn bytewise_equal(self, other: Self) -> Self {
        let lo = usize::MAX / 0xFF;
        let hi = lo << 7;

        let x = self ^ other;
        !((((x & !hi) + !hi) | x) >> 7) & lo
    }

    fn increment(self, incr: Self) -> Self {
        self + incr
    }

    fn sum(&self) -> usize {
        let every_other_byte_lo = usize::MAX / 0xFFFF;
        let every_other_byte = every_other_byte_lo * 0xFF;

        // Pairwise reduction to avoid overflow on next step.
        let pair_sum: usize = (self & every_other_byte) + ((self >> 8) & every_other_byte);

        // Multiplication results in top two bytes holding sum.
        pair_sum.wrapping_mul(every_other_byte_lo) >> ((mem::size_of::<usize>() - 2) * 8)
    }
}

#[cfg(feature = "simd-accel")]
impl ByteChunk for u8x16 {
    type Splat = Self;

    fn splat(byte: u8) -> Self {
        Self::splat(byte)
    }

    fn from_splat(splat: Self) -> Self {
        splat
    }

    fn is_leading_utf8_byte(self) -> Self {
        (self & Self::splat(0b1100_0000)).ne(Self::splat(0b1000_0000)).to_repr().to_u8()
    }

    fn bytewise_equal(self, other: Self) -> Self {
        self.eq(other).to_repr().to_u8()
    }

    fn increment(self, incr: Self) -> Self {
        // incr on -1
        self - incr
    }

    fn sum(&self) -> usize {
        let mut count = 0;
        for i in 0..16 {
            count += self.extract(i) as usize;
        }
        count
    }
}

#[cfg(feature = "avx-accel")]
impl ByteChunk for u8x32 {
    type Splat = Self;

    fn splat(byte: u8) -> Self {
        Self::splat(byte)
    }

    fn from_splat(splat: Self) -> Self {
        splat
    }

    fn is_leading_utf8_byte(self) -> Self {
        (self & Self::splat(0b1100_0000)).ne(Self::splat(0b1000_0000)).to_repr().to_u8()
    }

    fn bytewise_equal(self, other: Self) -> Self {
        self.eq(other).to_repr().to_u8()
    }

    fn increment(self, incr: Self) -> Self {
        // incr on -1
        self - incr
    }

    fn sum(&self) -> usize {
        let zero = u8x16::splat(0);
        let sad_lo = self.low().sad(zero);
        let sad_hi = self.high().sad(zero);

        let mut count = 0;
        count += (sad_lo.extract(0) + sad_lo.extract(1)) as usize;
        count += (sad_hi.extract(0) + sad_hi.extract(1)) as usize;
        count
    }
}

fn chunk_align<Chunk: ByteChunk>(x: &[u8]) -> (&[u8], &[Chunk], &[u8]) {
    let align = mem::size_of::<Chunk>();

    let offset_ptr = (x.as_ptr() as usize) % align;
    let offset_end = (x.as_ptr() as usize + x.len()) % align;

    let d2 = x.len().saturating_sub(offset_end);
    let d1 = cmp::min((align - offset_ptr) % align, d2);

    let (init, tail) = x.split_at(d2);
    let (init, mid) = init.split_at(d1);
    assert_eq!(mid.len() % align, 0);
    let mid = unsafe { slice::from_raw_parts(mid.as_ptr() as *const Chunk, mid.len() / align) };

    (init, mid, tail)
}

fn chunk_count<Chunk: ByteChunk>(haystack: &[Chunk], needle: u8) -> usize {
    let zero = Chunk::splat(0);
    let needles = Chunk::splat(needle);
    let mut count = 0;
    let mut i = 0;

    while i < haystack.len() {
        let mut counts = Chunk::from_splat(zero);

        let end = cmp::min(i + 255, haystack.len());
        for &chunk in &haystack[i..end] {
            counts = counts.increment(chunk.bytewise_equal(needles));
        }
        i = end;

        count += counts.sum();
    }

    count
}

fn count_generic<Chunk: ByteChunk<Splat = Chunk>>(naive_below: usize, haystack: &[u8], needle: u8) -> usize {
    let mut count = 0;

    // Extract pre/post so naive_count is only inlined once.
    let len = haystack.len();
    let unchunked = if len < naive_below {
        [haystack, &haystack[0..0]]
    } else {
        let (pre, mid, post) = chunk_align::<Chunk>(haystack);
        count += chunk_count(mid, needle);
        [pre, post]
    };

    for &slice in &unchunked {
        count += naive_count(slice, needle);
    }

    count
}

/// Count occurrences of a byte in a slice of bytes, fast
///
/// # Examples
///
/// ```
/// let s = b"This is a Text with spaces";
/// let number_of_spaces = bytecount::count(s, b' ');
/// assert_eq!(number_of_spaces, 5);
/// ```
#[cfg(not(feature = "simd-accel"))]
pub fn count(haystack: &[u8], needle: u8) -> usize {
    count_generic::<usize>(32, haystack, needle)
}

/// Count occurrences of a byte in a slice of bytes, fast
///
/// # Examples
///
/// ```
/// let s = b"This is a Text with spaces";
/// let number_of_spaces = bytecount::count(s, b' ');
/// assert_eq!(number_of_spaces, 5);
/// ```
#[cfg(all(feature = "simd-accel", not(feature = "avx-accel")))]
pub fn count(haystack: &[u8], needle: u8) -> usize {
    count_generic::<u8x16>(32, haystack, needle)
}

/// Count occurrences of a byte in a slice of bytes, fast
///
/// # Examples
///
/// ```
/// let s = b"This is a Text with spaces";
/// let number_of_spaces = bytecount::count(s, b' ');
/// assert_eq!(number_of_spaces, 5);
/// ```
#[cfg(feature = "avx-accel")]
pub fn count(haystack: &[u8], needle: u8) -> usize {
    count_generic::<u8x32>(64, haystack, needle)
}

/// Count up to `(2^32)-1` occurrences of a byte in a slice
/// of bytes, simple
///
/// # Example
///
/// ```
/// let s = b"This is yet another Text with spaces";
/// let number_of_spaces = bytecount::naive_count_32(s, b' ');
/// assert_eq!(number_of_spaces, 6);
/// ```
pub fn naive_count_32(haystack: &[u8], needle: u8) -> usize {
    haystack.iter().fold(0, |n, c| n + (*c == needle) as u32) as usize
}

/// Count occurrences of a byte in a slice of bytes, simple
///
/// # Example
///
/// ```
/// let s = b"This is yet another Text with spaces";
/// let number_of_spaces = bytecount::naive_count(s, b' ');
/// assert_eq!(number_of_spaces, 6);
/// ```
pub fn naive_count(haystack: &[u8], needle: u8) -> usize {
    haystack.iter().fold(0, |n, c| n + (*c == needle) as usize)
}

fn chunk_num_chars<Chunk: ByteChunk>(haystack: &[Chunk]) -> usize {
    let zero = Chunk::splat(0);
    let mut count = 0;
    let mut i = 0;
    while i < haystack.len() {
        let mut counts = Chunk::from_splat(zero);
        let end = cmp::min(i + 255, haystack.len());
        for &chunk in &haystack[i..end] {
            counts = counts.increment(chunk.is_leading_utf8_byte());
        }
        i = end;
        count += counts.sum();
    }
    count
}

fn num_chars_generic<Chunk: ByteChunk<Splat = Chunk>>(naive_below: usize, haystack: &[u8]) -> usize {
    // Extract pre/post so naive_count is only inlined once.
    let len = haystack.len();
    let mut count = 0;
    let unchunked = if len < naive_below {
        [haystack, &haystack[0..0]]
    } else {
        let (pre, mid, post) = chunk_align::<Chunk>(haystack);
        count += chunk_num_chars(mid);
        [pre, post]
    };
    for &slice in &unchunked {
        count += naive_num_chars(slice);
    }
    count
}

/// Count the number of UTF-8 encoded unicode codepoints in a slice of bytes, fast
///
/// This function is safe to use on any byte array, valid UTF-8 or not,
/// but the output is only meaningful for well-formed UTF-8.
///
/// # Example
///
/// ```
/// let swordfish = "メカジキ";
/// let char_count = bytecount::num_chars(swordfish.as_bytes());
/// assert_eq!(char_count, 4);
/// ```
#[cfg(not(feature = "simd-accel"))]
pub fn num_chars(haystack: &[u8]) -> usize {
    // Never use [usize; 4]
    num_chars_generic::<usize>(32, haystack)
}

/// Count the number of UTF-8 encoded unicode codepoints in a slice of bytes, fast
///
/// This function is safe to use on any byte array, valid UTF-8 or not,
/// but the output is only meaningful for well-formed UTF-8.
///
/// # Example
///
/// ```
/// let swordfish = "メカジキ";
/// let char_count = bytecount::num_chars(swordfish.as_bytes());
/// assert_eq!(char_count, 4);
/// ```
#[cfg(all(feature = "simd-accel", not(feature = "avx-accel")))]
pub fn num_chars(haystack: &[u8]) -> usize {
    num_chars_generic::<u8x16>(32, haystack)
}

/// Count the number of UTF-8 encoded unicode codepoints in a slice of bytes, fast
///
/// This function is safe to use on any byte array, valid UTF-8 or not,
/// but the output is only meaningful for well-formed UTF-8.
///
/// # Example
///
/// ```
/// let swordfish = "メカジキ";
/// let char_count = bytecount::num_chars(swordfish.as_bytes());
/// assert_eq!(char_count, 4);
/// ```
#[cfg(feature = "avx-accel")]
pub fn num_chars(haystack: &[u8]) -> usize {
    num_chars_generic::<u8x32>(64, haystack)
}

/// Count the number of UTF-8 encoded unicode codepoints in a slice of bytes, simple
///
/// This function is safe to use on any byte array, valid UTF-8 or not,
/// but the output is only meaningful for well-formed UTF-8.
///
/// # Example
///
/// ```
/// let swordfish = "メカジキ";
/// let char_count = bytecount::naive_num_chars(swordfish.as_bytes());
/// assert_eq!(char_count, 4);
/// ```
pub fn naive_num_chars(haystack: &[u8]) -> usize {
    haystack.iter().filter(|&&byte| (byte >> 6) != 0b10).count()
}
<commit_msg>Make sure we do not create an unaligned slice<commit_after>//! count occurrences of a given byte, or the number of UTF-8 code points, in a
//! byte slice, fast.
//!
//! This crate has the [`count`](fn.count.html) method to count byte
//! occurrences (for example newlines) in a larger `&[u8]` slice.
//!
//! For example:
//!
//! ```rust
//! assert_eq!(5, bytecount::count(b"Hello, this is the bytecount crate!", b' '));
//! ```
//!
//! Also there is a [`num_chars`](fn.num_chars.html) method to count
//! the number of UTF8 characters in a slice. It will work the same as
//! `str::chars().count()` for byte slices of correct UTF-8 character
//! sequences. The result will likely be off for invalid sequences,
//! although the result is guaranteed to be between `0` and
//! `[_]::len()`, inclusive.
//!
//! Example:
//!
//! ```rust
//!# use bytecount::num_chars;
//! let sequence = "Wenn ich ein Vöglein wär, flög ich zu Dir!";
//! assert_eq!(sequence.chars().count(),
//!            bytecount::num_chars(&sequence.bytes().collect::<Vec<u8>>()));
//! ```
//!
//! For completeness and easy comparison, the "naive" versions of both
//! count and num_chars are provided. Those are also faster if used on
//! predominantly small strings. The
//! [`naive_count_32`](fn.naive_count_32.html) method can be faster
//! still on small strings.

#![no_std]

#![deny(missing_docs)]

#[cfg(feature = "simd-accel")]
extern crate simd;

use core::{cmp, mem, slice, usize};

#[cfg(feature = "simd-accel")]
use simd::u8x16;
#[cfg(feature = "avx-accel")]
use simd::x86::sse2::Sse2U8x16;
#[cfg(feature = "avx-accel")]
use simd::x86::avx::{LowHigh128, u8x32};

trait ByteChunk: Copy {
    type Splat: Copy;
    fn splat(byte: u8) -> Self::Splat;
    fn from_splat(splat: Self::Splat) -> Self;
    fn bytewise_equal(self, other: Self::Splat) -> Self;
    fn is_leading_utf8_byte(self) -> Self;
    fn increment(self, incr: Self) -> Self;
    fn sum(&self) -> usize;
}

impl ByteChunk for usize {
    type Splat = Self;

    fn splat(byte: u8) -> Self {
        let lo = usize::MAX / 0xFF;
        lo * byte as usize
    }

    fn from_splat(splat: Self) -> Self {
        splat
    }

    fn is_leading_utf8_byte(self) -> Self {
        // a leading UTF-8 byte is one which does not start with the bits 10.
        ((!self >> 7) | (self >> 6)) & Self::splat(1)
    }

    fn bytewise_equal(self, other: Self) -> Self {
        let lo = usize::MAX / 0xFF;
        let hi = lo << 7;

        let x = self ^ other;
        !((((x & !hi) + !hi) | x) >> 7) & lo
    }

    fn increment(self, incr: Self) -> Self {
        self + incr
    }

    fn sum(&self) -> usize {
        let every_other_byte_lo = usize::MAX / 0xFFFF;
        let every_other_byte = every_other_byte_lo * 0xFF;

        // Pairwise reduction to avoid overflow on next step.
        let pair_sum: usize = (self & every_other_byte) + ((self >> 8) & every_other_byte);

        // Multiplication results in top two bytes holding sum.
        pair_sum.wrapping_mul(every_other_byte_lo) >> ((mem::size_of::<usize>() - 2) * 8)
    }
}

#[cfg(feature = "simd-accel")]
impl ByteChunk for u8x16 {
    type Splat = Self;

    fn splat(byte: u8) -> Self {
        Self::splat(byte)
    }

    fn from_splat(splat: Self) -> Self {
        splat
    }

    fn is_leading_utf8_byte(self) -> Self {
        (self & Self::splat(0b1100_0000)).ne(Self::splat(0b1000_0000)).to_repr().to_u8()
    }

    fn bytewise_equal(self, other: Self) -> Self {
        self.eq(other).to_repr().to_u8()
    }

    fn increment(self, incr: Self) -> Self {
        // incr on -1
        self - incr
    }

    fn sum(&self) -> usize {
        let mut count = 0;
        for i in 0..16 {
            count += self.extract(i) as usize;
        }
        count
    }
}

#[cfg(feature = "avx-accel")]
impl ByteChunk for u8x32 {
    type Splat = Self;

    fn splat(byte: u8) -> Self {
        Self::splat(byte)
    }

    fn from_splat(splat: Self) -> Self {
        splat
    }

    fn is_leading_utf8_byte(self) -> Self {
        (self & Self::splat(0b1100_0000)).ne(Self::splat(0b1000_0000)).to_repr().to_u8()
    }

    fn bytewise_equal(self, other: Self) -> Self {
        self.eq(other).to_repr().to_u8()
    }

    fn increment(self, incr: Self) -> Self {
        // incr on -1
        self - incr
    }

    fn sum(&self) -> usize {
        let zero = u8x16::splat(0);
        let sad_lo = self.low().sad(zero);
        let sad_hi = self.high().sad(zero);

        let mut count = 0;
        count += (sad_lo.extract(0) + sad_lo.extract(1)) as usize;
        count += (sad_hi.extract(0) + sad_hi.extract(1)) as usize;
        count
    }
}

fn chunk_align<Chunk: ByteChunk>(x: &[u8]) -> (&[u8], &[Chunk], &[u8]) {
    let align = mem::size_of::<Chunk>();

    let offset_ptr = (x.as_ptr() as usize) % align;
    let offset_end = (x.as_ptr() as usize + x.len()) % align;

    let d1 = (align - offset_ptr) % align; // `offset_ptr` might be 0, then `d1` should be 0.
    let d2 = x.len().saturating_sub(offset_end);
    if d1 > d2 {
        // No space for anything aligned
        return (x, &[], &[]);
    }

    let (init, tail) = x.split_at(d2);
    let (init, mid) = init.split_at(d1);
    assert_eq!(mid.len() % align, 0);
    // `mid` is guaranteed to be aligned
    let mid = unsafe { slice::from_raw_parts(mid.as_ptr() as *const Chunk, mid.len() / align) };

    (init, mid, tail)
}

fn chunk_count<Chunk: ByteChunk>(haystack: &[Chunk], needle: u8) -> usize {
    let zero = Chunk::splat(0);
    let needles = Chunk::splat(needle);
    let mut count = 0;
    let mut i = 0;

    while i < haystack.len() {
        let mut counts = Chunk::from_splat(zero);

        let end = cmp::min(i + 255, haystack.len());
        for &chunk in &haystack[i..end] {
            counts = counts.increment(chunk.bytewise_equal(needles));
        }
        i = end;

        count += counts.sum();
    }

    count
}

fn count_generic<Chunk: ByteChunk<Splat = Chunk>>(naive_below: usize, haystack: &[u8], needle: u8) -> usize {
    let mut count = 0;

    // Extract pre/post so naive_count is only inlined once.
    let len = haystack.len();
    let unchunked = if len < naive_below {
        [haystack, &haystack[0..0]]
    } else {
        let (pre, mid, post) = chunk_align::<Chunk>(haystack);
        count += chunk_count(mid, needle);
        [pre, post]
    };

    for &slice in &unchunked {
        count += naive_count(slice, needle);
    }

    count
}

/// Count occurrences of a byte in a slice of bytes, fast
///
/// # Examples
///
/// ```
/// let s = b"This is a Text with spaces";
/// let number_of_spaces = bytecount::count(s, b' ');
/// assert_eq!(number_of_spaces, 5);
/// ```
#[cfg(not(feature = "simd-accel"))]
pub fn count(haystack: &[u8], needle: u8) -> usize {
    count_generic::<usize>(32, haystack, needle)
}

/// Count occurrences of a byte in a slice of bytes, fast
///
/// # Examples
///
/// ```
/// let s = b"This is a Text with spaces";
/// let number_of_spaces = bytecount::count(s, b' ');
/// assert_eq!(number_of_spaces, 5);
/// ```
#[cfg(all(feature = "simd-accel", not(feature = "avx-accel")))]
pub fn count(haystack: &[u8], needle: u8) -> usize {
    count_generic::<u8x16>(32, haystack, needle)
}

/// Count occurrences of a byte in a slice of bytes, fast
///
/// # Examples
///
/// ```
/// let s = b"This is a Text with spaces";
/// let number_of_spaces = bytecount::count(s, b' ');
/// assert_eq!(number_of_spaces, 5);
/// ```
#[cfg(feature = "avx-accel")]
pub fn count(haystack: &[u8], needle: u8) -> usize {
    count_generic::<u8x32>(64, haystack, needle)
}

/// Count up to `(2^32)-1` occurrences of a byte in a slice
/// of bytes, simple
///
/// # Example
///
/// ```
/// let s = b"This is yet another Text with spaces";
/// let number_of_spaces = bytecount::naive_count_32(s, b' ');
/// assert_eq!(number_of_spaces, 6);
/// ```
pub fn naive_count_32(haystack: &[u8], needle: u8) -> usize {
    haystack.iter().fold(0, |n, c| n + (*c == needle) as u32) as usize
}

/// Count occurrences of a byte in a slice of bytes, simple
///
/// # Example
///
/// ```
/// let s = b"This is yet another Text with spaces";
/// let number_of_spaces = bytecount::naive_count(s, b' ');
/// assert_eq!(number_of_spaces, 6);
/// ```
pub fn naive_count(haystack: &[u8], needle: u8) -> usize {
    haystack.iter().fold(0, |n, c| n + (*c == needle) as usize)
}

fn chunk_num_chars<Chunk: ByteChunk>(haystack: &[Chunk]) -> usize {
    let zero = Chunk::splat(0);
    let mut count = 0;
    let mut i = 0;
    while i < haystack.len() {
        let mut counts = Chunk::from_splat(zero);
        let end = cmp::min(i + 255, haystack.len());
        for &chunk in &haystack[i..end] {
            counts = counts.increment(chunk.is_leading_utf8_byte());
        }
        i = end;
        count += counts.sum();
    }
    count
}

fn num_chars_generic<Chunk: ByteChunk<Splat = Chunk>>(naive_below: usize, haystack: &[u8]) -> usize {
    // Extract pre/post so naive_count is only inlined once.
    let len = haystack.len();
    let mut count = 0;
    let unchunked = if len < naive_below {
        [haystack, &haystack[0..0]]
    } else {
        let (pre, mid, post) = chunk_align::<Chunk>(haystack);
        count += chunk_num_chars(mid);
        [pre, post]
    };
    for &slice in &unchunked {
        count += naive_num_chars(slice);
    }
    count
}

/// Count the number of UTF-8 encoded unicode codepoints in a slice of bytes, fast
///
/// This function is safe to use on any byte array, valid UTF-8 or not,
/// but the output is only meaningful for well-formed UTF-8.
///
/// # Example
///
/// ```
/// let swordfish = "メカジキ";
/// let char_count = bytecount::num_chars(swordfish.as_bytes());
/// assert_eq!(char_count, 4);
/// ```
#[cfg(not(feature = "simd-accel"))]
pub fn num_chars(haystack: &[u8]) -> usize {
    // Never use [usize; 4]
    num_chars_generic::<usize>(32, haystack)
}

/// Count the number of UTF-8 encoded unicode codepoints in a slice of bytes, fast
///
/// This function is safe to use on any byte array, valid UTF-8 or not,
/// but the output is only meaningful for well-formed UTF-8.
///
/// # Example
///
/// ```
/// let swordfish = "メカジキ";
/// let char_count = bytecount::num_chars(swordfish.as_bytes());
/// assert_eq!(char_count, 4);
/// ```
#[cfg(all(feature = "simd-accel", not(feature = "avx-accel")))]
pub fn num_chars(haystack: &[u8]) -> usize {
    num_chars_generic::<u8x16>(32, haystack)
}

/// Count the number of UTF-8 encoded unicode codepoints in a slice of bytes, fast
///
/// This function is safe to use on any byte array, valid UTF-8 or not,
/// but the output is only meaningful for well-formed UTF-8.
///
/// # Example
///
/// ```
/// let swordfish = "メカジキ";
/// let char_count = bytecount::num_chars(swordfish.as_bytes());
/// assert_eq!(char_count, 4);
/// ```
#[cfg(feature = "avx-accel")]
pub fn num_chars(haystack: &[u8]) -> usize {
    num_chars_generic::<u8x32>(64, haystack)
}

/// Count the number of UTF-8 encoded unicode codepoints in a slice of bytes, simple
///
/// This function is safe to use on any byte array, valid UTF-8 or not,
/// but the output is only meaningful for well-formed UTF-8.
///
/// # Example
///
/// ```
/// let swordfish = "メカジキ";
/// let char_count = bytecount::naive_num_chars(swordfish.as_bytes());
/// assert_eq!(char_count, 4);
/// ```
pub fn naive_num_chars(haystack: &[u8]) -> usize {
    haystack.iter().filter(|&&byte| (byte >> 6) != 0b10).count()
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

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

pub use self::arithmetic::{ArithmeticBase, ArithmeticExpression, ArithmeticOperator};
pub use self::common::{FieldExpression, Literal, Operator, SqlType, TableKey};
pub use self::column::{Column, ColumnConstraint, ColumnSpecification, FunctionExpression};
pub use self::condition::{ConditionBase, ConditionExpression, ConditionTree};
pub use self::create::CreateTableStatement;
pub use self::insert::InsertStatement;
pub use self::join::{JoinConstraint, JoinOperator, JoinRightSide};
pub use self::parser::*;
pub use self::compound_select::{CompoundSelectOperator, CompoundSelectStatement};
pub use self::select::{GroupByClause, JoinClause, LimitClause, OrderClause, OrderType,
                       SelectStatement};
pub use self::table::Table;

pub mod parser;

#[macro_use]
mod caseless_tag;
mod keywords;
mod arithmetic;
mod column;
mod common;
mod condition;
mod create;
mod insert;
mod join;
mod select;
mod compound_select;
mod table;
mod delete;
mod update;
mod set;
<commit_msg>Make SetStatement public<commit_after>#[macro_use]
extern crate nom;

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

pub use self::arithmetic::{ArithmeticBase, ArithmeticExpression, ArithmeticOperator};
pub use self::common::{FieldExpression, Literal, Operator, SqlType, TableKey};
pub use self::column::{Column, ColumnConstraint, ColumnSpecification, FunctionExpression};
pub use self::condition::{ConditionBase, ConditionExpression, ConditionTree};
pub use self::create::CreateTableStatement;
pub use self::insert::InsertStatement;
pub use self::join::{JoinConstraint, JoinOperator, JoinRightSide};
pub use self::parser::*;
pub use self::compound_select::{CompoundSelectOperator, CompoundSelectStatement};
pub use self::select::{GroupByClause, JoinClause, LimitClause, OrderClause, OrderType,
                       SelectStatement};
pub use self::table::Table;
pub use self::set::SetStatement;

pub mod parser;

#[macro_use]
mod caseless_tag;
mod keywords;
mod arithmetic;
mod column;
mod common;
mod condition;
mod create;
mod insert;
mod join;
mod select;
mod compound_select;
mod table;
mod delete;
mod update;
mod set;
<|endoftext|>


<commit_before>extern crate cards;

use std::cmp::{Ord};

use cards::card::{Card};

#[derive(Debug, PartialEq)]
#[derive(Eq, Hash)]
#[derive(PartialOrd, Ord)]
pub enum HandRankClass {
    HighCard,
    OnePair,
    TwoPair,
    ThreeOfAKind,
    Straight,
    Flush,
    FullHouse,
    FourOfAKind,
    StraightFlush,
}

// find maximum value to determine best hand
// larger values are "better", inverting the Cactus Kev convention
pub type HandRank = u16;

pub const HAND_RANK_COUNT : u16 = 7462;

// assumes there are HAND_RANK_COUNT distinct hand ranks, where the
// largest are the most valuable. An inversion of cactus kev's ranks.
pub fn hand_rank_to_class(val: &HandRank) -> HandRankClass {
    match *val {
        x if x < HAND_RANK_COUNT-6185 => HandRankClass::HighCard,
        x if x < HAND_RANK_COUNT-3325 => HandRankClass::OnePair,
        x if x < HAND_RANK_COUNT-2467 => HandRankClass::TwoPair,
        x if x < HAND_RANK_COUNT-1609 => HandRankClass::ThreeOfAKind,
        x if x < HAND_RANK_COUNT-1599 => HandRankClass::Straight,
        x if x < HAND_RANK_COUNT-322  => HandRankClass::Flush,
        x if x < HAND_RANK_COUNT-166  => HandRankClass::FullHouse,
        x if x < HAND_RANK_COUNT-10   => HandRankClass::FourOfAKind,
        x if x < HAND_RANK_COUNT-0    => HandRankClass::StraightFlush,
        x                             => panic!("Unexpected hand rank value! '{}'", x)
    }
}

pub enum CardSlot {
    Empty,
    Dealt(Card),
}

impl CardSlot {
    pub fn expect_borrow(&self) -> &Card {
        match self {
            &CardSlot::Empty => panic!("You are trying to borrow a non-dealt card"),
            &CardSlot::Dealt(ref x) => x
        }
    }
}

pub struct HandCards(pub CardSlot, pub CardSlot);
pub struct CommunityCards(pub CardSlot, pub CardSlot, pub CardSlot, pub CardSlot, pub CardSlot);
<commit_msg>Shot myself in the foot there, being sloppy as hell.<commit_after>extern crate cards;

use std::cmp::{Ord};

use cards::card::{Card};

#[derive(Debug, PartialEq)]
#[derive(Eq, Hash)]
#[derive(PartialOrd, Ord)]
pub enum HandRankClass {
    HighCard,
    OnePair,
    TwoPair,
    ThreeOfAKind,
    Straight,
    Flush,
    FullHouse,
    FourOfAKind,
    StraightFlush,
}

// find maximum value to determine best hand
// larger values are "better", inverting the Cactus Kev convention
pub type HandRank = u16;

pub const HAND_RANK_COUNT : u16 = 7462;

// assumes there are HAND_RANK_COUNT distinct hand ranks, where the
// largest are the most valuable. An inversion of cactus kev's ranks.
pub fn hand_rank_to_class(val: &HandRank) -> HandRankClass {
    match *val {
        x if x < HAND_RANK_COUNT-6185 => HandRankClass::HighCard,
        x if x < HAND_RANK_COUNT-3325 => HandRankClass::OnePair,
        x if x < HAND_RANK_COUNT-2467 => HandRankClass::TwoPair,
        x if x < HAND_RANK_COUNT-1609 => HandRankClass::ThreeOfAKind,
        x if x < HAND_RANK_COUNT-1599 => HandRankClass::Straight,
        x if x < HAND_RANK_COUNT-322  => HandRankClass::Flush,
        x if x < HAND_RANK_COUNT-166  => HandRankClass::FullHouse,
        x if x < HAND_RANK_COUNT-10   => HandRankClass::FourOfAKind,
        x if x <= HAND_RANK_COUNT-0    => HandRankClass::StraightFlush, //include the former zero (now HAND_RANK_COUNT)
        x                             => panic!("Unexpected hand rank value! '{}'", x)
    }
}

pub enum CardSlot {
    Empty,
    Dealt(Card),
}

impl CardSlot {
    pub fn expect_borrow(&self) -> &Card {
        match self {
            &CardSlot::Empty => panic!("You are trying to borrow a non-dealt card"),
            &CardSlot::Dealt(ref x) => x
        }
    }
}

pub struct HandCards(pub CardSlot, pub CardSlot);
pub struct CommunityCards(pub CardSlot, pub CardSlot, pub CardSlot, pub CardSlot, pub CardSlot);
<|endoftext|>


<commit_before>#![crate_name = "raft"]
#![crate_type="lib"]
#![doc(html_logo_url = "https://raw.githubusercontent.com/Hoverbear/raft/master/raft.png")]
#![doc(html_root_url = "https://hoverbear.github.io/raft/raft/")]

#![feature(convert)]

extern crate capnp;
extern crate mio;
extern crate rand;
extern crate rustc_serialize;
extern crate uuid;
#[macro_use] extern crate log;

pub mod state_machine;
pub mod store;

mod node;
mod replica;
mod state;

mod messages_capnp {
    #![allow(dead_code)]
    include!(concat!(env!("OUT_DIR"), "/messages_capnp.rs"));
}

use std::{io, ops};
use std::collections::HashSet;
use std::fmt::Debug;
use std::net::SocketAddr;
use std::net::TcpStream;
use std::str::FromStr;

use rustc_serialize::{Encodable, Decodable};
// Data structures.
use store::Store;
use node::RaftNode;
use state_machine::StateMachine;

// Cap'n Proto
use capnp::serialize_packed;
use capnp::{MessageBuilder, MessageReader, ReaderOptions, MallocMessageBuilder};
use messages_capnp::{
    client_request,
    client_response,
};

/// This is the primary interface with a `RaftNode` in the cluster. Creating a new `Raft` client
/// will, for now, automatically spawn a `RaftNode` with the relevant parameters. This may be
/// changed in the future. This is based on the assumption that any consuming appliaction
/// interacting with a Raft cluster will also be a participant.
pub struct Raft {
    current_leader: Option<SocketAddr>,
    related_raftnode: SocketAddr, // Not RaftNode because we move that to another thread.
    cluster_members: HashSet<SocketAddr>,
}

impl Raft {
    /// Create a new `Raft` client that has a cooresponding `RaftNode` attached. Note that this
    /// `Raft` may not necessarily interact with the cooreponding `RaftNode`, it will interact with
    /// the `Leader` of a cluster in almost all cases.
    /// *Note:* All requests are blocking, by design from the Raft paper.
    pub fn new<S, M>(addr: SocketAddr,
                     cluster_members: HashSet<SocketAddr>,
                     store: S,
                     state_machine: M)
                     -> Raft
    where S: Store, M: StateMachine {
        let mut peers = cluster_members.clone();
        peers.remove(&addr);
        RaftNode::<S, M>::spawn(addr, peers, store, state_machine);
        // Store relevant information.
        Raft {
            current_leader: None,
            related_raftnode: addr,
            cluster_members: cluster_members,
        }
    }

    /// Appends an entry to the replicated log. This will only return once it's properly replicated
    /// to a majority of nodes.
    pub fn append(&mut self, entry: &[u8]) -> io::Result<()> {
        let mut message = MallocMessageBuilder::new_default();
        if self.current_leader.is_none() { try!(self.refresh_leader()); }
        {
            let mut client_req = message.init_root::<client_request::Builder>();
            client_req.set_append(entry)
        }
        // We know current leader `is_some()` because `refresh_leader()` didn't fail.
        let mut socket = try!(TcpStream::connect(self.current_leader.unwrap())); // TODO: Handle Leader
        serialize_packed::write_packed_message_unbuffered(&mut socket, &mut message);

        // Wait for a response.
        let mut response = serialize_packed::new_reader_unbuffered(socket, ReaderOptions::new()).unwrap();
        let client_res = response.get_root::<client_response::Reader>().unwrap();
        // Set the current leader.
        match client_res.which().unwrap() {
            client_response::Which::Success(()) => {
                // It worked!
                Ok(())
            },
            client_response::Which::NotLeader(Ok(leader_bytes)) => {
                let socket = SocketAddr::from_str(leader_bytes).unwrap();
                self.current_leader = Some(socket);
                // Try again.
                self.append(entry)
            }
            _ => unimplemented!(),
        }
    }

    /// This function will force the `Raft` interface to refresh it's knowledge of the leader from
    /// The cooresponding `RaftNode` running alongside it.
    pub fn refresh_leader(&mut self) -> io::Result<()> {
        let mut message = MallocMessageBuilder::new_default();
        {
            let mut client_req = message.init_root::<client_request::Builder>();
            client_req.set_leader_refresh(());
        }
        let mut socket = try!(TcpStream::connect(self.related_raftnode));
        try!(serialize_packed::write_packed_message_unbuffered(&mut socket, &mut message));

        // Wait for a response.
        let mut response = serialize_packed::new_reader_unbuffered(socket, ReaderOptions::new()).unwrap();
        let client_res = response.get_root::<client_response::Reader>().unwrap();
        // Set the current leader.
        self.current_leader = match client_res.which().unwrap() {
            client_response::Which::NotLeader(Ok(leader_bytes)) => {
                let socket = SocketAddr::from_str(leader_bytes).unwrap();
                Some(socket)
            },
            _ => unimplemented!(),
        };
        Ok(())
    }
}

/// The term of a log entry.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
pub struct Term(u64);
impl From<u64> for Term {
    fn from(val: u64) -> Term {
        Term(val)
    }
}
impl Into<u64> for Term {
    fn into(self) -> u64 {
        self.0
    }
}
impl ops::Add<u64> for Term {
    type Output = Term;
    fn add(self, rhs: u64) -> Term {
        Term(self.0.checked_add(rhs).expect("overflow while incrementing Term"))
    }
}
impl ops::Sub<u64> for Term {
    type Output = Term;
    fn sub(self, rhs: u64) -> Term {
        Term(self.0.checked_sub(rhs).expect("underflow while decrementing Term"))
    }
}

/// The index of a log entry.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
pub struct LogIndex(u64);
impl From<u64> for LogIndex {
    fn from(val: u64) -> LogIndex {
        LogIndex(val)
    }
}
impl Into<u64> for LogIndex {
    fn into(self) -> u64 {
        self.0
    }
}
impl ops::Add<u64> for LogIndex {
    type Output = LogIndex;
    fn add(self, rhs: u64) -> LogIndex {
        LogIndex(self.0.checked_add(rhs).expect("overflow while incrementing LogIndex"))
    }
}
impl ops::Sub<u64> for LogIndex {
    type Output = LogIndex;
    fn sub(self, rhs: u64) -> LogIndex {
        LogIndex(self.0.checked_sub(rhs).expect("underflow while decrementing LogIndex"))
    }
}
<commit_msg>Improve error handling for #21<commit_after>#![crate_name = "raft"]
#![crate_type="lib"]
#![doc(html_logo_url = "https://raw.githubusercontent.com/Hoverbear/raft/master/raft.png")]
#![doc(html_root_url = "https://hoverbear.github.io/raft/raft/")]

#![feature(convert)]

extern crate capnp;
extern crate mio;
extern crate rand;
extern crate rustc_serialize;
extern crate uuid;
#[macro_use] extern crate log;

pub mod state_machine;
pub mod store;

mod node;
mod replica;
mod state;

mod messages_capnp {
    #![allow(dead_code)]
    include!(concat!(env!("OUT_DIR"), "/messages_capnp.rs"));
}

use std::{io, ops};
use std::result::Result;
use std::collections::HashSet;
use std::fmt::Debug;
use std::net::SocketAddr;
use std::net::TcpStream;
use std::str::FromStr;
use std::error::FromError;

use rustc_serialize::{Encodable, Decodable};
// Data structures.
use store::Store;
use node::RaftNode;
use state_machine::StateMachine;

// Cap'n Proto
use capnp::serialize_packed;
use capnp::{MessageBuilder, MessageReader, ReaderOptions, MallocMessageBuilder};
use messages_capnp::{
    client_request,
    client_response,
};

/// This is the primary interface with a `RaftNode` in the cluster. Creating a new `Raft` client
/// will, for now, automatically spawn a `RaftNode` with the relevant parameters. This may be
/// changed in the future. This is based on the assumption that any consuming appliaction
/// interacting with a Raft cluster will also be a participant.
pub struct Raft {
    current_leader: Option<SocketAddr>,
    related_raftnode: SocketAddr, // Not RaftNode because we move that to another thread.
    cluster_members: HashSet<SocketAddr>,
}

impl Raft {
    /// Create a new `Raft` client that has a cooresponding `RaftNode` attached. Note that this
    /// `Raft` may not necessarily interact with the cooreponding `RaftNode`, it will interact with
    /// the `Leader` of a cluster in almost all cases.
    /// *Note:* All requests are blocking, by design from the Raft paper.
    pub fn new<S, M>(addr: SocketAddr,
                     cluster_members: HashSet<SocketAddr>,
                     store: S,
                     state_machine: M)
                     -> Raft
    where S: Store, M: StateMachine {
        let mut peers = cluster_members.clone();
        peers.remove(&addr);
        RaftNode::<S, M>::spawn(addr, peers, store, state_machine);
        // Store relevant information.
        Raft {
            current_leader: None,
            related_raftnode: addr,
            cluster_members: cluster_members,
        }
    }

    /// Appends an entry to the replicated log. This will only return once it's properly replicated
    /// to a majority of nodes.
    pub fn append(&mut self, entry: &[u8]) -> Result<(), RaftError> {
        let mut message = MallocMessageBuilder::new_default();
        if self.current_leader.is_none() { try!(self.refresh_leader()); }
        {
            let mut client_req = message.init_root::<client_request::Builder>();
            client_req.set_append(entry)
        }
        // We know current leader `is_some()` because `refresh_leader()` didn't fail.
        let mut socket = try!(TcpStream::connect(self.current_leader.unwrap())); // TODO: Handle Leader
        serialize_packed::write_packed_message_unbuffered(&mut socket, &mut message);

        // Wait for a response.
        let mut response = try!(serialize_packed::new_reader_unbuffered(socket, ReaderOptions::new()));
        let client_res = try!(response.get_root::<client_response::Reader>());
        // Set the current leader.
        match try!(client_res.which()) {
            client_response::Which::Success(()) => {
                // It worked!
                Ok(())
            },
            client_response::Which::NotLeader(Ok(leader_bytes)) => {
                let current_leader = match SocketAddr::from_str(leader_bytes) {
                    Ok(socket) => Some(socket),
                    Err(_) => return Err(RaftError::Raft(RaftErrorKind::BadResponse))
                };
                // Try again.
                self.append(entry)
            },
            _ => unimplemented!(),
        }
    }

    /// This function will force the `Raft` interface to refresh it's knowledge of the leader from
    /// The cooresponding `RaftNode` running alongside it.
    pub fn refresh_leader(&mut self) -> Result<(), RaftError> {
        let mut message = MallocMessageBuilder::new_default();
        {
            let mut client_req = message.init_root::<client_request::Builder>();
            client_req.set_leader_refresh(());
        }
        let mut socket = try!(TcpStream::connect(self.related_raftnode));
        try!(serialize_packed::write_packed_message_unbuffered(&mut socket, &mut message));

        // Wait for a response.
        let mut response = serialize_packed::new_reader_unbuffered(socket, ReaderOptions::new()).unwrap();
        let client_res = try!(response.get_root::<client_response::Reader>());
        // Set the current leader.
        self.current_leader = match try!(client_res.which()) {
            client_response::Which::NotLeader(Ok(leader_bytes)) => {
                match SocketAddr::from_str(leader_bytes) {
                    Ok(socket) => Some(socket),
                    Err(_) => return Err(RaftError::Raft(RaftErrorKind::BadResponse))
                }
            },
            _ => unimplemented!(),
        };
        Ok(())
    }
}

/// RaftErrors are the composed variety of errors that can originate from the various libraries.
/// With the exception of the `Raft` variant these are generated from `try!()` macros invoking
/// on `io::Error` or `capnp::Error` by using
/// [`FromError`](https://doc.rust-lang.org/std/error/#the-fromerror-trait).
#[derive(Debug)]
pub enum RaftError {
    CapnProto(capnp::Error),
    SchemaError(capnp::NotInSchema),
    Io(io::Error),
    Raft(RaftErrorKind),
}

/// Currently, this can only be:
///
/// * `RelatedNodeDown` - When the related RaftNode is known to be down.
/// * `CannotProceed` - When the related RaftNode cannot proceed due to more than a majority of
///                     nodes being unavailable.
/// TODO: Hook these up.
#[derive(Debug)]
pub enum RaftErrorKind {
    RelatedNodeDown,
    CannotProceed,
    NotInCluster,
    BadResponse,
}

impl FromError<io::Error> for RaftError {
    fn from_error(err: io::Error) -> RaftError {
        RaftError::Io(err)
    }
}

impl FromError<capnp::Error> for RaftError {
    fn from_error(err: capnp::Error) -> RaftError {
        RaftError::CapnProto(err)
    }
}

impl FromError<capnp::NotInSchema> for RaftError {
    fn from_error(err: capnp::NotInSchema) -> RaftError {
        RaftError::SchemaError(err)
    }
}

/// The term of a log entry.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
pub struct Term(u64);
impl From<u64> for Term {
    fn from(val: u64) -> Term {
        Term(val)
    }
}
impl Into<u64> for Term {
    fn into(self) -> u64 {
        self.0
    }
}
impl ops::Add<u64> for Term {
    type Output = Term;
    fn add(self, rhs: u64) -> Term {
        Term(self.0.checked_add(rhs).expect("overflow while incrementing Term"))
    }
}
impl ops::Sub<u64> for Term {
    type Output = Term;
    fn sub(self, rhs: u64) -> Term {
        Term(self.0.checked_sub(rhs).expect("underflow while decrementing Term"))
    }
}

/// The index of a log entry.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
pub struct LogIndex(u64);
impl From<u64> for LogIndex {
    fn from(val: u64) -> LogIndex {
        LogIndex(val)
    }
}
impl Into<u64> for LogIndex {
    fn into(self) -> u64 {
        self.0
    }
}
impl ops::Add<u64> for LogIndex {
    type Output = LogIndex;
    fn add(self, rhs: u64) -> LogIndex {
        LogIndex(self.0.checked_add(rhs).expect("overflow while incrementing LogIndex"))
    }
}
impl ops::Sub<u64> for LogIndex {
    type Output = LogIndex;
    fn sub(self, rhs: u64) -> LogIndex {
        LogIndex(self.0.checked_sub(rhs).expect("underflow while decrementing LogIndex"))
    }
}
<|endoftext|>