<commit_before>use std::fs::File;
use std::io::Write;
use std::io::prelude::*;
use std::io;
use std::path::Path;
use std::collections::VecDeque;
use pest::prelude::*;

#[derive(Debug, Clone)]
pub struct Variable {
    pub name: String,
    pub vtype: String,
    pub primitive: bool,
}

#[derive(Debug, Clone)]
pub struct Function {
    pub name: String,
    pub function_args: Vec<Variable>,
    pub return_val: Option<Variable>,
    pub callback: bool,
}

#[derive(Debug)]
pub enum StructEntry {
    Var(Variable),
    Function(Function),
}

#[derive(Debug)]
pub struct Struct {
    pub name: String,
    pub inherit: Option<String>,
    pub entries: Vec<StructEntry>,
}

#[derive(Debug)]
pub struct ApiDef {
    pub entries: Vec<Struct>,
}

fn is_primitve(name: &str) -> bool {
    if name == "u8" || name == "u8" || name == "i16" || name == "u16" ||
       name == "i32" || name == "u32" || name == "i64" || name == "u64" ||
       name == "f32" || name == "f64" || name == "bool" {
        true
    } else {
        false
    }
}

impl Struct {
    pub fn is_pod(&self) -> bool {
        self.entries
            .iter()
            .all(|e| match *e {
                     StructEntry::Var(ref _var) => true,
                     _ => false,
                 })
    }

    pub fn get_functions(&self, funcs: &mut Vec<Function>) {
        for entry in &self.entries {
            match *entry {
                StructEntry::Function(ref func) => funcs.push(func.clone()),
                _ => (),
            }
        }
    }
}

impl Variable {
    pub fn get_c_type(&self) -> String {
        let tname = &self.vtype;
        let primitve = self.primitive;

        if tname == "String" {
            return "const char*".to_owned();
        }

        if tname == "self" {
            return "void*".to_owned();
        }

        if primitve {
            if tname == "f32" {
                return "float".to_owned();
            } else if tname == "bool" {
                return "bool".to_owned();
            } else if tname == "f64" {
                return "double".to_owned();
            } else if tname == "i32" {
                return "int".to_owned();
            } else {
                // here we will have u8/i8,u32/etc
                if tname.starts_with("u") {
                    return format!("uint{}_t", &tname[1..]);
                } else {
                    return format!("int{}_t", &tname[1..]);
                }
            }
        } else {
            // Unknown type here, we always assume to use a struct Type*
            format!("struct PU{}*", tname)
        }
    }
}

impl Function {
    pub fn write_c_func_def<F>(&self, f: &mut File, filter: F) -> io::Result<()>
        where F: Fn(usize, &Variable) -> (String, String)
    {
        let arg_count = self.function_args.len();

        for (i, arg) in self.function_args.iter().enumerate() {
            let filter_arg = filter(i, &arg);

            if filter_arg.1 == "" {
                f.write_fmt(format_args!("{}", filter_arg.0))?;
            } else {
                f.write_fmt(format_args!("{} {}", filter_arg.0, filter_arg.1))?;
            }

            if i != arg_count - 1 {
                f.write_all(b", ")?;
            }
        }

        f.write_all(b")")?;

        if let Some(ref ret_var) = self.return_val {
            let filter_arg = filter(arg_count, &ret_var);
            if filter_arg.1 != "" {
                f.write_fmt(format_args!(" -> {}", filter_arg.1))?;
            }
        }

        Ok(())
    }

    pub fn write_func_def<F>(&self, f: &mut File, filter: F) -> io::Result<()>
        where F: Fn(usize, &Variable) -> (String, String)
    {
        let arg_count = self.function_args.len();

        for (i, arg) in self.function_args.iter().enumerate() {
            let filter_arg = filter(i, &arg);

            if filter_arg.1 == "" {
                f.write_fmt(format_args!("{}", filter_arg.0))?;
            } else {
                f.write_fmt(format_args!("{}: {}", filter_arg.0, filter_arg.1))?;
            }

            if i != arg_count - 1 {
                f.write_all(b", ")?;
            }
        }

        //f.write_all(b")")?;

        if let Some(ref ret_var) = self.return_val {
            let filter_arg = filter(arg_count, &ret_var);
            if filter_arg.1 != "" {
                f.write_fmt(format_args!(" -> {}", filter_arg.1))?;
            }
        }

        Ok(())
    }
}

impl ApiDef {
    fn collect_recursive(funcs: &mut Vec<Function>, api_def: &ApiDef, sdef: &Struct) {
        if let Some(ref inherit_name) = sdef.inherit {
            for sdef in &api_def.entries {
                if &sdef.name == inherit_name {
                    Self::collect_recursive(funcs, api_def, &sdef);
                }
            }
        }

        sdef.get_functions(funcs);
    }

    pub fn collect_functions(&self, sdef: &Struct) -> Vec<Function> {
        let mut funcs = Vec::new();

        Self::collect_recursive(&mut funcs, &self, sdef);

        funcs
    }
}

impl_rdp! {
    grammar! {
        chunk = _{ soi ~ structdef* ~ eoi }

        structdef   =  { name ~ derive? ~ ["{"] ~ fieldlist? ~ ["}"] }
        fieldlist   =  { field ~ (fieldsep ~ field)* ~ fieldsep* }
        field       =  { var | function }
        fieldsep    = _{ [","] }

        rettype     = { name }
        derive      = { [":"] ~ name }
        callback    = { ["[callback]"] }
        retexp      = { ["->"] ~ name }
        var         = { name ~ name }
        varlist     = { var ~ ([","] ~ var)* }
        function    = { callback? ~ name ~ ["("] ~ varlist? ~ [")"] ~ retexp? }

        name = @{
            (['a'..'z'] | ['A'..'Z'] | ["_"]) ~ (['a'..'z'] | ['A'..'Z'] | ["_"] | ['0'..'9'])*
        }

       comment = _{
            ["//"] ~ (!(["\r"] | ["\n"]) ~ any)* ~ (["\n"] | ["\r\n"] | ["\r"] | eoi)
        }

        whitespace = _{ [" "] | ["\t"] | ["\u{000C}"] | ["\r"] | ["\n"] }
    }

    process! {
        process(&self) -> Vec<Struct> {
            (structs: _chunk()) => {
                structs.into_iter().collect::<Vec<_>>()
            },
        }

        _chunk(&self) -> VecDeque<Struct> {
            (_: structdef, sdef: _structdef(), mut tail: _chunk()) => {
                tail.push_front(sdef);
                tail
            },

            () => VecDeque::new(),
        }

        _structdef(&self) -> Struct {
            (&name: name, inherit: _derive(), list: _fieldentries()) => {
                Struct {
                    name: name.to_owned(),
                    inherit: inherit,
                    entries: list.into_iter().collect::<Vec<_>>(),
                }
            },
        }

        _derive(&self) -> Option<String> {
            (_: derive, &name: name) => Some(name.to_owned()),
            () => None,
        }

        _fieldentries(&self) -> VecDeque<StructEntry> {
            (_: field, entry: _fieldentry(), mut tail: _fieldentries()) => {
                tail.push_front(entry);
                tail
            },

            (_: fieldlist, entries: _fieldentries()) => entries,
            () => VecDeque::new(),
        }

        _fieldentry(&self) -> StructEntry {
            (_: function, func: _funcentry()) => func,

            (_: var, &vtype: name, &name: name) => {
                StructEntry::Var(Variable {
                    name: name.to_owned(),
                    vtype: vtype.to_owned(),
                    primitive: is_primitve(vtype),
                })
            },
        }

        _funcentry(&self) -> StructEntry {
            (callback: _callback(), &name: name, mut func_args: _func_args_list(), ret_value: _returnvalue()) => {
                func_args.push_front(Variable {
                    name: "self_c".to_owned(),
                    vtype: "self".to_owned(),
                    primitive: false,
                });
                // we always have self as first parameter so add it here
                StructEntry::Function(Function {
                    name: name.to_owned(),
                    function_args: func_args.into_iter().collect::<Vec<_>>(),
                    return_val: ret_value,
                    callback: callback,
                })
            }
        }

        _callback(&self) -> bool {
            (_: callback) => true,
            () => false,
        }

        _returnvalue(&self) -> Option<Variable> {
            (_: retexp, &name: name) => {
                Some(Variable {
                    name: "".to_owned(),
                    vtype: name.to_owned(),
                    primitive: is_primitve(name),
                })
            },
            () => None,
        }

        _func_args_list(&self) -> VecDeque<Variable> {
            (_: var, &name: name, &atype: name, mut tail: _func_args_list()) => {
                tail.push_front(Variable {
                    name: atype.to_owned(),
                    vtype: name.to_owned(),
                    primitive: is_primitve(name),
                });

                tail
            },

            (_: varlist, tail: _func_args_list()) => tail,
            () => VecDeque::new(),
        }
    }
}

impl ApiDef {
    pub fn new<P: AsRef<Path>>(path: P) -> ApiDef {
        let mut text = String::new();

        let mut file = File::open(path).unwrap();
        file.read_to_string(&mut text).unwrap();

        let mut parser = Rdp::new(StringInput::new(&text));

        parser.chunk();

        if !parser.end() {
            let expected = parser.expected();
            panic!("Failed to parse file - {:?} - {}",
                   parser.expected(),
                   &text[expected.1..]);
        }

        ApiDef { entries: parser.process() }
    }
}
<commit_msg>Helper functions to reduce client code<commit_after>use std::fs::File;
use std::io::Write;
use std::io::prelude::*;
use std::io;
use std::path::Path;
use std::collections::VecDeque;
use pest::prelude::*;

#[derive(Debug, Clone)]
pub struct Variable {
    pub name: String,
    pub vtype: String,
    pub primitive: bool,
}

#[derive(Debug, Clone)]
pub struct Function {
    pub name: String,
    pub function_args: Vec<Variable>,
    pub return_val: Option<Variable>,
    pub callback: bool,
}

#[derive(Debug)]
pub enum StructEntry {
    Var(Variable),
    Function(Function),
}

#[derive(Debug)]
pub struct Struct {
    pub name: String,
    pub inherit: Option<String>,
    pub entries: Vec<StructEntry>,
}

#[derive(Debug)]
pub struct ApiDef {
    pub entries: Vec<Struct>,
}

fn is_primitve(name: &str) -> bool {
    if name == "u8" || name == "u8" || name == "i16" || name == "u16" ||
       name == "i32" || name == "u32" || name == "i64" || name == "u64" ||
       name == "f32" || name == "f64" || name == "bool" {
        true
    } else {
        false
    }
}

impl Struct {
    pub fn is_pod(&self) -> bool {
        self.entries
            .iter()
            .all(|e| match *e {
                     StructEntry::Var(ref _var) => true,
                     _ => false,
                 })
    }

    pub fn get_functions<F>(&self, funcs: &mut Vec<Function>, filter: F)
        where F: Fn(&Func) -> bool {
        for entry in &self.entries {
            match *entry {
                StructEntry::Function(ref func) =>
                    if filter(func) {
                        funcs.push(func.clone());
                    },
                _ => (),
            }
        }
    }

    pub fn get_callback_functions(&self, funcs: &mut Vec<Function>) {
        Self::get_functions(self, funcs, |func| func.callback)
    }

    pub fn get_regular_functions(&self, funcs: &mut Vec<Function>) {
        Self::get_functions(self, funcs, |func| !func.callback)
    }

    pub fn get_all_functions(&self, funcs: &mut Vec<Function>) {
        Self::get_functions(self, funcs, |_| true)
    }
}

impl Variable {
    pub fn get_c_type(&self) -> String {
        let tname = &self.vtype;
        let primitve = self.primitive;

        if tname == "String" {
            return "const char*".to_owned();
        }

        if tname == "self" {
            return "void*".to_owned();
        }

        if primitve {
            if tname == "f32" {
                return "float".to_owned();
            } else if tname == "bool" {
                return "bool".to_owned();
            } else if tname == "f64" {
                return "double".to_owned();
            } else if tname == "i32" {
                return "int".to_owned();
            } else {
                // here we will have u8/i8,u32/etc
                if tname.starts_with("u") {
                    return format!("uint{}_t", &tname[1..]);
                } else {
                    return format!("int{}_t", &tname[1..]);
                }
            }
        } else {
            // Unknown type here, we always assume to use a struct Type*
            format!("struct PU{}*", tname)
        }
    }
}

impl Function {
    pub fn write_c_func_def<F>(&self, f: &mut File, filter: F) -> io::Result<()>
        where F: Fn(usize, &Variable) -> (String, String)
    {
        let arg_count = self.function_args.len();

        for (i, arg) in self.function_args.iter().enumerate() {
            let filter_arg = filter(i, &arg);

            if filter_arg.1 == "" {
                f.write_fmt(format_args!("{}", filter_arg.0))?;
            } else {
                f.write_fmt(format_args!("{} {}", filter_arg.0, filter_arg.1))?;
            }

            if i != arg_count - 1 {
                f.write_all(b", ")?;
            }
        }

        f.write_all(b")")?;

        if let Some(ref ret_var) = self.return_val {
            let filter_arg = filter(arg_count, &ret_var);
            if filter_arg.1 != "" {
                f.write_fmt(format_args!(" -> {}", filter_arg.1))?;
            }
        }

        Ok(())
    }

    pub fn write_func_def<F>(&self, f: &mut File, filter: F) -> io::Result<()>
        where F: Fn(usize, &Variable) -> (String, String)
    {
        let arg_count = self.function_args.len();

        for (i, arg) in self.function_args.iter().enumerate() {
            let filter_arg = filter(i, &arg);

            if filter_arg.1 == "" {
                f.write_fmt(format_args!("{}", filter_arg.0))?;
            } else {
                f.write_fmt(format_args!("{}: {}", filter_arg.0, filter_arg.1))?;
            }

            if i != arg_count - 1 {
                f.write_all(b", ")?;
            }
        }

        //f.write_all(b")")?;

        if let Some(ref ret_var) = self.return_val {
            let filter_arg = filter(arg_count, &ret_var);
            if filter_arg.1 != "" {
                f.write_fmt(format_args!(" -> {}", filter_arg.1))?;
            }
        }

        Ok(())
    }
}

impl ApiDef {
    fn collect_recursive<F>(funcs: &mut Vec<Function>, api_def: &ApiDef, sdef: &Struct, filter: F)
        where F: Fn(&Func) -> bool {
        if let Some(ref inherit_name) = sdef.inherit {
            for sdef in &api_def.entries {
                if &sdef.name == inherit_name {
                    Self::collect_recursive(funcs, api_def, &sdef);
                }
            }
        }

        sdef.get_functions(funcs, f);
    }

    pub fn collect_functions<F>(&self, sdef: &Struct, filter)
        where F: Fn(&Func) -> Vec<Function> {

        let mut funcs = Vec::new();

        Self::collect_recursive(&mut funcs, &self, sdef, f);

        funcs
    }

    pub fn collect_all_functions(&self, sdef: &Struct) -> Vec<Function> {
        Self::collect_functions(&self, sdef, |_| true)
    }

    pub fn collect_callback_functions(&self, sdef: &Struct) -> Vec<Function> {
        Self::collect_functions(&self, sdef, |f| f.callback )
    }

    pub fn collect_regular_functions(&self, sdef: &Struct) -> Vec<Function> {
        Self::collect_functions(&self, sdef, |f| !f.callback)
    }
}

impl_rdp! {
    grammar! {
        chunk = _{ soi ~ structdef* ~ eoi }

        structdef   =  { name ~ derive? ~ ["{"] ~ fieldlist? ~ ["}"] }
        fieldlist   =  { field ~ (fieldsep ~ field)* ~ fieldsep* }
        field       =  { var | function }
        fieldsep    = _{ [","] }

        rettype     = { name }
        derive      = { [":"] ~ name }
        callback    = { ["[callback]"] }
        retexp      = { ["->"] ~ name }
        var         = { name ~ name }
        varlist     = { var ~ ([","] ~ var)* }
        function    = { callback? ~ name ~ ["("] ~ varlist? ~ [")"] ~ retexp? }

        name = @{
            (['a'..'z'] | ['A'..'Z'] | ["_"]) ~ (['a'..'z'] | ['A'..'Z'] | ["_"] | ['0'..'9'])*
        }

       comment = _{
            ["//"] ~ (!(["\r"] | ["\n"]) ~ any)* ~ (["\n"] | ["\r\n"] | ["\r"] | eoi)
        }

        whitespace = _{ [" "] | ["\t"] | ["\u{000C}"] | ["\r"] | ["\n"] }
    }

    process! {
        process(&self) -> Vec<Struct> {
            (structs: _chunk()) => {
                structs.into_iter().collect::<Vec<_>>()
            },
        }

        _chunk(&self) -> VecDeque<Struct> {
            (_: structdef, sdef: _structdef(), mut tail: _chunk()) => {
                tail.push_front(sdef);
                tail
            },

            () => VecDeque::new(),
        }

        _structdef(&self) -> Struct {
            (&name: name, inherit: _derive(), list: _fieldentries()) => {
                Struct {
                    name: name.to_owned(),
                    inherit: inherit,
                    entries: list.into_iter().collect::<Vec<_>>(),
                }
            },
        }

        _derive(&self) -> Option<String> {
            (_: derive, &name: name) => Some(name.to_owned()),
            () => None,
        }

        _fieldentries(&self) -> VecDeque<StructEntry> {
            (_: field, entry: _fieldentry(), mut tail: _fieldentries()) => {
                tail.push_front(entry);
                tail
            },

            (_: fieldlist, entries: _fieldentries()) => entries,
            () => VecDeque::new(),
        }

        _fieldentry(&self) -> StructEntry {
            (_: function, func: _funcentry()) => func,

            (_: var, &vtype: name, &name: name) => {
                StructEntry::Var(Variable {
                    name: name.to_owned(),
                    vtype: vtype.to_owned(),
                    primitive: is_primitve(vtype),
                })
            },
        }

        _funcentry(&self) -> StructEntry {
            (callback: _callback(), &name: name, mut func_args: _func_args_list(), ret_value: _returnvalue()) => {
                func_args.push_front(Variable {
                    name: "self_c".to_owned(),
                    vtype: "self".to_owned(),
                    primitive: false,
                });
                // we always have self as first parameter so add it here
                StructEntry::Function(Function {
                    name: name.to_owned(),
                    function_args: func_args.into_iter().collect::<Vec<_>>(),
                    return_val: ret_value,
                    callback: callback,
                })
            }
        }

        _callback(&self) -> bool {
            (_: callback) => true,
            () => false,
        }

        _returnvalue(&self) -> Option<Variable> {
            (_: retexp, &name: name) => {
                Some(Variable {
                    name: "".to_owned(),
                    vtype: name.to_owned(),
                    primitive: is_primitve(name),
                })
            },
            () => None,
        }

        _func_args_list(&self) -> VecDeque<Variable> {
            (_: var, &name: name, &atype: name, mut tail: _func_args_list()) => {
                tail.push_front(Variable {
                    name: atype.to_owned(),
                    vtype: name.to_owned(),
                    primitive: is_primitve(name),
                });

                tail
            },

            (_: varlist, tail: _func_args_list()) => tail,
            () => VecDeque::new(),
        }
    }
}

impl ApiDef {
    pub fn new<P: AsRef<Path>>(path: P) -> ApiDef {
        let mut text = String::new();

        let mut file = File::open(path).unwrap();
        file.read_to_string(&mut text).unwrap();

        let mut parser = Rdp::new(StringInput::new(&text));

        parser.chunk();

        if !parser.end() {
            let expected = parser.expected();
            panic!("Failed to parse file - {:?} - {}",
                   parser.expected(),
                   &text[expected.1..]);
        }

        ApiDef { entries: parser.process() }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Defines how the color output of the fragment shader is written to the attachment.
//!
//! There are three kinds of color attachments for the purpose of blending:
//!
//! - Attachments with a floating-point, fixed point format.
//! - Attachments with a (non-normalized) integer format.
//! - Attachments with a normalized integer format.
//!
//! For floating-point and fixed-point formats, the blending operation is applied. For integer
//! formats, the logic operation is applied. For normalized integer formats, the logic operation
//! will take precedence if it is activated, otherwise the blending operation is applied.
//!

use vk;

#[derive(Debug, Clone, PartialEq)]
pub struct Blend {
    pub logic_op: Option<LogicOp>,

    pub attachments: AttachmentsBlend,

    /// The constant color to use for the `Constant*` blending operation.
    ///
    /// If you pass `None`, then this state will be considered as dynamic and the blend constants
    /// will need to be set when you build the command buffer.
    pub blend_constants: Option<[f32; 4]>,
}

impl Blend {
    /// Returns a `Blend` object that directly writes colors and alpha on the surface.
    #[inline]
    pub fn pass_through() -> Blend {
        Blend {
            logic_op: None,
            attachments: AttachmentsBlend::Collective(AttachmentBlend {
                enabled: false,
                color_op: BlendOp::Add,
                color_src: BlendFactor::Zero,
                color_dst: BlendFactor::One,
                alpha_op: BlendOp::Add,
                alpha_src: BlendFactor::Zero,
                alpha_dst: BlendFactor::One,
                mask_red: true,
                mask_green: true,
                mask_blue: true,
                mask_alpha: true,
            }),
            blend_constants: Some([0.0, 0.0, 0.0, 0.0]),
        }
    }

    /// Returns a `Blend` object that adds transparent objects over others.
    #[inline]
    pub fn alpha_blending() -> Blend {
        Blend {
            logic_op: None,
            attachments: AttachmentsBlend::Collective(AttachmentBlend {
                enabled: false,
                color_op: BlendOp::Add,
                color_src: BlendFactor::SrcAlpha,
                color_dst: BlendFactor::OneMinusSrcAlpha,
                alpha_op: BlendOp::Add,
                alpha_src: BlendFactor::SrcAlpha,
                alpha_dst: BlendFactor::OneMinusSrcAlpha,
                mask_red: true,
                mask_green: true,
                mask_blue: true,
                mask_alpha: true,
            }),
            blend_constants: Some([0.0, 0.0, 0.0, 0.0]),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AttachmentsBlend {
    Collective(AttachmentBlend),
    Individual(Vec<AttachmentBlend>),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AttachmentBlend {
    // TODO: could be automatically determined from the other params
    pub enabled: bool,

    pub color_op: BlendOp,
    pub color_src: BlendFactor,
    pub color_dst: BlendFactor,

    pub alpha_op: BlendOp,
    pub alpha_src: BlendFactor,
    pub alpha_dst: BlendFactor,

    pub mask_red: bool,
    pub mask_green: bool,
    pub mask_blue: bool,
    pub mask_alpha: bool,
}

#[doc(hidden)]
impl Into<vk::PipelineColorBlendAttachmentState> for AttachmentBlend {
    #[inline]
    fn into(self) -> vk::PipelineColorBlendAttachmentState {
        vk::PipelineColorBlendAttachmentState {
            blendEnable: if self.enabled { vk::TRUE } else { vk::FALSE },
            srcColorBlendFactor: self.color_src as u32,
            dstColorBlendFactor: self.color_dst as u32,
            colorBlendOp: self.color_op as u32,
            srcAlphaBlendFactor: self.alpha_src as u32,
            dstAlphaBlendFactor: self.alpha_dst as u32,
            alphaBlendOp: self.alpha_op as u32,
            colorWriteMask: {
                let mut mask = 0;
                if self.mask_red { mask |= vk::COLOR_COMPONENT_R_BIT; }
                if self.mask_green { mask |= vk::COLOR_COMPONENT_G_BIT; }
                if self.mask_blue { mask |= vk::COLOR_COMPONENT_B_BIT; }
                if self.mask_alpha { mask |= vk::COLOR_COMPONENT_A_BIT; }
                mask
            },
        }
    }
}

/// Which logical operation to apply to the output values.
///
/// The operation is applied individually for each channel (red, green, blue and alpha).
///
/// Only relevant for integer or unsigned attachments.
///
/// Also note that some implementations don't support logic operations.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum LogicOp {
    /// Returns `0`.
    Clear = vk::LOGIC_OP_CLEAR,
    /// Returns `src & dest`.
    And = vk::LOGIC_OP_AND,
    /// Returns `src & !dest`.
    AndReverse = vk::LOGIC_OP_AND_REVERSE,
    /// Returns `src`.
    Copy = vk::LOGIC_OP_COPY,
    /// Returns `!src & dest`.
    AndInverted = vk::LOGIC_OP_AND_INVERTED,
    /// Returns `dest`.
    Noop = vk::LOGIC_OP_NO_OP,
    /// Returns `src ^ dest`.
    Xor = vk::LOGIC_OP_XOR,
    /// Returns `src | dest`.
    Or = vk::LOGIC_OP_OR,
    /// Returns `!(src | dest)`.
    Nor = vk::LOGIC_OP_NOR,
    /// Returns `!(src ^ dest)`.
    Equivalent = vk::LOGIC_OP_EQUIVALENT,
    /// Returns `!dest`.
    Invert = vk::LOGIC_OP_INVERT,
    /// Returns `src | !dest.
    OrReverse = vk::LOGIC_OP_OR_REVERSE,
    /// Returns `!src`.
    CopyInverted = vk::LOGIC_OP_COPY_INVERTED,
    /// Returns `!src | dest`.
    OrInverted = vk::LOGIC_OP_OR_INVERTED,
    /// Returns `!(src & dest)`.
    Nand = vk::LOGIC_OP_NAND,
    /// Returns `!0` (all bits set to 1).
    Set = vk::LOGIC_OP_SET,
}

impl Default for LogicOp {
    #[inline]
    fn default() -> LogicOp {
        LogicOp::Noop
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum BlendOp {
    Add = vk::BLEND_OP_ADD,
    Subtract = vk::BLEND_OP_SUBTRACT,
    ReverseSubtract = vk::BLEND_OP_REVERSE_SUBTRACT,
    Min = vk::BLEND_OP_MIN,
    Max = vk::BLEND_OP_MAX,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum BlendFactor {
    Zero = vk::BLEND_FACTOR_ZERO,
    One = vk::BLEND_FACTOR_ONE,
    SrcColor = vk::BLEND_FACTOR_SRC_COLOR,
    OneMinusSrcColor = vk::BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
    DstColor = vk::BLEND_FACTOR_DST_COLOR,
    OneMinusDstColor = vk::BLEND_FACTOR_ONE_MINUS_DST_COLOR,
    SrcAlpha = vk::BLEND_FACTOR_SRC_ALPHA,
    OneMinusSrcAlpha = vk::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
    DstAlpha = vk::BLEND_FACTOR_DST_ALPHA,
    OneMinusDstAlpha = vk::BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
    ConstantColor = vk::BLEND_FACTOR_CONSTANT_COLOR,
    OneMinusConstantColor = vk::BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
    ConstantAlpha = vk::BLEND_FACTOR_CONSTANT_ALPHA,
    OneMinusConstantAlpha = vk::BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
    SrcAlphaSaturate = vk::BLEND_FACTOR_SRC_ALPHA_SATURATE,
    Src1Color = vk::BLEND_FACTOR_SRC1_COLOR,
    OneMinusSrc1Color = vk::BLEND_FACTOR_ONE_MINUS_SRC1_COLOR,
    Src1Alpha = vk::BLEND_FACTOR_SRC1_ALPHA,
    OneMinusSrc1Alpha = vk::BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA,
}
<commit_msg>Fix blending disabled in alpha_blending()<commit_after>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Defines how the color output of the fragment shader is written to the attachment.
//!
//! There are three kinds of color attachments for the purpose of blending:
//!
//! - Attachments with a floating-point, fixed point format.
//! - Attachments with a (non-normalized) integer format.
//! - Attachments with a normalized integer format.
//!
//! For floating-point and fixed-point formats, the blending operation is applied. For integer
//! formats, the logic operation is applied. For normalized integer formats, the logic operation
//! will take precedence if it is activated, otherwise the blending operation is applied.
//!

use vk;

#[derive(Debug, Clone, PartialEq)]
pub struct Blend {
    pub logic_op: Option<LogicOp>,

    pub attachments: AttachmentsBlend,

    /// The constant color to use for the `Constant*` blending operation.
    ///
    /// If you pass `None`, then this state will be considered as dynamic and the blend constants
    /// will need to be set when you build the command buffer.
    pub blend_constants: Option<[f32; 4]>,
}

impl Blend {
    /// Returns a `Blend` object that directly writes colors and alpha on the surface.
    #[inline]
    pub fn pass_through() -> Blend {
        Blend {
            logic_op: None,
            attachments: AttachmentsBlend::Collective(AttachmentBlend {
                enabled: false,
                color_op: BlendOp::Add,
                color_src: BlendFactor::Zero,
                color_dst: BlendFactor::One,
                alpha_op: BlendOp::Add,
                alpha_src: BlendFactor::Zero,
                alpha_dst: BlendFactor::One,
                mask_red: true,
                mask_green: true,
                mask_blue: true,
                mask_alpha: true,
            }),
            blend_constants: Some([0.0, 0.0, 0.0, 0.0]),
        }
    }

    /// Returns a `Blend` object that adds transparent objects over others.
    #[inline]
    pub fn alpha_blending() -> Blend {
        Blend {
            logic_op: None,
            attachments: AttachmentsBlend::Collective(AttachmentBlend {
                enabled: true,
                color_op: BlendOp::Add,
                color_src: BlendFactor::SrcAlpha,
                color_dst: BlendFactor::OneMinusSrcAlpha,
                alpha_op: BlendOp::Add,
                alpha_src: BlendFactor::SrcAlpha,
                alpha_dst: BlendFactor::OneMinusSrcAlpha,
                mask_red: true,
                mask_green: true,
                mask_blue: true,
                mask_alpha: true,
            }),
            blend_constants: Some([0.0, 0.0, 0.0, 0.0]),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AttachmentsBlend {
    Collective(AttachmentBlend),
    Individual(Vec<AttachmentBlend>),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AttachmentBlend {
    // TODO: could be automatically determined from the other params
    pub enabled: bool,

    pub color_op: BlendOp,
    pub color_src: BlendFactor,
    pub color_dst: BlendFactor,

    pub alpha_op: BlendOp,
    pub alpha_src: BlendFactor,
    pub alpha_dst: BlendFactor,

    pub mask_red: bool,
    pub mask_green: bool,
    pub mask_blue: bool,
    pub mask_alpha: bool,
}

#[doc(hidden)]
impl Into<vk::PipelineColorBlendAttachmentState> for AttachmentBlend {
    #[inline]
    fn into(self) -> vk::PipelineColorBlendAttachmentState {
        vk::PipelineColorBlendAttachmentState {
            blendEnable: if self.enabled { vk::TRUE } else { vk::FALSE },
            srcColorBlendFactor: self.color_src as u32,
            dstColorBlendFactor: self.color_dst as u32,
            colorBlendOp: self.color_op as u32,
            srcAlphaBlendFactor: self.alpha_src as u32,
            dstAlphaBlendFactor: self.alpha_dst as u32,
            alphaBlendOp: self.alpha_op as u32,
            colorWriteMask: {
                let mut mask = 0;
                if self.mask_red { mask |= vk::COLOR_COMPONENT_R_BIT; }
                if self.mask_green { mask |= vk::COLOR_COMPONENT_G_BIT; }
                if self.mask_blue { mask |= vk::COLOR_COMPONENT_B_BIT; }
                if self.mask_alpha { mask |= vk::COLOR_COMPONENT_A_BIT; }
                mask
            },
        }
    }
}

/// Which logical operation to apply to the output values.
///
/// The operation is applied individually for each channel (red, green, blue and alpha).
///
/// Only relevant for integer or unsigned attachments.
///
/// Also note that some implementations don't support logic operations.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum LogicOp {
    /// Returns `0`.
    Clear = vk::LOGIC_OP_CLEAR,
    /// Returns `src & dest`.
    And = vk::LOGIC_OP_AND,
    /// Returns `src & !dest`.
    AndReverse = vk::LOGIC_OP_AND_REVERSE,
    /// Returns `src`.
    Copy = vk::LOGIC_OP_COPY,
    /// Returns `!src & dest`.
    AndInverted = vk::LOGIC_OP_AND_INVERTED,
    /// Returns `dest`.
    Noop = vk::LOGIC_OP_NO_OP,
    /// Returns `src ^ dest`.
    Xor = vk::LOGIC_OP_XOR,
    /// Returns `src | dest`.
    Or = vk::LOGIC_OP_OR,
    /// Returns `!(src | dest)`.
    Nor = vk::LOGIC_OP_NOR,
    /// Returns `!(src ^ dest)`.
    Equivalent = vk::LOGIC_OP_EQUIVALENT,
    /// Returns `!dest`.
    Invert = vk::LOGIC_OP_INVERT,
    /// Returns `src | !dest.
    OrReverse = vk::LOGIC_OP_OR_REVERSE,
    /// Returns `!src`.
    CopyInverted = vk::LOGIC_OP_COPY_INVERTED,
    /// Returns `!src | dest`.
    OrInverted = vk::LOGIC_OP_OR_INVERTED,
    /// Returns `!(src & dest)`.
    Nand = vk::LOGIC_OP_NAND,
    /// Returns `!0` (all bits set to 1).
    Set = vk::LOGIC_OP_SET,
}

impl Default for LogicOp {
    #[inline]
    fn default() -> LogicOp {
        LogicOp::Noop
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum BlendOp {
    Add = vk::BLEND_OP_ADD,
    Subtract = vk::BLEND_OP_SUBTRACT,
    ReverseSubtract = vk::BLEND_OP_REVERSE_SUBTRACT,
    Min = vk::BLEND_OP_MIN,
    Max = vk::BLEND_OP_MAX,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum BlendFactor {
    Zero = vk::BLEND_FACTOR_ZERO,
    One = vk::BLEND_FACTOR_ONE,
    SrcColor = vk::BLEND_FACTOR_SRC_COLOR,
    OneMinusSrcColor = vk::BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
    DstColor = vk::BLEND_FACTOR_DST_COLOR,
    OneMinusDstColor = vk::BLEND_FACTOR_ONE_MINUS_DST_COLOR,
    SrcAlpha = vk::BLEND_FACTOR_SRC_ALPHA,
    OneMinusSrcAlpha = vk::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
    DstAlpha = vk::BLEND_FACTOR_DST_ALPHA,
    OneMinusDstAlpha = vk::BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
    ConstantColor = vk::BLEND_FACTOR_CONSTANT_COLOR,
    OneMinusConstantColor = vk::BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
    ConstantAlpha = vk::BLEND_FACTOR_CONSTANT_ALPHA,
    OneMinusConstantAlpha = vk::BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
    SrcAlphaSaturate = vk::BLEND_FACTOR_SRC_ALPHA_SATURATE,
    Src1Color = vk::BLEND_FACTOR_SRC1_COLOR,
    OneMinusSrc1Color = vk::BLEND_FACTOR_ONE_MINUS_SRC1_COLOR,
    Src1Alpha = vk::BLEND_FACTOR_SRC1_ALPHA,
    OneMinusSrc1Alpha = vk::BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA,
}
<|endoftext|>


<commit_before>extern crate handlebars;
extern crate itertools;
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;

use handlebars::Handlebars;
use itertools::Itertools;
use serde_json::Value;
use std::collections::BTreeMap;
use std::ascii::AsciiExt;

trait Codegen {
    fn codegen(&self, handlebars: &Handlebars) -> String;
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AMQProtocolDefinition {
    pub name:          String,
    #[serde(rename="major-version")]
    pub major_version: u8,
    #[serde(rename="minor-version")]
    pub minor_version: u8,
    pub revision:      u8,
    pub port:          u32,
    pub copyright:     Vec<String>,
    pub domains:       Vec<AMQPDomain>,
    pub constants:     Vec<AMQPConstant>,
    pub classes:       Vec<AMQPClass>,
}

impl AMQProtocolDefinition {
    pub fn load() -> AMQProtocolDefinition {
        let specs = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/specs/amqp-rabbitmq-0.9.1.json"));

        serde_json::from_str::<AMQProtocolDefinition>(specs).expect("Failed to parse AMQP specs file")
    }

    pub fn codegen(&self, templates: &AMQPTemplates) -> String {
        let handlebars = register_templates(templates);
        let mut data   = BTreeMap::new();

        data.insert("name".to_string(),          self.name.clone());
        data.insert("major_version".to_string(), format!("{}", self.major_version));
        data.insert("minor_version".to_string(), format!("{}", self.minor_version));
        data.insert("revision".to_string(),      format!("{}", self.revision));
        data.insert("port".to_string(),          format!("{}", self.port));
        data.insert("copyright".to_string(),     self.copyright.iter().join(""));
        data.insert("domains".to_string(),       self.domains.iter().map(|domain| domain.codegen(&handlebars)).join("\n"));
        data.insert("constants".to_string(),     self.constants.iter().map(|constant| constant.codegen(&handlebars)).join("\n"));
        data.insert("classes".to_string(),       self.classes.iter().map(|klass| klass.codegen(&handlebars)).join("\n"));

        handlebars.render("main", &data).expect("Failed to render main template")
    }

    pub fn codegen_full(self, full_template: &str) -> String {
        let mut handlebars = Handlebars::new();
        let mut data = BTreeMap::new();

        handlebars.register_escape_fn(handlebars::no_escape);
        handlebars.register_template_string("full", full_template).expect("Failed to register full template");

        data.insert("specs".to_string(), self);

        handlebars.render("full", &data).expect("Failed to render full template")
    }
}

fn register_templates(templates: &AMQPTemplates) -> Handlebars {
    let mut handlebars = Handlebars::new();

    handlebars.register_escape_fn(handlebars::no_escape);

    handlebars.register_template_string("main",     &templates.main).expect("Failed to register main template");
    handlebars.register_template_string("domain",   &templates.domain).expect("Failed to register domain template");
    handlebars.register_template_string("constant", &templates.constant).expect("Failed to register constant template");
    handlebars.register_template_string("class",    &templates.klass).expect("Failed to register class template");
    handlebars.register_template_string("method",   &templates.method).expect("Failed to register method template");
    handlebars.register_template_string("argument", &templates.argument).expect("Failed to register argument template");
    handlebars.register_template_string("property", &templates.property).expect("Failed to register property template");

    handlebars
}

pub struct AMQPTemplates {
    pub main:     String,
    pub domain:   String,
    pub constant: String,
    pub klass:    String,
    pub method:   String,
    pub argument: String,
    pub property: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub enum AMQPType {
    #[serde(rename="bit")]
    Bit,
    #[serde(rename="octet")]
    Octet,
    #[serde(rename="short")]
    Short,
    #[serde(rename="long")]
    Long,
    #[serde(rename="longlong")]
    LongLong,
    #[serde(rename="shortstr")]
    ShortStr,
    #[serde(rename="longstr")]
    LongStr,
    #[serde(rename="table")]
    Table,
    #[serde(rename="timestamp")]
    Timestamp,
}

impl AMQPType {
    fn to_string(&self) -> String {
        match *self {
            AMQPType::Bit       => "bit",
            AMQPType::Octet     => "octet",
            AMQPType::Short     => "short",
            AMQPType::Long      => "long",
            AMQPType::LongLong  => "longlong",
            AMQPType::ShortStr  => "shortstr",
            AMQPType::LongStr   => "longstr",
            AMQPType::Table     => "table",
            AMQPType::Timestamp => "timestamp",
        }.to_string()
    }

    fn to_rust_type(&self) -> String {
        match *self {
            AMQPType::Bit       => "bool",
            AMQPType::Octet     => "u8",
            AMQPType::Short     => "u16",
            AMQPType::Long      => "u32",
            AMQPType::LongLong  => "u64",
            AMQPType::ShortStr  => "String",
            AMQPType::LongStr   => "String",
            AMQPType::Table     => "String", /* FIXME: add a custom type */
            AMQPType::Timestamp => "u64",
        }.to_string()
    }
}

fn camel_name(name: &str) -> String {
    let mut new_word: bool = true;
    name.chars().fold("".to_string(), |mut result, ch| {
        if ch == '-' || ch == '_' || ch == ' ' {
            new_word = true;
            result
        } else {
            result.push(if new_word { ch.to_ascii_uppercase() } else { ch.to_ascii_lowercase() });
            new_word = false;
            result
        }
    })
}

fn snake_name(name: &str) -> String {
    match name {
        "type"   => "amqp_type".to_string(),
        "return" => "amqp_return".to_string(),
        name     => name.replace("-", "_").to_lowercase(),
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AMQPDomain(pub String, pub AMQPType);

impl Codegen for AMQPDomain {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("name".to_string(),       self.0.clone());
        data.insert("snake_name".to_string(), snake_name(&self.0));
        data.insert("type".to_string(),       self.1.to_string());

        handlebars.render("domain", &data).expect("Failed to render domain template")
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AMQPConstant {
    pub name:  String,
    pub value: u16,
    #[serde(rename="class")]
    pub klass: Option<String>,
}

impl AMQPConstant {
    pub fn serialize_class(&self) -> String {
        match self.klass {
            Some(ref klass) => format!("Some(\"{}\".to_string())", klass),
            None            => "None".to_string(),
        }
    }
}

impl Codegen for AMQPConstant {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("name".to_string(),       self.name.clone());
        data.insert("snake_name".to_string(), snake_name(&self.name));
        data.insert("value".to_string(),      format!("{}", self.value));
        data.insert("class".to_string(),      self.serialize_class());

        handlebars.render("constant", &data).expect("Failed to render constant template")
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AMQPClass {
    pub id:         u8,
    pub methods:    Vec<AMQPMethod>,
    pub name:       String,
    pub properties: Option<Vec<AMQPProperty>>,
}

impl Codegen for AMQPClass {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("id".to_string(),         format!("{}", self.id));
        data.insert("methods".to_string(),    self.methods.iter().map(|method| method.codegen(&handlebars)).join("\n"));
        data.insert("name".to_string(),       self.name.clone());
        data.insert("snake_name".to_string(), snake_name(&self.name));
        if let Some(ref properties) = self.properties {
            data.insert("properties".to_string(), properties.iter().map(|prop| prop.codegen(&handlebars)).join("\n"));
        }

        handlebars.render("class", &data).expect("Failed to render class template")
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AMQPMethod {
    pub id:          u8,
    pub arguments:   Vec<AMQPArgument>,
    pub name:        String,
    pub synchronous: Option<bool>,
}

impl Codegen for AMQPMethod {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("id".to_string(),              format!("{}", self.id));
        data.insert("arguments".to_string(),       self.arguments.iter().map(|arg| arg.codegen(&handlebars)).join("\n"));
        data.insert("argument_fields".to_string(), self.arguments.iter().map(|arg| arg.codegen_field()).join("\n"));
        data.insert("name".to_string(),            self.name.clone());
        data.insert("synchronous".to_string(),     format!("{}", self.synchronous.unwrap_or(false)));
        data.insert("camel_name".to_string(),      camel_name(&self.name));
        data.insert("snake_name".to_string(),      snake_name(&self.name));

        handlebars.render("method", &data).expect("Failed to render method template")
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AMQPArgument {
    #[serde(rename="type")]
    pub amqp_type:     Option<AMQPType>,
    pub name:          String,
    #[serde(rename="default-value")]
    pub default_value: Option<Value>,
    pub domain:        Option<String>,
}

impl AMQPArgument {
    fn serialize_default_value(&self) -> String {
        if let Some(ref default_value) = self.default_value {
            let s = default_value.to_string();
            match default_value {
                /* TODO: simplify that, handle Table */
                &Value::String(_) => format!("Some({}.to_string())", s),
                &Value::Number(_) => format!("Some({})", s),
                &Value::Bool(_)   => format!("Some({})", s),
                _                 => "None".to_string(),
            }
        } else {
            "None".to_string()
        }
    }

    fn serialize_domain(&self) -> String {
        if let Some(ref domain) = self.domain {
            format!("Some(\"{}\".to_string())", domain)
        } else {
            "None".to_string()
        }
    }

    fn codegen_field(&self) -> String {
        format!("pub {}: {},", snake_name(&self.name), camel_name(&self.name))
    }
}

impl Codegen for AMQPArgument {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        if let Some(ref amqp_type) = self.amqp_type {
            data.insert("type".to_string(), amqp_type.to_string());
            data.insert("value_field".to_string(), format!("pub value: {},", amqp_type.to_rust_type()));
            data.insert("default_value_method".to_string(), format!("pub fn default_value() -> Option<{}> {{ {} }}", amqp_type.to_rust_type(), &self.serialize_default_value()));
        }
        data.insert("name".to_string(),          self.name.clone());
        data.insert("camel_name".to_string(),    camel_name(&self.name));
        data.insert("snake_name".to_string(),    snake_name(&self.name));
        data.insert("domain".to_string(),        self.serialize_domain());

        handlebars.render("argument", &data).expect("Failed to render argument template")
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AMQPProperty {
    #[serde(rename="type")]
    pub amqp_type: AMQPType,
    pub name:      String,
}

impl Codegen for AMQPProperty {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("type".to_string(),       self.amqp_type.to_string());
        data.insert("rust_type".to_string(),  self.amqp_type.to_rust_type());
        data.insert("name".to_string(),       self.name.clone());
        data.insert("camel_name".to_string(), camel_name(&self.name));

        handlebars.render("property", &data).expect("Failed to render property template")
    }
}

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

    fn specs() -> AMQProtocolDefinition {
        AMQProtocolDefinition {
            name:          "AMQP".to_string(),
            major_version: 0,
            minor_version: 9,
            revision:      1,
            port:          5672,
            copyright:     vec!["Copyright 1\n".to_string(), "Copyright 2".to_string()],
            domains:       vec![AMQPDomain("domain1".to_string(), AMQPType::Octet)],
            constants:     vec![
                AMQPConstant {
                    name:  "constant1".to_string(),
                    value: 128,
                    klass: Some("class1".to_string()),
                }
            ],
            classes:       vec![
                AMQPClass {
                    id:         42,
                    methods:    vec![
                        AMQPMethod {
                            id:          64,
                            arguments:   vec![
                                AMQPArgument {
                                    amqp_type:     Some(AMQPType::LongStr),
                                    name:          "argument1".to_string(),
                                    default_value: Some(Value::String("value1".to_string())),
                                    domain:        Some("domain1".to_string()),
                                }
                            ],
                            name:        "method1".to_string(),
                            synchronous: Some(true),
                        }
                    ],
                    name:       "class1".to_string(),
                    properties: Some(vec![
                        AMQPProperty {
                            amqp_type: AMQPType::LongStr,
                            name:      "property1".to_string(),
                        }
                    ]),
                }
            ],
        }
    }

    fn templates() -> AMQPTemplates {
        AMQPTemplates {
            main:     r#"
{{name}} - {{major_version}}.{{minor_version}}.{{revision}}
{{copyright}}
port {{port}}
{{domains}}
{{constants}}
{{classes}}
"#.to_string(),
            domain:   "{{name}}: {{type}}".to_string(),
            constant: "{{name}}({{class}}) = {{value}}".to_string(),
            klass:    r#"
{{id}} - {{name}}
{{properties}}
{{methods}}
"#.to_string(),
            method:   r#"
{{id}} - {{name}}
synchronous: {{synchronous}}
{{arguments}}
"#.to_string(),
            argument: "{{name}}({{domain}}): {{type}} = {{default_value_method}}".to_string(),
            property: "{{name}}: {{type}}".to_string(),
        }
    }

    #[test]
    fn main_template() {
        assert_eq!(specs().codegen(&templates()), r#"
AMQP - 0.9.1
Copyright 1
Copyright 2
port 5672
domain1: octet
constant1(class1) = 128

42 - class1
property1: longstr

64 - method1
synchronous: true
argument1(Some("domain1".to_string())): longstr = pub fn default_value() -> Option<String> { Some("value1".to_string()) }

"#);
    }
}
<commit_msg>codegen: update expectation in test<commit_after>extern crate handlebars;
extern crate itertools;
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;

use handlebars::Handlebars;
use itertools::Itertools;
use serde_json::Value;
use std::collections::BTreeMap;
use std::ascii::AsciiExt;

trait Codegen {
    fn codegen(&self, handlebars: &Handlebars) -> String;
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AMQProtocolDefinition {
    pub name:          String,
    #[serde(rename="major-version")]
    pub major_version: u8,
    #[serde(rename="minor-version")]
    pub minor_version: u8,
    pub revision:      u8,
    pub port:          u32,
    pub copyright:     Vec<String>,
    pub domains:       Vec<AMQPDomain>,
    pub constants:     Vec<AMQPConstant>,
    pub classes:       Vec<AMQPClass>,
}

impl AMQProtocolDefinition {
    pub fn load() -> AMQProtocolDefinition {
        let specs = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/specs/amqp-rabbitmq-0.9.1.json"));

        serde_json::from_str::<AMQProtocolDefinition>(specs).expect("Failed to parse AMQP specs file")
    }

    pub fn codegen(&self, templates: &AMQPTemplates) -> String {
        let handlebars = register_templates(templates);
        let mut data   = BTreeMap::new();

        data.insert("name".to_string(),          self.name.clone());
        data.insert("major_version".to_string(), format!("{}", self.major_version));
        data.insert("minor_version".to_string(), format!("{}", self.minor_version));
        data.insert("revision".to_string(),      format!("{}", self.revision));
        data.insert("port".to_string(),          format!("{}", self.port));
        data.insert("copyright".to_string(),     self.copyright.iter().join(""));
        data.insert("domains".to_string(),       self.domains.iter().map(|domain| domain.codegen(&handlebars)).join("\n"));
        data.insert("constants".to_string(),     self.constants.iter().map(|constant| constant.codegen(&handlebars)).join("\n"));
        data.insert("classes".to_string(),       self.classes.iter().map(|klass| klass.codegen(&handlebars)).join("\n"));

        handlebars.render("main", &data).expect("Failed to render main template")
    }

    pub fn codegen_full(self, full_template: &str) -> String {
        let mut handlebars = Handlebars::new();
        let mut data = BTreeMap::new();

        handlebars.register_escape_fn(handlebars::no_escape);
        handlebars.register_template_string("full", full_template).expect("Failed to register full template");

        data.insert("specs".to_string(), self);

        handlebars.render("full", &data).expect("Failed to render full template")
    }
}

fn register_templates(templates: &AMQPTemplates) -> Handlebars {
    let mut handlebars = Handlebars::new();

    handlebars.register_escape_fn(handlebars::no_escape);

    handlebars.register_template_string("main",     &templates.main).expect("Failed to register main template");
    handlebars.register_template_string("domain",   &templates.domain).expect("Failed to register domain template");
    handlebars.register_template_string("constant", &templates.constant).expect("Failed to register constant template");
    handlebars.register_template_string("class",    &templates.klass).expect("Failed to register class template");
    handlebars.register_template_string("method",   &templates.method).expect("Failed to register method template");
    handlebars.register_template_string("argument", &templates.argument).expect("Failed to register argument template");
    handlebars.register_template_string("property", &templates.property).expect("Failed to register property template");

    handlebars
}

pub struct AMQPTemplates {
    pub main:     String,
    pub domain:   String,
    pub constant: String,
    pub klass:    String,
    pub method:   String,
    pub argument: String,
    pub property: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub enum AMQPType {
    #[serde(rename="bit")]
    Bit,
    #[serde(rename="octet")]
    Octet,
    #[serde(rename="short")]
    Short,
    #[serde(rename="long")]
    Long,
    #[serde(rename="longlong")]
    LongLong,
    #[serde(rename="shortstr")]
    ShortStr,
    #[serde(rename="longstr")]
    LongStr,
    #[serde(rename="table")]
    Table,
    #[serde(rename="timestamp")]
    Timestamp,
}

impl AMQPType {
    fn to_string(&self) -> String {
        match *self {
            AMQPType::Bit       => "bit",
            AMQPType::Octet     => "octet",
            AMQPType::Short     => "short",
            AMQPType::Long      => "long",
            AMQPType::LongLong  => "longlong",
            AMQPType::ShortStr  => "shortstr",
            AMQPType::LongStr   => "longstr",
            AMQPType::Table     => "table",
            AMQPType::Timestamp => "timestamp",
        }.to_string()
    }

    fn to_rust_type(&self) -> String {
        match *self {
            AMQPType::Bit       => "bool",
            AMQPType::Octet     => "u8",
            AMQPType::Short     => "u16",
            AMQPType::Long      => "u32",
            AMQPType::LongLong  => "u64",
            AMQPType::ShortStr  => "String",
            AMQPType::LongStr   => "String",
            AMQPType::Table     => "String", /* FIXME: add a custom type */
            AMQPType::Timestamp => "u64",
        }.to_string()
    }
}

fn camel_name(name: &str) -> String {
    let mut new_word: bool = true;
    name.chars().fold("".to_string(), |mut result, ch| {
        if ch == '-' || ch == '_' || ch == ' ' {
            new_word = true;
            result
        } else {
            result.push(if new_word { ch.to_ascii_uppercase() } else { ch.to_ascii_lowercase() });
            new_word = false;
            result
        }
    })
}

fn snake_name(name: &str) -> String {
    match name {
        "type"   => "amqp_type".to_string(),
        "return" => "amqp_return".to_string(),
        name     => name.replace("-", "_").to_lowercase(),
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AMQPDomain(pub String, pub AMQPType);

impl Codegen for AMQPDomain {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("name".to_string(),       self.0.clone());
        data.insert("snake_name".to_string(), snake_name(&self.0));
        data.insert("type".to_string(),       self.1.to_string());

        handlebars.render("domain", &data).expect("Failed to render domain template")
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AMQPConstant {
    pub name:  String,
    pub value: u16,
    #[serde(rename="class")]
    pub klass: Option<String>,
}

impl AMQPConstant {
    pub fn serialize_class(&self) -> String {
        match self.klass {
            Some(ref klass) => format!("Some(\"{}\".to_string())", klass),
            None            => "None".to_string(),
        }
    }
}

impl Codegen for AMQPConstant {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("name".to_string(),       self.name.clone());
        data.insert("snake_name".to_string(), snake_name(&self.name));
        data.insert("value".to_string(),      format!("{}", self.value));
        data.insert("class".to_string(),      self.serialize_class());

        handlebars.render("constant", &data).expect("Failed to render constant template")
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AMQPClass {
    pub id:         u8,
    pub methods:    Vec<AMQPMethod>,
    pub name:       String,
    pub properties: Option<Vec<AMQPProperty>>,
}

impl Codegen for AMQPClass {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("id".to_string(),         format!("{}", self.id));
        data.insert("methods".to_string(),    self.methods.iter().map(|method| method.codegen(&handlebars)).join("\n"));
        data.insert("name".to_string(),       self.name.clone());
        data.insert("snake_name".to_string(), snake_name(&self.name));
        if let Some(ref properties) = self.properties {
            data.insert("properties".to_string(), properties.iter().map(|prop| prop.codegen(&handlebars)).join("\n"));
        }

        handlebars.render("class", &data).expect("Failed to render class template")
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AMQPMethod {
    pub id:          u8,
    pub arguments:   Vec<AMQPArgument>,
    pub name:        String,
    pub synchronous: Option<bool>,
}

impl Codegen for AMQPMethod {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("id".to_string(),              format!("{}", self.id));
        data.insert("arguments".to_string(),       self.arguments.iter().map(|arg| arg.codegen(&handlebars)).join("\n"));
        data.insert("argument_fields".to_string(), self.arguments.iter().map(|arg| arg.codegen_field()).join("\n"));
        data.insert("name".to_string(),            self.name.clone());
        data.insert("synchronous".to_string(),     format!("{}", self.synchronous.unwrap_or(false)));
        data.insert("camel_name".to_string(),      camel_name(&self.name));
        data.insert("snake_name".to_string(),      snake_name(&self.name));

        handlebars.render("method", &data).expect("Failed to render method template")
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AMQPArgument {
    #[serde(rename="type")]
    pub amqp_type:     Option<AMQPType>,
    pub name:          String,
    #[serde(rename="default-value")]
    pub default_value: Option<Value>,
    pub domain:        Option<String>,
}

impl AMQPArgument {
    fn serialize_default_value(&self) -> String {
        if let Some(ref default_value) = self.default_value {
            let s = default_value.to_string();
            match default_value {
                /* TODO: simplify that, handle Table */
                &Value::String(_) => format!("Some({}.to_string())", s),
                &Value::Number(_) => format!("Some({})", s),
                &Value::Bool(_)   => format!("Some({})", s),
                _                 => "None".to_string(),
            }
        } else {
            "None".to_string()
        }
    }

    fn serialize_domain(&self) -> String {
        if let Some(ref domain) = self.domain {
            format!("Some(\"{}\".to_string())", domain)
        } else {
            "None".to_string()
        }
    }

    fn codegen_field(&self) -> String {
        format!("pub {}: {},", snake_name(&self.name), camel_name(&self.name))
    }
}

impl Codegen for AMQPArgument {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        if let Some(ref amqp_type) = self.amqp_type {
            data.insert("type".to_string(), amqp_type.to_string());
            data.insert("value_field".to_string(), format!("pub value: {},", amqp_type.to_rust_type()));
            data.insert("default_value_method".to_string(), format!("pub fn default_value() -> Option<{}> {{ {} }}", amqp_type.to_rust_type(), &self.serialize_default_value()));
        }
        data.insert("name".to_string(),          self.name.clone());
        data.insert("camel_name".to_string(),    camel_name(&self.name));
        data.insert("snake_name".to_string(),    snake_name(&self.name));
        data.insert("domain".to_string(),        self.serialize_domain());

        handlebars.render("argument", &data).expect("Failed to render argument template")
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AMQPProperty {
    #[serde(rename="type")]
    pub amqp_type: AMQPType,
    pub name:      String,
}

impl Codegen for AMQPProperty {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("type".to_string(),       self.amqp_type.to_string());
        data.insert("rust_type".to_string(),  self.amqp_type.to_rust_type());
        data.insert("name".to_string(),       self.name.clone());
        data.insert("camel_name".to_string(), camel_name(&self.name));

        handlebars.render("property", &data).expect("Failed to render property template")
    }
}

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

    fn specs() -> AMQProtocolDefinition {
        AMQProtocolDefinition {
            name:          "AMQP".to_string(),
            major_version: 0,
            minor_version: 9,
            revision:      1,
            port:          5672,
            copyright:     vec!["Copyright 1\n".to_string(), "Copyright 2".to_string()],
            domains:       vec![AMQPDomain("domain1".to_string(), AMQPType::Octet)],
            constants:     vec![
                AMQPConstant {
                    name:  "constant1".to_string(),
                    value: 128,
                    klass: Some("class1".to_string()),
                }
            ],
            classes:       vec![
                AMQPClass {
                    id:         42,
                    methods:    vec![
                        AMQPMethod {
                            id:          64,
                            arguments:   vec![
                                AMQPArgument {
                                    amqp_type:     Some(AMQPType::LongStr),
                                    name:          "argument1".to_string(),
                                    default_value: Some(Value::String("value1".to_string())),
                                    domain:        Some("domain1".to_string()),
                                }
                            ],
                            name:        "method1".to_string(),
                            synchronous: Some(true),
                        }
                    ],
                    name:       "class1".to_string(),
                    properties: Some(vec![
                        AMQPProperty {
                            amqp_type: AMQPType::LongStr,
                            name:      "property1".to_string(),
                        }
                    ]),
                }
            ],
        }
    }

    fn templates() -> AMQPTemplates {
        AMQPTemplates {
            main:     r#"
{{name}} - {{major_version}}.{{minor_version}}.{{revision}}
{{copyright}}
port {{port}}
{{domains}}
{{constants}}
{{classes}}
"#.to_string(),
            domain:   "{{name}}: {{type}}".to_string(),
            constant: "{{name}}({{class}}) = {{value}}".to_string(),
            klass:    r#"
{{id}} - {{name}}
{{properties}}
{{methods}}
"#.to_string(),
            method:   r#"
{{id}} - {{name}}
synchronous: {{synchronous}}
{{arguments}}
"#.to_string(),
            argument: "{{name}}({{domain}}): {{type}} = {{default_value_method}}".to_string(),
            property: "{{name}}: {{type}}".to_string(),
        }
    }

    #[test]
    fn main_template() {
        assert_eq!(specs().codegen(&templates()), r#"
AMQP - 0.9.1
Copyright 1
Copyright 2
port 5672
domain1: octet
constant1(Some("class1".to_string())) = 128

42 - class1
property1: longstr

64 - method1
synchronous: true
argument1(Some("domain1".to_string())): longstr = pub fn default_value() -> Option<String> { Some("value1".to_string()) }

"#);
    }
}
<|endoftext|>


<commit_before>extern crate itertools;
extern crate time;

use itertools::Itertools;
use time::PreciseTime;

fn check_sum_zero(v: Vec<i32>) -> bool {
    let int_list = v;

    for i in (1..int_list.len()+1).rev() {

        let iter = int_list.iter();

        for item in iter.combinations(i) {
            let a = item.into_iter();
            let sum: i32 = a.sum();

            if sum == 0 {
                return true;
            }
        }
    }
    return false;
}

fn main() {
    // Main function only for benchmarking Optional bonus 2
    let start = PreciseTime::now();
    println!("Running optional bonus 2 test...");

    let list_1 = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24];

    println!("Result: {:?}", check_sum_zero(list_1));

    let end = PreciseTime::now();

    println!("Second to finish: {}", start.to(end));

}

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

    #[test]
    fn base_examples_ok() {

        let list_ok = [vec![-5, -3, -1, 2, 4, 6], vec![-1, 1],
            vec![-97364, -71561, -69336, 19675, 71561, 97863],
            vec![-53974, -39140, -36561, -23935, -15680, 0], vec![-2, 2, 3]];

        for list_vector in list_ok.iter() {
            assert_eq!(true, check_sum_zero(list_vector.to_vec()));
        }

    }

    #[test]
    fn base_examples_no_ok() {
        let list_no_ok = [vec![1, 2, 3], vec![]];

        for list_vector in list_no_ok.iter() {
            assert_eq!(false, check_sum_zero(list_vector.to_vec()));
        }
    }

    #[test]
    fn optional_bonus_ok() {
        let list_ok = [vec![0], vec![-3, 1, 2],
            vec![-98634, -86888, -48841, -40483, 2612, 9225, 17848, 71967, 84319, 88875]];

        for list_vector in list_ok.iter() {
            assert_eq!(true, check_sum_zero(list_vector.to_vec()));
        }
    }

    #[test]
    fn optional_bonus_examples_no_ok() {
        let list_no_ok = [vec![-83314, -82838, -80120, -63468, -62478, -59378, -56958, -50061, -34791, -32264, -21928, -14988, 23767, 24417, 26403, 26511, 36399, 78055],
            vec![-92953, -91613, -89733, -50673, -16067, -9172, 8852, 30883, 46690, 46968, 56772, 58703, 59150, 78476, 84413, 90106, 94777, 95148],
            vec![-94624, -86776, -85833, -80822, -71902, -54562, -38638, -26483, -20207, -1290, 12414, 12627, 19509, 30894, 32505, 46825, 50321, 69294],
            vec![-83964, -81834, -78386, -70497, -69357, -61867, -49127, -47916, -38361, -35772, -29803, -15343, 6918, 19662, 44614, 66049, 93789, 95405],
            vec![-68808, -58968, -45958, -36013, -32810, -28726, -13488, 3986, 26342, 29245, 30686, 47966, 58352, 68610, 74533, 77939, 80520, 87195]];

        for list_vector in list_no_ok.iter() {
            assert_eq!(false, check_sum_zero(list_vector.to_vec()));
        }
    }

    #[test]
    fn optional_bonus_examples_ok() {
        let list_ok = [vec![-97162, -95761, -94672, -87254, -57207, -22163, -20207, -1753, 11646, 13652, 14572, 30580, 52502, 64282, 74896, 83730, 89889, 92200],
            vec![-93976, -93807, -64604, -59939, -44394, -36454, -34635, -16483, 267, 3245, 8031, 10622, 44815, 46829, 61689, 65756, 69220, 70121],
            vec![-92474, -61685, -55348, -42019, -35902, -7815, -5579, 4490, 14778, 19399, 34202, 46624, 55800, 57719, 60260, 71511, 75665, 82754],
            vec![-85029, -84549, -82646, -80493, -73373, -57478, -56711, -42456, -38923, -29277, -3685, -3164, 26863, 29890, 37187, 46607, 69300, 84808],
            vec![-87565, -71009, -49312, -47554, -27197, 905, 2839, 8657, 14622, 32217, 35567, 38470, 46885, 59236, 64704, 82944, 86902, 90487]];

        for list_vector in list_ok.iter() {
            assert_eq!(true, check_sum_zero(list_vector.to_vec()));
        }
    }
}<commit_msg>Add 1 step<commit_after>extern crate itertools;
extern crate time;

use itertools::Itertools;
use time::PreciseTime;

fn check_sum_zero(v: Vec<i32>) -> bool {
    let int_list = v;

    for i in (1..int_list.len()+1).rev() {

        let iter = int_list.iter();

        for item in iter.combinations(i) {
            let a = item.into_iter();
            let sum: i32 = a.sum();

            if sum == 0 {
                return true;
            }
        }
    }
    return false;
}

fn main() {
    // Main function only for benchmarking Optional bonus 2
    let start = PreciseTime::now();
    println!("Running optional bonus 2 test...");

    let list_1 = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25];

    println!("Result: {:?}", check_sum_zero(list_1));

    let end = PreciseTime::now();

    println!("Second to finish: {}", start.to(end));

}

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

    #[test]
    fn base_examples_ok() {

        let list_ok = [vec![-5, -3, -1, 2, 4, 6], vec![-1, 1],
            vec![-97364, -71561, -69336, 19675, 71561, 97863],
            vec![-53974, -39140, -36561, -23935, -15680, 0], vec![-2, 2, 3]];

        for list_vector in list_ok.iter() {
            assert_eq!(true, check_sum_zero(list_vector.to_vec()));
        }

    }

    #[test]
    fn base_examples_no_ok() {
        let list_no_ok = [vec![1, 2, 3], vec![]];

        for list_vector in list_no_ok.iter() {
            assert_eq!(false, check_sum_zero(list_vector.to_vec()));
        }
    }

    #[test]
    fn optional_bonus_ok() {
        let list_ok = [vec![0], vec![-3, 1, 2],
            vec![-98634, -86888, -48841, -40483, 2612, 9225, 17848, 71967, 84319, 88875]];

        for list_vector in list_ok.iter() {
            assert_eq!(true, check_sum_zero(list_vector.to_vec()));
        }
    }

    #[test]
    fn optional_bonus_examples_no_ok() {
        let list_no_ok = [vec![-83314, -82838, -80120, -63468, -62478, -59378, -56958, -50061, -34791, -32264, -21928, -14988, 23767, 24417, 26403, 26511, 36399, 78055],
            vec![-92953, -91613, -89733, -50673, -16067, -9172, 8852, 30883, 46690, 46968, 56772, 58703, 59150, 78476, 84413, 90106, 94777, 95148],
            vec![-94624, -86776, -85833, -80822, -71902, -54562, -38638, -26483, -20207, -1290, 12414, 12627, 19509, 30894, 32505, 46825, 50321, 69294],
            vec![-83964, -81834, -78386, -70497, -69357, -61867, -49127, -47916, -38361, -35772, -29803, -15343, 6918, 19662, 44614, 66049, 93789, 95405],
            vec![-68808, -58968, -45958, -36013, -32810, -28726, -13488, 3986, 26342, 29245, 30686, 47966, 58352, 68610, 74533, 77939, 80520, 87195]];

        for list_vector in list_no_ok.iter() {
            assert_eq!(false, check_sum_zero(list_vector.to_vec()));
        }
    }

    #[test]
    fn optional_bonus_examples_ok() {
        let list_ok = [vec![-97162, -95761, -94672, -87254, -57207, -22163, -20207, -1753, 11646, 13652, 14572, 30580, 52502, 64282, 74896, 83730, 89889, 92200],
            vec![-93976, -93807, -64604, -59939, -44394, -36454, -34635, -16483, 267, 3245, 8031, 10622, 44815, 46829, 61689, 65756, 69220, 70121],
            vec![-92474, -61685, -55348, -42019, -35902, -7815, -5579, 4490, 14778, 19399, 34202, 46624, 55800, 57719, 60260, 71511, 75665, 82754],
            vec![-85029, -84549, -82646, -80493, -73373, -57478, -56711, -42456, -38923, -29277, -3685, -3164, 26863, 29890, 37187, 46607, 69300, 84808],
            vec![-87565, -71009, -49312, -47554, -27197, 905, 2839, 8657, 14622, 32217, 35567, 38470, 46885, 59236, 64704, 82944, 86902, 90487]];

        for list_vector in list_ok.iter() {
            assert_eq!(true, check_sum_zero(list_vector.to_vec()));
        }
    }
}<|endoftext|>


<commit_before>#[inline]
pub fn bits_0_3(n: u16) -> u8 {
    n as u8 & 0b_111
}

#[inline]
pub fn bits_0_7(n: u16) -> u8 {
    (n & 0b_111_1111) as u8
}

#[inline]
pub fn bits_0_8(n: u16) -> u8 {
    (n & 0b_1111_1111) as u8
}

#[inline]
pub fn bits_0_11(n: u16) -> u16 {
    n & 0b_11_1111_1111
}

#[inline]
pub fn bits_3_6(n: u16) -> u8 {
    ((n & 0b_111_000) >> 3) as u8
}

#[inline]
pub fn bits_3_7(n: u16) -> u8 {
    ((n & 0b_1111_000) >> 3) as u8
}

#[inline]
pub fn bits_6_9(n: u16) -> u8 {
    ((n & 0b_111_000_000) >> 6) as u8
}

#[inline]
pub fn bits_8_11(n: u16) -> u8 {
    ((n & 0b_111_00_000_000) >> 8) as u8
}

#[inline]
pub fn bits_6_11(n: u16) -> u8 {
    ((n & 0b_11111_000_000) >> 6) as u8
}

<commit_msg>Add more bit decoding funcs<commit_after>#[inline]
pub fn bits_0_3(n: u16) -> u8 {
    n as u8 & 0b_111
}

#[inline]
pub fn bits_0_4(n: u16) -> u8 {
    n as u8 & 0b_1111
}

#[inline]
pub fn bits_0_7(n: u16) -> u8 {
    (n & 0b_111_1111) as u8
}

#[inline]
pub fn bits_0_8(n: u16) -> u8 {
    (n & 0b_1111_1111) as u8
}

#[inline]
pub fn bit_0(n: u16) -> u8 {
    ((n & 0b_0000_0001) >> 0) as u8
}

#[inline]
pub fn bit_1(n: u16) -> u8 {
    ((n & 0b_0000_0010) >> 1) as u8
}

#[inline]
pub fn bit_2(n: u16) -> u8 {
    ((n & 0b_0000_0100) >> 2) as u8
}

#[inline]
pub fn bit_3(n: u16) -> u8 {
    ((n & 0b_0000_1000) >> 3) as u8
}

#[inline]
pub fn bit_4(n: u16) -> u8 {
    ((n & 0b_0001_0000) >> 4) as u8
}

#[inline]
pub fn bit_5(n: u16) -> u8 {
    ((n & 0b_0010_0000) >> 5) as u8
}

#[inline]
pub fn bit_6(n: u16) -> u8 {
    ((n & 0b_0100_0000) >> 6) as u8
}

#[inline]
pub fn bit_7(n: u16) -> u8 {
    ((n & 0b_1000_0000) >> 7) as u8
}

#[inline]
pub fn bit_8(n: u16) -> u8 {
    ((n & 0b_1_0000_0000) >> 8) as u8
}

#[inline]
pub fn bits_0_11(n: u16) -> u16 {
    n & 0b_11_1111_1111
}

#[inline]
pub fn bits_3_6(n: u16) -> u8 {
    ((n & 0b_111_000) >> 3) as u8
}

#[inline]
pub fn bits_3_7(n: u16) -> u8 {
    ((n & 0b_1111_000) >> 3) as u8
}

#[inline]
pub fn bits_6_9(n: u16) -> u8 {
    ((n & 0b_111_000_000) >> 6) as u8
}

#[inline]
pub fn bits_8_11(n: u16) -> u8 {
    ((n & 0b_111_00_000_000) >> 8) as u8
}

#[inline]
pub fn bits_8_12(n: u16) -> u8 {
    ((n & 0b_1111_00_000_000) >> 8) as u8
}

#[inline]
pub fn bits_6_11(n: u16) -> u8 {
    ((n & 0b_11111_000_000) >> 6) as u8
}
<|endoftext|>


<commit_before>//! This is the actual Bot module. For ergonomic reasons there is a RcBot which composes the real
//! bot as an underlying field. You should always use RcBot.

use error::Error;
use objects;

use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::rc::Rc;
use std::str;
use std::sync::{Arc, Mutex};
use std::time::Duration;

use curl::easy::{Easy, List};
use futures::sync::mpsc;
use futures::sync::mpsc::UnboundedSender;
use futures::{stream, Future, IntoFuture, Stream};
use serde::de::DeserializeOwned;
use serde_json;
use tokio_core::reactor::{Handle, Interval};
use tokio_curl::Session;

/// A clonable, single threaded bot
///
/// The outer API gets implemented on RcBot
#[derive(Clone)]
pub struct RcBot {
    pub inner: Rc<Bot>,
}

impl RcBot {
    pub fn new<'a>(handle: Handle, key: &str) -> impl Future<Item = RcBot, Error = Error> + 'a {
        use functions::FunctionGetMe;
        let bot = RcBot {
            inner: Rc::new(Bot::new(handle, key)),
        };
        bot.get_me().send().map(|(mut bot, me)| {
            Rc::get_mut(&mut bot.inner).as_mut().unwrap().id = me.id;
            Rc::get_mut(&mut bot.inner).as_mut().unwrap().username = me.username.unwrap();
            bot
        })
    }
}

/// The main bot structure
pub struct Bot {
    pub key: String,
    pub handle: Handle,
    pub last_id: Cell<u32>,
    pub update_interval: Cell<u64>,
    pub handlers: RefCell<HashMap<String, UnboundedSender<(RcBot, objects::Message)>>>,
    pub session: Session,
    pub username: String,
    pub id: i64,
}

impl Bot {
    pub fn new(handle: Handle, key: &str) -> Bot {
        Bot {
            handle: handle.clone(),
            key: key.into(),
            last_id: Cell::new(0),
            update_interval: Cell::new(1000),
            handlers: RefCell::new(HashMap::new()),
            session: Session::new(handle.clone()),
            username: String::new(),
            id: 0,
        }
    }

    /// Creates a new request and adds a JSON message to it. The returned Future contains a the
    /// reply as a string.  This method should be used if no file is added because a JSON msg is
    /// always compacter than a formdata one.
    pub fn fetch_json<'a, T: DeserializeOwned + 'a>(
        &self,
        func: &str,
        msg: &str,
    ) -> impl Future<Item = T, Error = Error> + 'a {
        debug!("Send JSON: {}", msg);

        let mut header = List::new();
        header.append("Content-Type: application/json").unwrap();

        let mut req = Easy::new();
        req.http_headers(header).unwrap();
        req.post_fields_copy(msg.as_bytes()).unwrap();
        req.post(true).unwrap();

        self.fetch(func, req)
    }

    /// calls cURL and parses the result for an error
    pub fn fetch<'a, T: DeserializeOwned + 'a>(
        &self,
        func: &str,
        mut req: Easy,
    ) -> impl Future<Item = T, Error = Error> + 'a {
        let result = Arc::new(Mutex::new(Vec::new()));

        req.url(&format!(
            "https://api.telegram.org/bot{}/{}",
            self.key, func
        )).unwrap();

        let r2 = result.clone();
        req.write_function(move |data| {
            r2.lock().unwrap().extend_from_slice(data);
            Ok(data.len())
        }).unwrap();

        self.session
            .perform(req)
            .map_err(|e| e.into())
            .and_then(move |_| {
                let response = result.lock().unwrap();
                let response = str::from_utf8(&response).unwrap();
                let response: Response<T> = serde_json::from_str(&response)?;
                if response.ok {
                    Ok(response.result.unwrap())
                } else {
                    Err(Error::Telegram(
                        response.error_code.unwrap(),
                        response.description.unwrap(),
                        response.parameters,
                    ))
                }
            })
    }
}

#[derive(Deserialize)]
struct Response<T> {
    ok: bool,
    result: Option<T>,
    error_code: Option<u32>,
    description: Option<String>,
    parameters: Option<objects::ResponseParameters>,
}

impl RcBot {
    /// Sets the update interval to an integer in milliseconds
    pub fn update_interval(self, interval: u64) -> RcBot {
        self.inner.update_interval.set(interval);

        self
    }

    /// Creates a new command and returns a stream which
    /// will yield a message when the command is send
    pub fn new_cmd(
        &self,
        cmd: &str,
    ) -> impl Stream<Item = (RcBot, objects::Message), Error = Error> {
        let (sender, receiver) = mpsc::unbounded();

        self.inner.handlers.borrow_mut().insert(cmd.into(), sender);

        receiver.map_err(|_| Error::Unknown)
    }

    /// Register a new commnd
    pub fn register<T>(&self, hnd: T)
    where
        T: Stream + 'static,
    {
        self.inner.handle.spawn(
            hnd.for_each(|_| Ok(()))
                .into_future()
                .map(|_| ())
                .map_err(|_| ()),
        );
    }

    /// The main update loop, the update function is called every update_interval milliseconds
    /// When an update is available the last_id will be updated and the message is filtered
    /// for commands
    /// The message is forwarded to the returned stream if no command was found
    pub fn get_stream<'a>(
        &'a self,
    ) -> impl Stream<Item = (RcBot, objects::Update), Error = Error> + 'a {
        use functions::*;

        Interval::new(
            Duration::from_millis(self.inner.update_interval.get()),
            &self.inner.handle,
        ).unwrap()
            .map_err(|_| Error::Unknown)
            .and_then(move |_| {
                self.get_updates()
                    .offset(self.inner.last_id.get())
                    .timeout(60)
                    .send()
            })
            .map(|(_, x)| stream::iter_ok(x.0))
            .flatten()
            .and_then(move |x| {
                if self.inner.last_id.get() < x.update_id as u32 + 1 {
                    self.inner.last_id.set(x.update_id as u32 + 1);
                }

                Ok(x)
            })
            .filter_map(move |mut val| {
                debug!("Got an update from Telegram: {:?}", val);
                let mut forward: Option<String> = None;

                if let Some(ref mut message) = val.message {
                    if let Some(text) = message.text.clone() {
                        let mut content = text.split_whitespace();
                        if let Some(cmd) = content.next() {
                            let s: Vec<&str> = cmd.split("@").take(2).collect();
                            if s.len() > 0 && (s.len() < 2 || s[1] == self.inner.username)
                                && self.inner.handlers.borrow().contains_key(s[0])
                            {
                                message.text = Some(content.collect::<Vec<&str>>().join(" "));

                                forward = Some(s[0].into());
                            }
                        }
                    }
                }

                if let Some(cmd) = forward {
                    if let Some(sender) = self.inner.handlers.borrow_mut().get_mut(&cmd) {
                        sender
                            .unbounded_send((self.clone(), val.message.unwrap()))
                            .unwrap();
                    }
                    return None;
                } else {
                    return Some((self.clone(), val));
                }
            })
    }
}
<commit_msg>telebot: Skip processed updates from Telegram<commit_after>//! This is the actual Bot module. For ergonomic reasons there is a RcBot which composes the real
//! bot as an underlying field. You should always use RcBot.

use error::Error;
use objects;

use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::rc::Rc;
use std::str;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};

use curl::easy::{Easy, List};
use futures::sync::mpsc;
use futures::sync::mpsc::UnboundedSender;
use futures::{stream, Future, IntoFuture, Stream};
use serde::de::DeserializeOwned;
use serde_json;
use tokio_core::reactor::{Handle, Interval};
use tokio_curl::Session;

const UPDATE_ID_EXPIRATION: Duration = Duration::from_secs(604800);

/// A clonable, single threaded bot
///
/// The outer API gets implemented on RcBot
#[derive(Clone)]
pub struct RcBot {
    pub inner: Rc<Bot>,
}

impl RcBot {
    pub fn new<'a>(handle: Handle, key: &str) -> impl Future<Item = RcBot, Error = Error> + 'a {
        use functions::FunctionGetMe;
        let bot = RcBot {
            inner: Rc::new(Bot::new(handle, key)),
        };
        bot.get_me().send().map(|(mut bot, me)| {
            Rc::get_mut(&mut bot.inner).as_mut().unwrap().id = me.id;
            Rc::get_mut(&mut bot.inner).as_mut().unwrap().username = me.username.unwrap();
            bot
        })
    }
}

/// The main bot structure
pub struct Bot {
    pub key: String,
    pub handle: Handle,
    pub last_id: Cell<u32>,
    pub timestamp: Cell<Instant>,
    pub update_interval: Cell<u64>,
    pub handlers: RefCell<HashMap<String, UnboundedSender<(RcBot, objects::Message)>>>,
    pub session: Session,
    pub username: String,
    pub id: i64,
}

impl Bot {
    pub fn new(handle: Handle, key: &str) -> Bot {
        Bot {
            handle: handle.clone(),
            key: key.into(),
            last_id: Cell::new(0),
            timestamp: Cell::new(Instant::now()),
            update_interval: Cell::new(1000),
            handlers: RefCell::new(HashMap::new()),
            session: Session::new(handle.clone()),
            username: String::new(),
            id: 0,
        }
    }

    /// Creates a new request and adds a JSON message to it. The returned Future contains a the
    /// reply as a string.  This method should be used if no file is added because a JSON msg is
    /// always compacter than a formdata one.
    pub fn fetch_json<'a, T: DeserializeOwned + 'a>(
        &self,
        func: &str,
        msg: &str,
    ) -> impl Future<Item = T, Error = Error> + 'a {
        debug!("Send JSON: {}", msg);

        let mut header = List::new();
        header.append("Content-Type: application/json").unwrap();

        let mut req = Easy::new();
        req.http_headers(header).unwrap();
        req.post_fields_copy(msg.as_bytes()).unwrap();
        req.post(true).unwrap();

        self.fetch(func, req)
    }

    /// calls cURL and parses the result for an error
    pub fn fetch<'a, T: DeserializeOwned + 'a>(
        &self,
        func: &str,
        mut req: Easy,
    ) -> impl Future<Item = T, Error = Error> + 'a {
        let result = Arc::new(Mutex::new(Vec::new()));

        req.url(&format!(
            "https://api.telegram.org/bot{}/{}",
            self.key, func
        )).unwrap();

        let r2 = result.clone();
        req.write_function(move |data| {
            r2.lock().unwrap().extend_from_slice(data);
            Ok(data.len())
        }).unwrap();

        self.session
            .perform(req)
            .map_err(|e| e.into())
            .and_then(move |_| {
                let response = result.lock().unwrap();
                let response = str::from_utf8(&response).unwrap();
                let response: Response<T> = serde_json::from_str(&response)?;
                if response.ok {
                    Ok(response.result.unwrap())
                } else {
                    Err(Error::Telegram(
                        response.error_code.unwrap(),
                        response.description.unwrap(),
                        response.parameters,
                    ))
                }
            })
    }
}

#[derive(Deserialize)]
struct Response<T> {
    ok: bool,
    result: Option<T>,
    error_code: Option<u32>,
    description: Option<String>,
    parameters: Option<objects::ResponseParameters>,
}

impl RcBot {
    /// Sets the update interval to an integer in milliseconds
    pub fn update_interval(self, interval: u64) -> RcBot {
        self.inner.update_interval.set(interval);

        self
    }

    /// Creates a new command and returns a stream which
    /// will yield a message when the command is send
    pub fn new_cmd(
        &self,
        cmd: &str,
    ) -> impl Stream<Item = (RcBot, objects::Message), Error = Error> {
        let (sender, receiver) = mpsc::unbounded();

        self.inner.handlers.borrow_mut().insert(cmd.into(), sender);

        receiver.map_err(|_| Error::Unknown)
    }

    /// Register a new commnd
    pub fn register<T>(&self, hnd: T)
    where
        T: Stream + 'static,
    {
        self.inner.handle.spawn(
            hnd.for_each(|_| Ok(()))
                .into_future()
                .map(|_| ())
                .map_err(|_| ()),
        );
    }

    /// The main update loop, the update function is called every update_interval milliseconds
    /// When an update is available the last_id will be updated and the message is filtered
    /// for commands
    /// The message is forwarded to the returned stream if no command was found
    pub fn get_stream<'a>(
        &'a self,
    ) -> impl Stream<Item = (RcBot, objects::Update), Error = Error> + 'a {
        use functions::*;

        Interval::new(
            Duration::from_millis(self.inner.update_interval.get()),
            &self.inner.handle,
        ).unwrap()
            .map_err(|_| Error::Unknown)
            .and_then(move |_| {
                self.get_updates()
                    .offset(self.inner.last_id.get())
                    .timeout(60)
                    .send()
            })
            .map(|(_, x)| stream::iter_ok(x.0))
            .flatten()
            .filter(move |x| {
                // If there are no new updates for at least a week, then update_id will be randomly.
                let fresh_update_id = Instant::now().duration_since(self.inner.timestamp.get()) < UPDATE_ID_EXPIRATION;
                let valid_update_id = self.inner.last_id.get() < x.update_id as u32 + 1;
                if !fresh_update_id || valid_update_id {
                    self.inner.timestamp.set(Instant::now());
                    self.inner.last_id.set(x.update_id as u32 + 1);
                }
                !fresh_update_id || valid_update_id
            })
            .filter_map(move |mut val| {
                debug!("Got an update from Telegram: {:?}", val);
                let mut forward: Option<String> = None;

                if let Some(ref mut message) = val.message {
                    if let Some(text) = message.text.clone() {
                        let mut content = text.split_whitespace();
                        if let Some(cmd) = content.next() {
                            let s: Vec<&str> = cmd.split("@").take(2).collect();
                            if s.len() > 0 && (s.len() < 2 || s[1] == self.inner.username)
                                && self.inner.handlers.borrow().contains_key(s[0])
                            {
                                message.text = Some(content.collect::<Vec<&str>>().join(" "));

                                forward = Some(s[0].into());
                            }
                        }
                    }
                }

                if let Some(cmd) = forward {
                    if let Some(sender) = self.inner.handlers.borrow_mut().get_mut(&cmd) {
                        sender
                            .unbounded_send((self.clone(), val.message.unwrap()))
                            .unwrap();
                    }
                    return None;
                } else {
                    return Some((self.clone(), val));
                }
            })
    }
}
<|endoftext|>