<commit_before>use super::{ParserError, ParserResult};
use super::primitives::{PrimitiveIterator, U1, U2, U4};

use std::ops::Deref;
use std::rc::Rc;

macro_rules! generate_constant_pool_retrieval_method {
    ($variant_name:ident, $struct_name:ident, $method_name:ident) => {
        pub fn $method_name(index: usize,
                            constant_pool: &Vec<ConstantPoolItem>)
            -> ParserResult<Rc<$struct_name>> {
                let actual_index = ConstantPoolItem::shift_index(index);

                if let Some(item) = constant_pool.get(actual_index) {
                    match item {
                        &ConstantPoolItem::$variant_name(ref val) => return Ok(val.clone()),
                        item @ _ => {
                            let name = item.to_friendly_name();
                            return Err(ParserError::UnexpectedConstantPoolItem(name))
                        }
                    }
                }

                Err(ParserError::ConstantPoolIndexOutOfBounds(actual_index))
            }

    }
}

#[derive(Debug)]
pub struct ClassInfo {
    pub tag: U1,
    pub name_index: U2,
}

#[derive(Debug)]
pub struct Utf8Info {
    pub tag: U1,
    pub length: U2,
    pub value: String,
}

impl Deref for Utf8Info {
    type Target = str;

    fn deref(&self) -> &str {
        &self.value
    }
}

#[derive(Debug)]
pub enum ConstantPoolItem {
    Class(Rc<ClassInfo>),
    FieldOrMethodOrInterfaceMethod {
        tag: U1,
        class_index: U2,
        name_and_type_index: U2,
    },
    String { tag: U1, string_index: U2 },
    IntegerOrFloat { tag: U1, bytes: U1 },
    LongOrDouble {
        tag: U1,
        high_bytes: U4,
        low_bytes: U4,
    },
    NameAndType {
        tag: U1,
        name_index: U2,
        descriptor_index: U2,
    },
    Utf8(Rc<Utf8Info>),
    MethodHandle {
        tag: U1,
        reference_kind: U1,
        reference_index: U2,
    },
    MethodType { tag: U1, descriptor_index: U2 },
    InvokeDynamic {
        tag: U1,
        bootstrap_method_attr_index: U2,
        name_and_type_index: U2,
    },
}

impl ConstantPoolItem {
    pub fn from<T: PrimitiveIterator>(iter: &mut T) -> ParserResult<ConstantPoolItem> {
        let tag = try!(iter.next_u1());

        match tag {
            1 => {
                let length = try!(iter.next_u2());

                let mut byte_vec = vec![];
                for _ in 0..length {
                    byte_vec.push(try!(iter.next_u1()));
                }

                let value = try!(String::from_utf8(byte_vec));

                Ok(ConstantPoolItem::Utf8(Rc::new(Utf8Info {
                    tag: tag,
                    length: length,
                    value: value,
                })))
            }
            7 => {
                Ok(ConstantPoolItem::Class(Rc::new(ClassInfo {
                    tag: tag,
                    name_index: try!(iter.next_u2()),
                })))
            }
            8 => {
                Ok(ConstantPoolItem::String {
                    tag: tag,
                    string_index: try!(iter.next_u2()),
                })
            }
            9 | 10 | 11 => {
                Ok(ConstantPoolItem::FieldOrMethodOrInterfaceMethod {
                    tag: tag,
                    class_index: try!(iter.next_u2()),
                    name_and_type_index: try!(iter.next_u2()),
                })
            }
            12 => {
                Ok(ConstantPoolItem::NameAndType {
                    tag: tag,
                    name_index: try!(iter.next_u2()),
                    descriptor_index: try!(iter.next_u2()),
                })
            }
            _ => Err(ParserError::UnknownConstantPoolTag(tag)),
        }
    }

    #[cfg_attr(rustfmt, rustfmt_skip)]
    pub fn to_friendly_name(&self) -> &'static str {
        match self {
            &ConstantPoolItem::Utf8(..) => "Utf8",
            &ConstantPoolItem::Class(..) => "Class",
            &ConstantPoolItem::String { .. } => "String",
            &ConstantPoolItem::FieldOrMethodOrInterfaceMethod { .. } =>
                "Field|Method|InterfaceMethod",
                &ConstantPoolItem::NameAndType { .. } => "NameAndType",
                _ => "Not yet implemented",
        }
    }

    generate_constant_pool_retrieval_method!(Class, ClassInfo, retrieve_class_info);
    generate_constant_pool_retrieval_method!(Utf8, Utf8Info, retrieve_utf8_info);

    fn shift_index(unshifted_index: usize) -> usize {
        unshifted_index - 1 // references to the constant pool start from one
    }
}

#[derive(Debug)]
pub struct CodeAttribute {
    pub attribute_name: Rc<Utf8Info>,
    pub max_stack: U2,
    pub max_locals: U2,
    pub code_length: U4,
    pub code: Vec<U1>,
    pub exception_table_length: U2,
    pub exception_table: Vec<ExceptionHandler>,
    pub attributes_count: U2,
    pub attributes: Vec<Attribute>,
}

impl CodeAttribute {
    pub fn from<T: PrimitiveIterator>(attribute_name: Rc<Utf8Info>,
                                      iter: &mut T,
                                      constant_pool: &Vec<ConstantPoolItem>)
                                      -> ParserResult<CodeAttribute> {
        let max_stack = try!(iter.next_u2());
        let max_locals = try!(iter.next_u2());

        let code_length = try!(iter.next_u4());
        let mut code = vec![];
        for _ in 0..code_length {
            code.push(try!(iter.next_u1()));
        }

        let exception_table_length = try!(iter.next_u2());
        let mut exception_table = vec![];
        for _ in 0..exception_table_length {
            exception_table.push(try!(ExceptionHandler::from(iter)));
        }

        let attributes_count = try!(iter.next_u2());
        let mut attributes = vec![];
        for _ in 0..attributes_count {
            attributes.push(try!(Attribute::from(iter, constant_pool)));
        }

        Ok(CodeAttribute {
            attribute_name: attribute_name,
            max_stack: max_stack,
            max_locals: max_locals,
            code_length: code_length,
            code: code,
            exception_table_length: exception_table_length,
            exception_table: exception_table,
            attributes_count: attributes_count,
            attributes: attributes,
        })
    }
}

#[derive(Debug)]
pub struct ExceptionHandler {
    pub start_pc: U2,
    pub end_pc: U2,
    pub handler_pc: U2,
    pub catch_type: U2,
}

impl ExceptionHandler {
    pub fn from<T: PrimitiveIterator>(iter: &mut T) -> ParserResult<ExceptionHandler> {
        let start_pc = try!(iter.next_u2());
        let end_pc = try!(iter.next_u2());
        let handler_pc = try!(iter.next_u2());
        let catch_type = try!(iter.next_u2());

        Ok(ExceptionHandler {
            start_pc: start_pc,
            end_pc: end_pc,
            handler_pc: handler_pc,
            catch_type: catch_type,
        })
    }
}

#[derive(Debug)]
pub enum Attribute {
    Code(Rc<CodeAttribute>),
    Unknown {
        attribute_name: Rc<Utf8Info>,
        info: Vec<U1>,
    },
}

impl Attribute {
    pub fn from<T: PrimitiveIterator>(iter: &mut T,
                                      constant_pool: &Vec<ConstantPoolItem>)
                                      -> ParserResult<Attribute> {
        let attribute_name_index = try!(iter.next_u2());
        let attribute_name =
            try!(ConstantPoolItem::retrieve_utf8_info(attribute_name_index as usize,
                                                      constant_pool));

        let attribute_length = try!(iter.next_u4());

        match &**attribute_name {
            "Code" => {
                Ok(Attribute::Code(Rc::new(try!(CodeAttribute::from(attribute_name,
                                                                    iter,
                                                                    constant_pool)))))
            }
            _ => {
                let mut info = vec![];
                for _ in 0..attribute_length {
                    info.push(try!(iter.next_u1()));
                }

                Ok(Attribute::Unknown {
                    attribute_name: attribute_name,
                    info: info,
                })
            }
        }
    }
}

macro_rules! generate_method_or_field_parser_impl {
    ($impl_name:ident) => {
        impl $impl_name {
            pub fn from<T: PrimitiveIterator>(iter: &mut T,
                                              constant_pool: &Vec<ConstantPoolItem>)
                -> ParserResult<$impl_name> {
                    let access_flags = try!(iter.next_u2());

                    let name_index = try!(iter.next_u2());
                    let name = try!(ConstantPoolItem::retrieve_utf8_info(name_index as usize,
                                                                         constant_pool));

                    let descriptor_index = try!(iter.next_u2());
                    let descriptor = try!(ConstantPoolItem::retrieve_utf8_info(
                            descriptor_index as usize,
                            constant_pool));

                    let attributes_count = try!(iter.next_u2());
                    let mut attributes = vec![];
                    for _ in 0..attributes_count {
                        attributes.push(Rc::new(try!(Attribute::from(iter, constant_pool))));
                    }

                    Ok($impl_name {
                        access_flags: access_flags,
                        name: name,
                        descriptor: descriptor,
                        attributes_count: attributes_count,
                        attributes: attributes,
                    })

                }
        }
    }
}

#[derive(Debug)]
pub struct Field {
    pub access_flags: U2,
    pub name: Rc<Utf8Info>,
    pub descriptor: Rc<Utf8Info>,
    pub attributes_count: U2,
    pub attributes: Vec<Rc<Attribute>>,
}

#[derive(Debug)]
pub struct Method {
    pub access_flags: U2,
    pub name: Rc<Utf8Info>,
    pub descriptor: Rc<Utf8Info>,
    pub attributes_count: U2,
    pub attributes: Vec<Rc<Attribute>>,
}

generate_method_or_field_parser_impl!(Field);
generate_method_or_field_parser_impl!(Method);

pub struct AccessFlags;

impl AccessFlags {
    pub fn is_public(access_flags: U2) -> bool {
        (access_flags & 0x0001) != 0
    }

    pub fn is_private(access_flags: U2) -> bool {
        (access_flags & 0x0002) != 0
    }

    pub fn is_protected(access_flags: U2) -> bool {
        (access_flags & 0x0004) != 0
    }

    pub fn is_static(access_flags: U2) -> bool {
        (access_flags & 0x0008) != 0
    }

    pub fn is_final(access_flags: U2) -> bool {
        (access_flags & 0x0010) != 0
    }

    pub fn is_super(access_flags: U2) -> bool {
        (access_flags & 0x0020) != 0
    }

    pub fn is_volatile(access_flags: U2) -> bool {
        (access_flags & 0x0040) != 0
    }

    pub fn is_bridge(access_flags: U2) -> bool {
        (access_flags & 0x0040) != 0
    }

    pub fn is_transient(access_flags: U2) -> bool {
        (access_flags & 0x0080) != 0
    }

    pub fn is_varargs(access_flags: U2) -> bool {
        (access_flags & 0x0080) != 0
    }

    pub fn is_native(access_flags: U2) -> bool {
        (access_flags & 0x0100) != 0
    }

    pub fn is_interface(access_flags: U2) -> bool {
        (access_flags & 0x0200) != 0
    }

    pub fn is_abstract(access_flags: U2) -> bool {
        (access_flags & 0x0400) != 0
    }

    pub fn is_strict(access_flags: U2) -> bool {
        (access_flags & 0x0800) != 0
    }

    pub fn is_synthetic(access_flags: U2) -> bool {
        (access_flags & 0x1000) != 0
    }

    pub fn is_annotation(access_flags: U2) -> bool {
        (access_flags & 0x2000) != 0
    }

    pub fn is_enum(access_flags: U2) -> bool {
        (access_flags & 0x4000) != 0
    }
}
<commit_msg>Added method to retrieve underlying ConstantPoolItem variant<commit_after>use super::{ParserError, ParserResult};
use super::primitives::{PrimitiveIterator, U1, U2, U4};

use std::ops::Deref;
use std::rc::Rc;

macro_rules! generate_constant_pool_retrieval_method {
    ($variant_name:ident, $struct_name:ident, $method_name:ident) => {
        pub fn $method_name(index: usize,
                            constant_pool: &Vec<ConstantPoolItem>)
            -> ParserResult<Rc<$struct_name>> {
                let actual_index = ConstantPoolItem::shift_index(index);

                if let Some(item) = constant_pool.get(actual_index) {
                    match item {
                        &ConstantPoolItem::$variant_name(ref val) => return Ok(val.clone()),
                        item @ _ => {
                            let name = item.to_friendly_name();
                            return Err(ParserError::UnexpectedConstantPoolItem(name))
                        }
                    }
                }

                Err(ParserError::ConstantPoolIndexOutOfBounds(actual_index))
            }

    }
}

#[derive(Debug)]
pub struct ClassInfo {
    pub tag: U1,
    pub name_index: U2,
}

#[derive(Debug)]
pub struct Utf8Info {
    pub tag: U1,
    pub length: U2,
    pub value: String,
}

impl Deref for Utf8Info {
    type Target = str;

    fn deref(&self) -> &str {
        &self.value
    }
}

#[derive(Debug)]
pub enum ConstantPoolItem {
    Class(Rc<ClassInfo>),
    FieldOrMethodOrInterfaceMethod {
        tag: U1,
        class_index: U2,
        name_and_type_index: U2,
    },
    String { tag: U1, string_index: U2 },
    IntegerOrFloat { tag: U1, bytes: U1 },
    LongOrDouble {
        tag: U1,
        high_bytes: U4,
        low_bytes: U4,
    },
    NameAndType {
        tag: U1,
        name_index: U2,
        descriptor_index: U2,
    },
    Utf8(Rc<Utf8Info>),
    MethodHandle {
        tag: U1,
        reference_kind: U1,
        reference_index: U2,
    },
    MethodType { tag: U1, descriptor_index: U2 },
    InvokeDynamic {
        tag: U1,
        bootstrap_method_attr_index: U2,
        name_and_type_index: U2,
    },
}

impl ConstantPoolItem {
    pub fn from<T: PrimitiveIterator>(iter: &mut T) -> ParserResult<ConstantPoolItem> {
        let tag = try!(iter.next_u1());

        match tag {
            1 => {
                let length = try!(iter.next_u2());

                let mut byte_vec = vec![];
                for _ in 0..length {
                    byte_vec.push(try!(iter.next_u1()));
                }

                let value = try!(String::from_utf8(byte_vec));

                Ok(ConstantPoolItem::Utf8(Rc::new(Utf8Info {
                    tag: tag,
                    length: length,
                    value: value,
                })))
            }
            7 => {
                Ok(ConstantPoolItem::Class(Rc::new(ClassInfo {
                    tag: tag,
                    name_index: try!(iter.next_u2()),
                })))
            }
            8 => {
                Ok(ConstantPoolItem::String {
                    tag: tag,
                    string_index: try!(iter.next_u2()),
                })
            }
            9 | 10 | 11 => {
                Ok(ConstantPoolItem::FieldOrMethodOrInterfaceMethod {
                    tag: tag,
                    class_index: try!(iter.next_u2()),
                    name_and_type_index: try!(iter.next_u2()),
                })
            }
            12 => {
                Ok(ConstantPoolItem::NameAndType {
                    tag: tag,
                    name_index: try!(iter.next_u2()),
                    descriptor_index: try!(iter.next_u2()),
                })
            }
            _ => Err(ParserError::UnknownConstantPoolTag(tag)),
        }
    }

    #[cfg_attr(rustfmt, rustfmt_skip)]
    pub fn to_friendly_name(&self) -> &'static str {
        match self {
            &ConstantPoolItem::Utf8(..) => "Utf8",
            &ConstantPoolItem::Class(..) => "Class",
            &ConstantPoolItem::String { .. } => "String",
            &ConstantPoolItem::FieldOrMethodOrInterfaceMethod { .. } =>
                "Field|Method|InterfaceMethod",
                &ConstantPoolItem::NameAndType { .. } => "NameAndType",
                _ => "Not yet implemented",
        }
    }

    pub fn retrieve_item(index: usize,
                         constant_pool: &Vec<ConstantPoolItem>)
                         -> ParserResult<&ConstantPoolItem> {
        let actual_index = Self::shift_index(index);
        return constant_pool.get(index)
            .ok_or(ParserError::ConstantPoolIndexOutOfBounds(actual_index));
    }

    generate_constant_pool_retrieval_method!(Class, ClassInfo, retrieve_class_info);
    generate_constant_pool_retrieval_method!(Utf8, Utf8Info, retrieve_utf8_info);

    fn shift_index(unshifted_index: usize) -> usize {
        unshifted_index - 1 // references to the constant pool start from one
    }
}

#[derive(Debug)]
pub struct CodeAttribute {
    pub attribute_name: Rc<Utf8Info>,
    pub max_stack: U2,
    pub max_locals: U2,
    pub code_length: U4,
    pub code: Vec<U1>,
    pub exception_table_length: U2,
    pub exception_table: Vec<ExceptionHandler>,
    pub attributes_count: U2,
    pub attributes: Vec<Attribute>,
}

impl CodeAttribute {
    pub fn from<T: PrimitiveIterator>(attribute_name: Rc<Utf8Info>,
                                      iter: &mut T,
                                      constant_pool: &Vec<ConstantPoolItem>)
                                      -> ParserResult<CodeAttribute> {
        let max_stack = try!(iter.next_u2());
        let max_locals = try!(iter.next_u2());

        let code_length = try!(iter.next_u4());
        let mut code = vec![];
        for _ in 0..code_length {
            code.push(try!(iter.next_u1()));
        }

        let exception_table_length = try!(iter.next_u2());
        let mut exception_table = vec![];
        for _ in 0..exception_table_length {
            exception_table.push(try!(ExceptionHandler::from(iter)));
        }

        let attributes_count = try!(iter.next_u2());
        let mut attributes = vec![];
        for _ in 0..attributes_count {
            attributes.push(try!(Attribute::from(iter, constant_pool)));
        }

        Ok(CodeAttribute {
            attribute_name: attribute_name,
            max_stack: max_stack,
            max_locals: max_locals,
            code_length: code_length,
            code: code,
            exception_table_length: exception_table_length,
            exception_table: exception_table,
            attributes_count: attributes_count,
            attributes: attributes,
        })
    }
}

#[derive(Debug)]
pub struct ExceptionHandler {
    pub start_pc: U2,
    pub end_pc: U2,
    pub handler_pc: U2,
    pub catch_type: U2,
}

impl ExceptionHandler {
    pub fn from<T: PrimitiveIterator>(iter: &mut T) -> ParserResult<ExceptionHandler> {
        let start_pc = try!(iter.next_u2());
        let end_pc = try!(iter.next_u2());
        let handler_pc = try!(iter.next_u2());
        let catch_type = try!(iter.next_u2());

        Ok(ExceptionHandler {
            start_pc: start_pc,
            end_pc: end_pc,
            handler_pc: handler_pc,
            catch_type: catch_type,
        })
    }
}

#[derive(Debug)]
pub enum Attribute {
    Code(Rc<CodeAttribute>),
    Unknown {
        attribute_name: Rc<Utf8Info>,
        info: Vec<U1>,
    },
}

impl Attribute {
    pub fn from<T: PrimitiveIterator>(iter: &mut T,
                                      constant_pool: &Vec<ConstantPoolItem>)
                                      -> ParserResult<Attribute> {
        let attribute_name_index = try!(iter.next_u2());
        let attribute_name =
            try!(ConstantPoolItem::retrieve_utf8_info(attribute_name_index as usize,
                                                      constant_pool));

        let attribute_length = try!(iter.next_u4());

        match &**attribute_name {
            "Code" => {
                Ok(Attribute::Code(Rc::new(try!(CodeAttribute::from(attribute_name,
                                                                    iter,
                                                                    constant_pool)))))
            }
            _ => {
                let mut info = vec![];
                for _ in 0..attribute_length {
                    info.push(try!(iter.next_u1()));
                }

                Ok(Attribute::Unknown {
                    attribute_name: attribute_name,
                    info: info,
                })
            }
        }
    }
}

macro_rules! generate_method_or_field_parser_impl {
    ($impl_name:ident) => {
        impl $impl_name {
            pub fn from<T: PrimitiveIterator>(iter: &mut T,
                                              constant_pool: &Vec<ConstantPoolItem>)
                -> ParserResult<$impl_name> {
                    let access_flags = try!(iter.next_u2());

                    let name_index = try!(iter.next_u2());
                    let name = try!(ConstantPoolItem::retrieve_utf8_info(name_index as usize,
                                                                         constant_pool));

                    let descriptor_index = try!(iter.next_u2());
                    let descriptor = try!(ConstantPoolItem::retrieve_utf8_info(
                            descriptor_index as usize,
                            constant_pool));

                    let attributes_count = try!(iter.next_u2());
                    let mut attributes = vec![];
                    for _ in 0..attributes_count {
                        attributes.push(Rc::new(try!(Attribute::from(iter, constant_pool))));
                    }

                    Ok($impl_name {
                        access_flags: access_flags,
                        name: name,
                        descriptor: descriptor,
                        attributes_count: attributes_count,
                        attributes: attributes,
                    })

                }
        }
    }
}

#[derive(Debug)]
pub struct Field {
    pub access_flags: U2,
    pub name: Rc<Utf8Info>,
    pub descriptor: Rc<Utf8Info>,
    pub attributes_count: U2,
    pub attributes: Vec<Rc<Attribute>>,
}

#[derive(Debug)]
pub struct Method {
    pub access_flags: U2,
    pub name: Rc<Utf8Info>,
    pub descriptor: Rc<Utf8Info>,
    pub attributes_count: U2,
    pub attributes: Vec<Rc<Attribute>>,
}

generate_method_or_field_parser_impl!(Field);
generate_method_or_field_parser_impl!(Method);

pub struct AccessFlags;

impl AccessFlags {
    pub fn is_public(access_flags: U2) -> bool {
        (access_flags & 0x0001) != 0
    }

    pub fn is_private(access_flags: U2) -> bool {
        (access_flags & 0x0002) != 0
    }

    pub fn is_protected(access_flags: U2) -> bool {
        (access_flags & 0x0004) != 0
    }

    pub fn is_static(access_flags: U2) -> bool {
        (access_flags & 0x0008) != 0
    }

    pub fn is_final(access_flags: U2) -> bool {
        (access_flags & 0x0010) != 0
    }

    pub fn is_super(access_flags: U2) -> bool {
        (access_flags & 0x0020) != 0
    }

    pub fn is_volatile(access_flags: U2) -> bool {
        (access_flags & 0x0040) != 0
    }

    pub fn is_bridge(access_flags: U2) -> bool {
        (access_flags & 0x0040) != 0
    }

    pub fn is_transient(access_flags: U2) -> bool {
        (access_flags & 0x0080) != 0
    }

    pub fn is_varargs(access_flags: U2) -> bool {
        (access_flags & 0x0080) != 0
    }

    pub fn is_native(access_flags: U2) -> bool {
        (access_flags & 0x0100) != 0
    }

    pub fn is_interface(access_flags: U2) -> bool {
        (access_flags & 0x0200) != 0
    }

    pub fn is_abstract(access_flags: U2) -> bool {
        (access_flags & 0x0400) != 0
    }

    pub fn is_strict(access_flags: U2) -> bool {
        (access_flags & 0x0800) != 0
    }

    pub fn is_synthetic(access_flags: U2) -> bool {
        (access_flags & 0x1000) != 0
    }

    pub fn is_annotation(access_flags: U2) -> bool {
        (access_flags & 0x2000) != 0
    }

    pub fn is_enum(access_flags: U2) -> bool {
        (access_flags & 0x4000) != 0
    }
}
<|endoftext|>


<commit_before>/// An input event.
///
/// An `Event` represents a single event from the underying terminal. At the moment no further
/// processing is done on events and raw escape sequences will also be passed as `Key`s.:wq
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Event {
    Key(char),
}
<commit_msg>Removed ':wq' from documentation<commit_after>/// An input event.
///
/// An `Event` represents a single event from the underying terminal. At the moment no further
/// processing is done on events and raw escape sequences will also be passed as `Key`s.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Event {
    Key(char),
}
<|endoftext|>


<commit_before>use self::super::{MAP, Status};
use self::super::super::http;

pub fn init(ctn: u16, pn: u16) -> Status {
    // Do we know this CTN?
    if MAP.lock().contains_key(&ctn) {
        error!("Card terminal has already been opened.");
        return Status::ErrInvalid;
    }

    let path = format!("ct_init/{}/{}", ctn, pn);
    let response = http::request(&path, None);
    match response {
        Err(why) => {
            error!("{}", why);
            Status::ErrHtsi
        }
        Ok(res) => {
            match res.status {
                200 => handle_ok_status(res.body, ctn, pn),
                _ => {
                    error!("Request failed! Server response was not OK!");
                    return Status::ErrHtsi;
                }
            }
        }
    }
}

fn handle_ok_status(body: String, ctn: u16, pn: u16) -> Status {
    let status: Status = match body.parse::<Status>() {
        Ok(status) => status,
        _ => {
            error!("Unexpected server reponse body!");
            Status::ErrHtsi
        }
    };

    match status {
        Status::OK => {
            // Store CTN
            MAP.lock().insert(ctn, pn);
            debug!("Card terminal opened.");
            status
        }
        _ => status,
    }
}

#[cfg(test)]
mod tests {

    use super::init;
    use super::super::MAP;
    use antidote::Mutex;
    use rand;
    use rouille::Response;

    #[test]
    fn returns_err_htsi_if_no_server() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        assert_eq!(-128, init(ctn, pn))
    }

    #[test]
    fn returns_err_invalid_if_already_open() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        MAP.lock().insert(ctn, pn);

        assert_eq!(-1, init(ctn, pn))
    }

    #[test]
    fn returns_err_htsi_if_server_response_is_not_200() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        let param = Mutex::new(hashmap!["ctn" => ctn, "pn" => pn]);

        let shutdown = test_server!({
            (POST) (/ct_init/{ctn: u16}/{pn: u16}) => {
                assert_eq!(&ctn, param.lock().get("ctn").unwrap());
                assert_eq!(&pn, param.lock().get("pn").unwrap());

                Response::empty_404()
            }
        });

        assert_eq!(-128, init(ctn, pn));
        assert_eq!(false, MAP.lock().contains_key(&ctn));

        // kill server thread
        let _ = shutdown.send(());
    }

    #[test]
    fn returns_err_htsi_if_server_response_not_contains_status() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        let param = Mutex::new(hashmap!["ctn" => ctn, "pn" => pn]);

        let shutdown = test_server!({
            (POST) (/ct_init/{ctn: u16}/{pn: u16}) => {
                assert_eq!(&ctn, param.lock().get("ctn").unwrap());
                assert_eq!(&pn, param.lock().get("pn").unwrap());

                Response::text("hello world")
            }
        });

        assert_eq!(-128, init(ctn, pn));
        assert_eq!(false, MAP.lock().contains_key(&ctn));

        // kill server thread
        let _ = shutdown.send(());
    }

    #[test]
    fn returns_response_status_from_server() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        let param = Mutex::new(hashmap!["ctn" => ctn, "pn" => pn]);

        let shutdown = test_server!({
            (POST) (/ct_init/{ctn: u16}/{pn: u16}) => {
                assert_eq!(&ctn, param.lock().get("ctn").unwrap());
                assert_eq!(&pn, param.lock().get("pn").unwrap());

                Response::text("-11")
            }
        });

        assert_eq!(-11, init(ctn, pn));
        assert_eq!(false, MAP.lock().contains_key(&ctn));

        // kill server thread
        let _ = shutdown.send(());
    }

    #[test]
    fn returns_ok_and_init_ctn_if_server_returns_ok() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        let param = Mutex::new(hashmap!["ctn" => ctn, "pn" => pn]);

        let shutdown = test_server!({
            (POST) (/ct_init/{ctn: u16}/{pn: u16}) => {
                assert_eq!(&ctn, param.lock().get("ctn").unwrap());
                assert_eq!(&pn, param.lock().get("pn").unwrap());

                Response::text("0")
            }
        });

        assert_eq!(0, init(ctn, pn));
        assert_eq!(true, MAP.lock().contains_key(&ctn));

        // kill server thread
        let _ = shutdown.send(());
    }
}
<commit_msg>adjust init for macro changes - add missing test for parameter<commit_after>use self::super::{MAP, Status};
use self::super::super::http;

pub fn init(ctn: u16, pn: u16) -> Status {
    // Do we know this CTN?
    if MAP.lock().contains_key(&ctn) {
        error!("Card terminal has already been opened.");
        return Status::ErrInvalid;
    }

    let path = format!("ct_init/{}/{}", ctn, pn);
    let response = http::request(&path, None);
    match response {
        Err(why) => {
            error!("{}", why);
            Status::ErrHtsi
        }
        Ok(res) => {
            match res.status {
                200 => handle_ok_status(res.body, ctn, pn),
                _ => {
                    error!("Request failed! Server response was not OK!");
                    return Status::ErrHtsi;
                }
            }
        }
    }
}

fn handle_ok_status(body: String, ctn: u16, pn: u16) -> Status {
    let status: Status = match body.parse::<Status>() {
        Ok(status) => status,
        _ => {
            error!("Unexpected server reponse body!");
            Status::ErrHtsi
        }
    };

    match status {
        Status::OK => {
            // Store CTN
            MAP.lock().insert(ctn, pn);
            debug!("Card terminal opened.");
            status
        }
        _ => status,
    }
}

#[cfg(test)]
mod tests {

    use super::init;
    use super::super::MAP;
    use rand;
    use rouille::Response;

    #[test]
    fn returns_err_htsi_if_no_server() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        assert_eq!(-128, init(ctn, pn))
    }

    #[test]
    fn returns_err_invalid_if_already_open() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        MAP.lock().insert(ctn, pn);

        assert_eq!(-1, init(ctn, pn))
    }

    #[test]
    fn use_ctn_and_pn_in_request_path() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        let shutdown =
            test_server!((request: &Request) {
            assert_eq!(request.url(), format!("/ct_init/{}/{}", ctn, pn));

            Response::empty_404()
        });

        init(ctn, pn);

        // kill server thread
        let _ = shutdown.send(());
    }

    #[test]
    fn returns_err_htsi_if_server_response_is_not_200() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        let shutdown =
            test_server!((request: &Request) {
            Response::empty_404()
        });

        assert_eq!(-128, init(ctn, pn));
        assert_eq!(false, MAP.lock().contains_key(&ctn));

        // kill server thread
        let _ = shutdown.send(());
    }

    #[test]
    fn returns_err_htsi_if_server_response_not_contains_status() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        let shutdown =
            test_server!((request: &Request) {
            Response::text("hello world")
        });

        assert_eq!(-128, init(ctn, pn));
        assert_eq!(false, MAP.lock().contains_key(&ctn));

        // kill server thread
        let _ = shutdown.send(());
    }

    #[test]
    fn returns_response_status_from_server() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        let shutdown =
            test_server!((request: &Request) {
            Response::text("-11")
        });

        assert_eq!(-11, init(ctn, pn));

        // kill server thread
        let _ = shutdown.send(());
    }

    #[test]
    fn returns_ok_and_init_ctn_if_server_returns_ok() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        let shutdown =
            test_server!((request: &Request) {
             Response::text("0")
        });

        assert_eq!(0, init(ctn, pn));
        assert_eq!(true, MAP.lock().contains_key(&ctn));

        // kill server thread
        let _ = shutdown.send(());
    }
}
<|endoftext|>


<commit_before>use inflector::Inflector;

use botocore::{Member, Operation, Service, Shape};
use super::GenerateProtocol;

pub struct QueryGenerator;

impl GenerateProtocol for QueryGenerator {
    fn generate_methods(&self, service: &Service) -> String {
        service.operations.values().map(|operation| {
            format!(
                "{documentation}
{method_signature} {{
    let mut request = SignedRequest::new(
        \"{http_method}\",
        \"{endpoint_prefix}\",
        self.region,
        \"{request_uri}\",
    );
    let mut params = Params::new();

    params.put(\"Action\", \"{operation_name}\");
    {serialize_input}

    request.set_params(params);

    let result = request.sign_and_execute(try!(self.credentials_provider.credentials()));
    let status = result.status.to_u16();
    let mut reader = EventReader::new(result);
    let mut stack = XmlResponseFromAws::new(reader.events().peekable());
    stack.next();
    stack.next();

    match status {{
        200 => {{
            {method_return_value}
        }}
        status_code => Err(AwsError::new(
            format!(\"HTTP response code for {operation_name}: {{}}\", status_code)
        ))
    }}
}}
                ",
                documentation = generate_documentation(operation),
                http_method = &operation.http.method,
                endpoint_prefix = &service.metadata.endpoint_prefix,
                method_return_value = generate_method_return_value(operation),
                method_signature = generate_method_signature(operation),
                operation_name = &operation.name,
                request_uri = &operation.http.request_uri,
                serialize_input = generate_method_input_serialization(operation),
            )
        }).collect::<Vec<String>>().join("\n")
    }

    fn generate_prelude(&self) -> String {
        "use std::collections::HashMap;
        use std::str::{FromStr, from_utf8};

        use xml::EventReader;

        use credential::ProvideAwsCredentials;
        use error::AwsError;
        use param::{Params, ServiceParams};
        use region::Region;
        use signature::SignedRequest;
        use xmlutil::{Next, Peek, XmlParseError, XmlResponseFromAws};
        use xmlutil::{characters, end_element, peek_at_name, start_element};
        ".to_owned()
    }

    fn generate_struct_attributes(&self) -> String {
        "#[derive(Debug, Default)]".to_owned()
    }

    fn generate_support_types(&self, name: &str, shape: &Shape, service: &Service) -> Option<String> {
        Some(format!(
            "/// Deserializes `{name}` from XML.
            struct {name}Deserializer;
            impl {name}Deserializer {{
                fn deserialize<'a, T: Peek + Next>(tag_name: &str, stack: &mut T)
                -> Result<{name}, XmlParseError> {{
                    {deserializer_body}
                }}
            }}

            /// Serialize `{name}` contents to a `SignedRequest`.
            struct {name}Serializer;
            impl {name}Serializer {{
                {serializer_signature} {{
                    {serializer_body}
                }}
            }}
            ",
            deserializer_body = generate_deserializer_body(name, shape, service),
            name = name,
            serializer_body = generate_serializer_body(shape),
            serializer_signature = generate_serializer_signature(name, shape),
        ))
    }
}

fn generate_documentation(operation: &Operation) -> String {
    match operation.documentation {
        Some(ref docs) => format!("#[doc=\"{}\"]", docs.replace("\"", "\\\"")),
        None => "".to_owned(),
    }
}

fn generate_method_input_serialization(operation: &Operation) -> String {
    if operation.input.is_some() {
        format!(
            "{input_type}Serializer::serialize(&mut params, \"\", &input);",
            input_type = operation.input.as_ref().unwrap().shape,
        )
    } else {
        String::new()
    }
}

fn generate_method_return_value(operation: &Operation) -> String {
    if operation.output.is_some() {
        format!(
            "Ok(try!({output_type}Deserializer::deserialize(\"{output_type}\", &mut stack)))",
            output_type = &operation.output.as_ref().unwrap().shape,
        )
    } else {
        "Ok(())".to_owned()
    }
}

fn generate_method_signature(operation: &Operation) -> String {
    if operation.input.is_some() {
        format!(
            "pub fn {operation_name}(&mut self, input: &{input_type}) -> Result<{output_type}, AwsError>",
            input_type = operation.input.as_ref().unwrap().shape,
            operation_name = operation.name.to_snake_case(),
            output_type = &operation.output_shape_or("()"),
        )
    } else {
        format!(
            "pub fn {operation_name}(&mut self) -> Result<{output_type}, AwsError>",
            operation_name = operation.name.to_snake_case(),
            output_type = &operation.output_shape_or("()"),
        )
    }
}

fn generate_deserializer_body(name: &str, shape: &Shape, service: &Service) -> String {
    match &shape.shape_type[..] {
        "list" => generate_list_deserializer(shape),
        "map" => generate_map_deserializer(shape),
        "structure" => generate_struct_deserializer(name, shape, service),
        _ => generate_primitive_deserializer(shape),
    }
}

fn generate_list_deserializer(shape: &Shape) -> String {
    format!(
        "
        let mut obj = vec![];

        while try!(peek_at_name(stack)) == tag_name {{
            obj.push(try!({member_name}Deserializer::deserialize(tag_name, stack)));
        }}

        Ok(obj)
        ",
        member_name = shape.member()
    )
}

fn generate_map_deserializer(shape: &Shape) -> String {
    let key = shape.key.as_ref().unwrap();
    let value = shape.value.as_ref().unwrap();

    format!(
        "
        let mut obj = HashMap::new();

        while try!(peek_at_name(stack)) == tag_name {{
            try!(start_element(tag_name, stack));
            let key = try!({key_type_name}Deserializer::deserialize(\"{key_tag_name}\", stack));
            let value = try!({value_type_name}Deserializer::deserialize(\"{value_tag_name}\", stack));
            obj.insert(key, value);
            try!(end_element(tag_name, stack));
        }}

        Ok(obj)
        ",
        key_tag_name = key.tag_name(),
        key_type_name = key.shape,
        value_tag_name = value.tag_name(),
        value_type_name = value.shape,
    )
}

fn generate_primitive_deserializer(shape: &Shape) -> String {
    let statement =  match &shape.shape_type[..] {
        "string" | "timestamp" => "try!(characters(stack))",
        "integer" => "i32::from_str(try!(characters(stack)).as_ref()).unwrap()",
        "double" => "f32::from_str(try!(characters(stack)).as_ref()).unwrap()",
        "blob" => "try!(characters(stack)).into_bytes()",
        "boolean" => "bool::from_str(try!(characters(stack)).as_ref()).unwrap()",
        shape_type => panic!("Unknown primitive shape type: {}", shape_type),
    };

    format!(
        "try!(start_element(tag_name, stack));
        let obj = {statement};
        try!(end_element(tag_name, stack));

        Ok(obj)
        ",
        statement = statement,
    )
}

fn generate_struct_deserializer(name: &str, shape: &Shape, service: &Service) -> String {
    if shape.members.as_ref().unwrap().is_empty() {
        return format!(
            "try!(start_element(tag_name, stack));

            let obj = {name}::default();

            try!(end_element(tag_name, stack));

            Ok(obj)
            ",
            name = name,
        );
    }

    format!(
        "try!(start_element(tag_name, stack));

        let mut obj = {name}::default();

        loop {{
            match &try!(peek_at_name(stack))[..] {{
                {struct_field_deserializers}
                _ => break,
            }}
        }}

        try!(end_element(tag_name, stack));

        Ok(obj)
        ",
        name = name,
        struct_field_deserializers = generate_struct_field_deserializers(shape, service),
    )
}

fn generate_struct_field_deserializers(shape: &Shape, service: &Service) -> String {
    shape.members.as_ref().unwrap().iter().map(|(member_name, member)| {
        // look up member.shape in all_shapes.  use that shape.member.location_name
        let mut location_name = member_name.to_string();
        let mut parse_expression = generate_struct_field_parse_expression(shape, member_name, member, None);

        match service.shape_for_member(member) {
            Some(ref child_shape) => {
                match child_shape.flattened {
                    Some(_) => {
                        match child_shape.member {
                            Some(ref child_member) => {
                                match child_member.location_name {
                                    Some(ref loc_name) => {
                                        location_name = loc_name.to_string();
                                        parse_expression = generate_struct_field_parse_expression(shape, member_name, member, Some(&location_name));
                                    },
                                    None => (),
                                }
                            },
                            None => (),
                        }
                    }
                    None => (),
                };
            },
            None => (),
        }
        format!(
            "\"{location_name}\" => {{
                obj.{field_name} = {parse_expression};
                continue;
            }}",
            field_name = member_name.to_snake_case(),
            parse_expression = parse_expression,
            location_name = location_name,
        )

    }).collect::<Vec<String>>().join("\n")
}

fn generate_struct_field_parse_expression(
    shape: &Shape,
    member_name: &str,
    member: &Member,
    location_name: Option<&String>,
) -> String {

    let location_to_use = match location_name {
        Some(loc) => loc,
        None => member_name,
    };
    let expression = format!(
        "try!({name}Deserializer::deserialize(\"{location}\", stack))",
        name = member.shape,
        location = location_to_use,
    );

    if shape.required(member_name) {
        expression
    } else {
        format!("Some({})", expression)
    }
}

fn generate_serializer_body(shape: &Shape) -> String {
    match &shape.shape_type[..] {
        "list" => generate_list_serializer(shape),
        "map" => generate_map_serializer(shape),
        "structure" => generate_struct_serializer(shape),
        _ => generate_primitive_serializer(shape),
    }
}

fn generate_serializer_signature(name: &str, shape: &Shape) -> String {
    if &shape.shape_type[..] == "structure" && shape.members.as_ref().unwrap().is_empty() {
        format!("fn serialize(_params: &mut Params, name: &str, _obj: &{})", name)
    } else {
        format!("fn serialize(params: &mut Params, name: &str, obj: &{})", name)
    }
}

fn generate_list_serializer(shape: &Shape) -> String {
    format!(
        "for (index, element) in obj.iter().enumerate() {{
    let key = format!(\"{{}}.{{}}\", name, index);
    {name}Serializer::serialize(params, &key, element);
}}
        ",
        name = shape.member(),
    )
}

fn generate_map_serializer(shape: &Shape) -> String {
    format!(
        "for (index, (key, value)) in obj.iter().enumerate() {{
    let prefix = format!(\"{{}}.{{}}\", name, index);
    {key_name}Serializer::serialize(
        params,
        &format!(\"{{}}.{{}}\", prefix, \"{key_name}\"),
        key,
    );
    {value_name}Serializer::serialize(
        params,
        &format!(\"{{}}.{{}}\", prefix, \"{value_name}\"),
        value,
    );
}}
        ",
        key_name = shape.key(),
        value_name = shape.value(),
    )
}

fn generate_struct_serializer(shape: &Shape) -> String {
    format!(
        "let mut prefix = name.to_string();
if prefix != \"\" {{
    prefix.push_str(\".\");
}}

{struct_field_serializers}
        ",
        struct_field_serializers = generate_struct_field_serializers(shape),
    )
}

fn generate_struct_field_serializers(shape: &Shape) -> String {
    shape.members.as_ref().unwrap().iter().map(|(member_name, member)| {
        if shape.required(member_name) {
            format!(
                "{member_shape_name}Serializer::serialize(
    params,
    &format!(\"{{}}{{}}\", prefix, \"{tag_name}\"),
    &obj.{field_name},
);
                ",
                field_name = member_name.to_snake_case(),
                member_shape_name = member.shape,
                tag_name = member_name,
            )
        } else {
            format!(
                "if let Some(ref field_value) = obj.{field_name} {{
    {member_shape_name}Serializer::serialize(
        params,
        &format!(\"{{}}{{}}\", prefix, \"{tag_name}\"),
        field_value,
    );
}}
                ",
                field_name = member_name.to_snake_case(),
                member_shape_name = member.shape,
                tag_name = member.tag_name(),
            )
        }
    }).collect::<Vec<String>>().join("\n")
}

fn generate_primitive_serializer(shape: &Shape) -> String {
    let expression = match &shape.shape_type[..] {
        "string" | "timestamp" => "obj",
        "integer" | "double" | "boolean" => "&obj.to_string()",
        "blob" => "from_utf8(obj).unwrap()",
        shape_type => panic!("Unknown primitive shape type: {}", shape_type),
    };

    format!("params.put(name, {});", expression)
}
<commit_msg>Fixes matching arm error.<commit_after>use inflector::Inflector;

use botocore::{Member, Operation, Service, Shape};
use super::GenerateProtocol;

pub struct QueryGenerator;

impl GenerateProtocol for QueryGenerator {
    fn generate_methods(&self, service: &Service) -> String {
        service.operations.values().map(|operation| {
            format!(
                "{documentation}
{method_signature} {{
    let mut request = SignedRequest::new(
        \"{http_method}\",
        \"{endpoint_prefix}\",
        self.region,
        \"{request_uri}\",
    );
    let mut params = Params::new();

    params.put(\"Action\", \"{operation_name}\");
    {serialize_input}

    request.set_params(params);

    let result = request.sign_and_execute(try!(self.credentials_provider.credentials()));
    let status = result.status.to_u16();
    let mut reader = EventReader::new(result);
    let mut stack = XmlResponseFromAws::new(reader.events().peekable());
    stack.next();
    stack.next();

    match status {{
        200 => {{
            {method_return_value}
        }}
        status_code => Err(AwsError::new(
            format!(\"HTTP response code for {operation_name}: {{}}\", status_code)
        ))
    }}
}}
                ",
                documentation = generate_documentation(operation),
                http_method = &operation.http.method,
                endpoint_prefix = &service.metadata.endpoint_prefix,
                method_return_value = generate_method_return_value(operation),
                method_signature = generate_method_signature(operation),
                operation_name = &operation.name,
                request_uri = &operation.http.request_uri,
                serialize_input = generate_method_input_serialization(operation),
            )
        }).collect::<Vec<String>>().join("\n")
    }

    fn generate_prelude(&self) -> String {
        "use std::collections::HashMap;
        use std::str::{FromStr, from_utf8};

        use xml::EventReader;

        use credential::ProvideAwsCredentials;
        use error::AwsError;
        use param::{Params, ServiceParams};
        use region::Region;
        use signature::SignedRequest;
        use xmlutil::{Next, Peek, XmlParseError, XmlResponseFromAws};
        use xmlutil::{characters, end_element, peek_at_name, start_element};
        ".to_owned()
    }

    fn generate_struct_attributes(&self) -> String {
        "#[derive(Debug, Default)]".to_owned()
    }

    fn generate_support_types(&self, name: &str, shape: &Shape, service: &Service) -> Option<String> {
        Some(format!(
            "/// Deserializes `{name}` from XML.
            struct {name}Deserializer;
            impl {name}Deserializer {{
                fn deserialize<'a, T: Peek + Next>(tag_name: &str, stack: &mut T)
                -> Result<{name}, XmlParseError> {{
                    {deserializer_body}
                }}
            }}

            /// Serialize `{name}` contents to a `SignedRequest`.
            struct {name}Serializer;
            impl {name}Serializer {{
                {serializer_signature} {{
                    {serializer_body}
                }}
            }}
            ",
            deserializer_body = generate_deserializer_body(name, shape, service),
            name = name,
            serializer_body = generate_serializer_body(shape),
            serializer_signature = generate_serializer_signature(name, shape),
        ))
    }
}

fn generate_documentation(operation: &Operation) -> String {
    match operation.documentation {
        Some(ref docs) => format!("#[doc=\"{}\"]", docs.replace("\"", "\\\"")),
        None => "".to_owned(),
    }
}

fn generate_method_input_serialization(operation: &Operation) -> String {
    if operation.input.is_some() {
        format!(
            "{input_type}Serializer::serialize(&mut params, \"\", &input);",
            input_type = operation.input.as_ref().unwrap().shape,
        )
    } else {
        String::new()
    }
}

fn generate_method_return_value(operation: &Operation) -> String {
    if operation.output.is_some() {
        format!(
            "Ok(try!({output_type}Deserializer::deserialize(\"{output_type}\", &mut stack)))",
            output_type = &operation.output.as_ref().unwrap().shape,
        )
    } else {
        "Ok(())".to_owned()
    }
}

fn generate_method_signature(operation: &Operation) -> String {
    if operation.input.is_some() {
        format!(
            "pub fn {operation_name}(&mut self, input: &{input_type}) -> Result<{output_type}, AwsError>",
            input_type = operation.input.as_ref().unwrap().shape,
            operation_name = operation.name.to_snake_case(),
            output_type = &operation.output_shape_or("()"),
        )
    } else {
        format!(
            "pub fn {operation_name}(&mut self) -> Result<{output_type}, AwsError>",
            operation_name = operation.name.to_snake_case(),
            output_type = &operation.output_shape_or("()"),
        )
    }
}

fn generate_deserializer_body(name: &str, shape: &Shape, service: &Service) -> String {
    match &shape.shape_type[..] {
        "list" => generate_list_deserializer(shape),
        "map" => generate_map_deserializer(shape),
        "structure" => generate_struct_deserializer(name, shape, service),
        _ => generate_primitive_deserializer(shape),
    }
}

fn generate_list_deserializer(shape: &Shape) -> String {
    format!(
        "
        let mut obj = vec![];

        while try!(peek_at_name(stack)) == tag_name {{
            obj.push(try!({member_name}Deserializer::deserialize(tag_name, stack)));
        }}

        Ok(obj)
        ",
        member_name = shape.member()
    )
}

fn generate_map_deserializer(shape: &Shape) -> String {
    let key = shape.key.as_ref().unwrap();
    let value = shape.value.as_ref().unwrap();

    format!(
        "
        let mut obj = HashMap::new();

        while try!(peek_at_name(stack)) == tag_name {{
            try!(start_element(tag_name, stack));
            let key = try!({key_type_name}Deserializer::deserialize(\"{key_tag_name}\", stack));
            let value = try!({value_type_name}Deserializer::deserialize(\"{value_tag_name}\", stack));
            obj.insert(key, value);
            try!(end_element(tag_name, stack));
        }}

        Ok(obj)
        ",
        key_tag_name = key.tag_name(),
        key_type_name = key.shape,
        value_tag_name = value.tag_name(),
        value_type_name = value.shape,
    )
}

fn generate_primitive_deserializer(shape: &Shape) -> String {
    let statement =  match &shape.shape_type[..] {
        "string" | "timestamp" => "try!(characters(stack))",
        "integer" => "i32::from_str(try!(characters(stack)).as_ref()).unwrap()",
        "double" => "f32::from_str(try!(characters(stack)).as_ref()).unwrap()",
        "blob" => "try!(characters(stack)).into_bytes()",
        "boolean" => "bool::from_str(try!(characters(stack)).as_ref()).unwrap()",
        shape_type => panic!("Unknown primitive shape type: {}", shape_type),
    };

    format!(
        "try!(start_element(tag_name, stack));
        let obj = {statement};
        try!(end_element(tag_name, stack));

        Ok(obj)
        ",
        statement = statement,
    )
}

fn generate_struct_deserializer(name: &str, shape: &Shape, service: &Service) -> String {
    if shape.members.as_ref().unwrap().is_empty() {
        return format!(
            "try!(start_element(tag_name, stack));

            let obj = {name}::default();

            try!(end_element(tag_name, stack));

            Ok(obj)
            ",
            name = name,
        );
    }

    format!(
        "try!(start_element(tag_name, stack));

        let mut obj = {name}::default();

        loop {{
            match &try!(peek_at_name(stack))[..] {{
                {struct_field_deserializers}
                _ => break,
            }}
        }}

        try!(end_element(tag_name, stack));

        Ok(obj)
        ",
        name = name,
        struct_field_deserializers = generate_struct_field_deserializers(shape, service),
    )
}

fn generate_struct_field_deserializers(shape: &Shape, service: &Service) -> String {
    shape.members.as_ref().unwrap().iter().map(|(member_name, member)| {
        // look up member.shape in all_shapes.  use that shape.member.location_name
        let mut location_name = member_name.to_string();
        let mut parse_expression = generate_struct_field_parse_expression(shape, member_name, member, None);

        match service.shape_for_member(member) {
            Some(ref child_shape) => {
                match child_shape.flattened {
                    Some(_) => {
                        match child_shape.member {
                            Some(ref child_member) => {
                                match child_member.location_name {
                                    Some(ref loc_name) => {
                                        location_name = loc_name.to_string();
                                        parse_expression = generate_struct_field_parse_expression(shape, member_name, member, Some(&location_name));
                                    },
                                    None => (),
                                }
                            },
                            None => (),
                        }
                    }
                    None => (),
                };
            },
            None => (),
        }
        format!(
            "\"{location_name}\" => {{
                obj.{field_name} = {parse_expression};
                continue;
            }}",
            field_name = member_name.to_snake_case(),
            parse_expression = parse_expression,
            location_name = location_name,
        )

    }).collect::<Vec<String>>().join("\n")
}

fn generate_struct_field_parse_expression(
    shape: &Shape,
    member_name: &str,
    member: &Member,
    location_name: Option<&String>,
) -> String {

    let location_to_use = match location_name {
        Some(loc) => loc.to_string(),
        None => member_name.to_string(),
    };
    let expression = format!(
        "try!({name}Deserializer::deserialize(\"{location}\", stack))",
        name = member.shape,
        location = location_to_use,
    );

    if shape.required(member_name) {
        expression
    } else {
        format!("Some({})", expression)
    }
}

fn generate_serializer_body(shape: &Shape) -> String {
    match &shape.shape_type[..] {
        "list" => generate_list_serializer(shape),
        "map" => generate_map_serializer(shape),
        "structure" => generate_struct_serializer(shape),
        _ => generate_primitive_serializer(shape),
    }
}

fn generate_serializer_signature(name: &str, shape: &Shape) -> String {
    if &shape.shape_type[..] == "structure" && shape.members.as_ref().unwrap().is_empty() {
        format!("fn serialize(_params: &mut Params, name: &str, _obj: &{})", name)
    } else {
        format!("fn serialize(params: &mut Params, name: &str, obj: &{})", name)
    }
}

fn generate_list_serializer(shape: &Shape) -> String {
    format!(
        "for (index, element) in obj.iter().enumerate() {{
    let key = format!(\"{{}}.{{}}\", name, index);
    {name}Serializer::serialize(params, &key, element);
}}
        ",
        name = shape.member(),
    )
}

fn generate_map_serializer(shape: &Shape) -> String {
    format!(
        "for (index, (key, value)) in obj.iter().enumerate() {{
    let prefix = format!(\"{{}}.{{}}\", name, index);
    {key_name}Serializer::serialize(
        params,
        &format!(\"{{}}.{{}}\", prefix, \"{key_name}\"),
        key,
    );
    {value_name}Serializer::serialize(
        params,
        &format!(\"{{}}.{{}}\", prefix, \"{value_name}\"),
        value,
    );
}}
        ",
        key_name = shape.key(),
        value_name = shape.value(),
    )
}

fn generate_struct_serializer(shape: &Shape) -> String {
    format!(
        "let mut prefix = name.to_string();
if prefix != \"\" {{
    prefix.push_str(\".\");
}}

{struct_field_serializers}
        ",
        struct_field_serializers = generate_struct_field_serializers(shape),
    )
}

fn generate_struct_field_serializers(shape: &Shape) -> String {
    shape.members.as_ref().unwrap().iter().map(|(member_name, member)| {
        if shape.required(member_name) {
            format!(
                "{member_shape_name}Serializer::serialize(
    params,
    &format!(\"{{}}{{}}\", prefix, \"{tag_name}\"),
    &obj.{field_name},
);
                ",
                field_name = member_name.to_snake_case(),
                member_shape_name = member.shape,
                tag_name = member_name,
            )
        } else {
            format!(
                "if let Some(ref field_value) = obj.{field_name} {{
    {member_shape_name}Serializer::serialize(
        params,
        &format!(\"{{}}{{}}\", prefix, \"{tag_name}\"),
        field_value,
    );
}}
                ",
                field_name = member_name.to_snake_case(),
                member_shape_name = member.shape,
                tag_name = member.tag_name(),
            )
        }
    }).collect::<Vec<String>>().join("\n")
}

fn generate_primitive_serializer(shape: &Shape) -> String {
    let expression = match &shape.shape_type[..] {
        "string" | "timestamp" => "obj",
        "integer" | "double" | "boolean" => "&obj.to_string()",
        "blob" => "from_utf8(obj).unwrap()",
        shape_type => panic!("Unknown primitive shape type: {}", shape_type),
    };

    format!("params.put(name, {});", expression)
}
<|endoftext|>


<commit_before>//! This module contains paths to types and functions Clippy needs to know
//! about.

pub const ANY_TRAIT: [&str; 3] = ["std", "any", "Any"];
pub const ARC: [&str; 3] = ["alloc", "arc", "Arc"];
pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"];
pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"];
pub const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"];
pub const BEGIN_PANIC_FMT: [&str; 3] = ["std", "panicking", "begin_panic_fmt"];
pub const BINARY_HEAP: [&str; 3] = ["alloc", "binary_heap", "BinaryHeap"];
pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"];
pub const BOX: [&str; 3] = ["std", "boxed", "Box"];
pub const BOX_NEW: [&str; 4] = ["std", "boxed", "Box", "new"];
pub const BTREEMAP: [&str; 4] = ["alloc", "btree", "map", "BTreeMap"];
pub const BTREEMAP_ENTRY: [&str; 4] = ["alloc", "btree", "map", "Entry"];
pub const BTREESET: [&str; 4] = ["alloc", "btree", "set", "BTreeSet"];
pub const CLONE: [&str; 4] = ["core", "clone", "Clone", "clone"];
pub const CLONE_TRAIT: [&str; 3] = ["core", "clone", "Clone"];
pub const CMP_MAX: [&str; 3] = ["core", "cmp", "max"];
pub const CMP_MIN: [&str; 3] = ["core", "cmp", "min"];
pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"];
pub const CSTRING_NEW: [&str; 5] = ["std", "ffi", "c_str", "CString", "new"];
pub const DEBUG_FMT_METHOD: [&str; 4] = ["core", "fmt", "Debug", "fmt"];
pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"];
pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"];
pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"];
pub const DROP: [&str; 3] = ["core", "mem", "drop"];
pub const FMT_ARGUMENTS_NEWV1: [&str; 4] = ["core", "fmt", "Arguments", "new_v1"];
pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"];
pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
pub const HASH: [&str; 2] = ["hash", "Hash"];
pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"];
pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"];
pub const HASHSET: [&str; 5] = ["std", "collections", "hash", "set", "HashSet"];
pub const INDEX: [&str; 3] = ["core", "ops", "Index"];
pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"];
pub const INIT: [&str; 4] = ["core", "intrinsics", "", "init"];
pub const INTO: [&str; 3] = ["core", "convert", "Into"];
pub const INTO_ITERATOR: [&str; 4] = ["core", "iter", "traits", "IntoIterator"];
pub const IO_PRINT: [&str; 4] = ["std", "io", "stdio", "_print"];
pub const IO_READ: [&str; 3] = ["std", "io", "Read"];
pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
pub const ITERATOR: [&str; 4] = ["core", "iter", "iterator", "Iterator"];
pub const LINKED_LIST: [&str; 3] = ["alloc", "linked_list", "LinkedList"];
pub const LINT: [&str; 2] = ["lint", "Lint"];
pub const LINT_ARRAY: [&str; 2] = ["lint", "LintArray"];
pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"];
pub const MEM_UNINIT: [&str; 3] = ["core", "mem", "uninitialized"];
pub const MEM_ZEROED: [&str; 3] = ["core", "mem", "zeroed"];
pub const MUTEX: [&str; 4] = ["std", "sync", "mutex", "Mutex"];
pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"];
pub const OPS_MODULE: [&str; 2] = ["core", "ops"];
pub const OPTION: [&str; 3] = ["core", "option", "Option"];
pub const OPTION_NONE: [&str; 4] = ["core", "option", "Option", "None"];
pub const OPTION_SOME: [&str; 4] = ["core", "option", "Option", "Some"];
pub const PTR_NULL: [&str; 2] = ["ptr", "null"];
pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"];
pub const RANGE: [&str; 3] = ["core", "ops", "Range"];
pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["alloc", "range", "RangeArgument"];
pub const RANGE_FROM: [&str; 3] = ["core", "ops", "RangeFrom"];
pub const RANGE_FROM_STD: [&str; 3] = ["std", "ops", "RangeFrom"];
pub const RANGE_FULL: [&str; 3] = ["core", "ops", "RangeFull"];
pub const RANGE_FULL_STD: [&str; 3] = ["std", "ops", "RangeFull"];
pub const RANGE_INCLUSIVE: [&str; 3] = ["core", "ops", "RangeInclusive"];
pub const RANGE_INCLUSIVE_STD: [&str; 3] = ["std", "ops", "RangeInclusive"];
pub const RANGE_STD: [&str; 3] = ["std", "ops", "Range"];
pub const RANGE_TO: [&str; 3] = ["core", "ops", "RangeTo"];
pub const RANGE_TO_INCLUSIVE: [&str; 3] = ["core", "ops", "RangeToInclusive"];
pub const RANGE_TO_INCLUSIVE_STD: [&str; 3] = ["std", "ops", "RangeToInclusive"];
pub const RANGE_TO_STD: [&str; 3] = ["std", "ops", "RangeTo"];
pub const RC: [&str; 3] = ["alloc", "rc", "Rc"];
pub const REGEX: [&str; 3] = ["regex", "re_unicode", "Regex"];
pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
pub const REGEX_BYTES: [&str; 3] = ["regex", "re_bytes", "Regex"];
pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
pub const REPEAT: [&str; 3] = ["core", "iter", "repeat"];
pub const RESULT: [&str; 3] = ["core", "result", "Result"];
pub const RESULT_ERR: [&str; 4] = ["core", "result", "Result", "Err"];
pub const RESULT_OK: [&str; 4] = ["core", "result", "Result", "Ok"];
pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
pub const SLICE_ITER: [&str; 3] = ["core", "slice", "Iter"];
pub const STRING: [&str; 3] = ["alloc", "string", "String"];
pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"];
pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"];
pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
pub const TRY_INTO_RESULT: [&str; 4] = ["std", "ops", "Try", "into_result"];
pub const UNINIT: [&str; 4] = ["core", "intrinsics", "", "uninit"];
pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
pub const VEC_DEQUE: [&str; 3] = ["alloc", "vec_deque", "VecDeque"];
pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
pub const WEAK_ARC: [&str; 3] = ["alloc", "arc", "Weak"];
pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
<commit_msg>Move RangeArgument<commit_after>//! This module contains paths to types and functions Clippy needs to know
//! about.

pub const ANY_TRAIT: [&str; 3] = ["std", "any", "Any"];
pub const ARC: [&str; 3] = ["alloc", "arc", "Arc"];
pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"];
pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"];
pub const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"];
pub const BEGIN_PANIC_FMT: [&str; 3] = ["std", "panicking", "begin_panic_fmt"];
pub const BINARY_HEAP: [&str; 3] = ["alloc", "binary_heap", "BinaryHeap"];
pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"];
pub const BOX: [&str; 3] = ["std", "boxed", "Box"];
pub const BOX_NEW: [&str; 4] = ["std", "boxed", "Box", "new"];
pub const BTREEMAP: [&str; 4] = ["alloc", "btree", "map", "BTreeMap"];
pub const BTREEMAP_ENTRY: [&str; 4] = ["alloc", "btree", "map", "Entry"];
pub const BTREESET: [&str; 4] = ["alloc", "btree", "set", "BTreeSet"];
pub const CLONE: [&str; 4] = ["core", "clone", "Clone", "clone"];
pub const CLONE_TRAIT: [&str; 3] = ["core", "clone", "Clone"];
pub const CMP_MAX: [&str; 3] = ["core", "cmp", "max"];
pub const CMP_MIN: [&str; 3] = ["core", "cmp", "min"];
pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"];
pub const CSTRING_NEW: [&str; 5] = ["std", "ffi", "c_str", "CString", "new"];
pub const DEBUG_FMT_METHOD: [&str; 4] = ["core", "fmt", "Debug", "fmt"];
pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"];
pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"];
pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"];
pub const DROP: [&str; 3] = ["core", "mem", "drop"];
pub const FMT_ARGUMENTS_NEWV1: [&str; 4] = ["core", "fmt", "Arguments", "new_v1"];
pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"];
pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
pub const HASH: [&str; 2] = ["hash", "Hash"];
pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"];
pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"];
pub const HASHSET: [&str; 5] = ["std", "collections", "hash", "set", "HashSet"];
pub const INDEX: [&str; 3] = ["core", "ops", "Index"];
pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"];
pub const INIT: [&str; 4] = ["core", "intrinsics", "", "init"];
pub const INTO: [&str; 3] = ["core", "convert", "Into"];
pub const INTO_ITERATOR: [&str; 4] = ["core", "iter", "traits", "IntoIterator"];
pub const IO_PRINT: [&str; 4] = ["std", "io", "stdio", "_print"];
pub const IO_READ: [&str; 3] = ["std", "io", "Read"];
pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
pub const ITERATOR: [&str; 4] = ["core", "iter", "iterator", "Iterator"];
pub const LINKED_LIST: [&str; 3] = ["alloc", "linked_list", "LinkedList"];
pub const LINT: [&str; 2] = ["lint", "Lint"];
pub const LINT_ARRAY: [&str; 2] = ["lint", "LintArray"];
pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"];
pub const MEM_UNINIT: [&str; 3] = ["core", "mem", "uninitialized"];
pub const MEM_ZEROED: [&str; 3] = ["core", "mem", "zeroed"];
pub const MUTEX: [&str; 4] = ["std", "sync", "mutex", "Mutex"];
pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"];
pub const OPS_MODULE: [&str; 2] = ["core", "ops"];
pub const OPTION: [&str; 3] = ["core", "option", "Option"];
pub const OPTION_NONE: [&str; 4] = ["core", "option", "Option", "None"];
pub const OPTION_SOME: [&str; 4] = ["core", "option", "Option", "Some"];
pub const PTR_NULL: [&str; 2] = ["ptr", "null"];
pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"];
pub const RANGE: [&str; 3] = ["core", "ops", "Range"];
pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBound"];
pub const RANGE_FROM: [&str; 3] = ["core", "ops", "RangeFrom"];
pub const RANGE_FROM_STD: [&str; 3] = ["std", "ops", "RangeFrom"];
pub const RANGE_FULL: [&str; 3] = ["core", "ops", "RangeFull"];
pub const RANGE_FULL_STD: [&str; 3] = ["std", "ops", "RangeFull"];
pub const RANGE_INCLUSIVE: [&str; 3] = ["core", "ops", "RangeInclusive"];
pub const RANGE_INCLUSIVE_STD: [&str; 3] = ["std", "ops", "RangeInclusive"];
pub const RANGE_STD: [&str; 3] = ["std", "ops", "Range"];
pub const RANGE_TO: [&str; 3] = ["core", "ops", "RangeTo"];
pub const RANGE_TO_INCLUSIVE: [&str; 3] = ["core", "ops", "RangeToInclusive"];
pub const RANGE_TO_INCLUSIVE_STD: [&str; 3] = ["std", "ops", "RangeToInclusive"];
pub const RANGE_TO_STD: [&str; 3] = ["std", "ops", "RangeTo"];
pub const RC: [&str; 3] = ["alloc", "rc", "Rc"];
pub const REGEX: [&str; 3] = ["regex", "re_unicode", "Regex"];
pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
pub const REGEX_BYTES: [&str; 3] = ["regex", "re_bytes", "Regex"];
pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
pub const REPEAT: [&str; 3] = ["core", "iter", "repeat"];
pub const RESULT: [&str; 3] = ["core", "result", "Result"];
pub const RESULT_ERR: [&str; 4] = ["core", "result", "Result", "Err"];
pub const RESULT_OK: [&str; 4] = ["core", "result", "Result", "Ok"];
pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
pub const SLICE_ITER: [&str; 3] = ["core", "slice", "Iter"];
pub const STRING: [&str; 3] = ["alloc", "string", "String"];
pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"];
pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"];
pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
pub const TRY_INTO_RESULT: [&str; 4] = ["std", "ops", "Try", "into_result"];
pub const UNINIT: [&str; 4] = ["core", "intrinsics", "", "uninit"];
pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
pub const VEC_DEQUE: [&str; 3] = ["alloc", "vec_deque", "VecDeque"];
pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
pub const WEAK_ARC: [&str; 3] = ["alloc", "arc", "Weak"];
pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
<|endoftext|>


<commit_before>use num::{BigUint, One, Zero};

const BITS: usize = 255;
const BYTES: usize = (BITS + 7) / 8;
const A24: u32 = 121665;

pub fn gen_pk(sk: &[u8]) -> Vec<u8> {
    let mut u = [0; 32];
    u[0] = 9;
    x25519(sk, &u)
}

/// This is horrible
/// and insecure
pub fn x25519(k: &[u8], u: &[u8]) -> Vec<u8> {
    assert_eq!(BYTES, k.len());
    assert_eq!(BYTES, u.len());
    let k = decode_scalar(k);
    let x_1 = decode_u_coordinate(u);
    let mut x_2 = One::one();
    let mut z_2 = Zero::zero();
    let mut x_3 = x_1.clone();
    let mut z_3 = One::one();
    let mut swap = Zero::zero();
    let a24: BigUint = A24.into();
    let p: BigUint = (BigUint::from(1u8) << 255) - BigUint::from(19u8);

    for t in (0..BITS).rev() {
        let k_t = (&k >> t) & BigUint::from(1u8);
        swap = swap ^ &k_t;
        cswap(&swap, &mut x_2, &mut x_3);
        cswap(&swap, &mut z_2, &mut z_3);
        swap = k_t;

        let a = (&x_2 + &z_2) % &p;
        let aa = &a * &a % &p;
        let b = (&p + &x_2 - &z_2) % &p;
        let bb = &b * &b % &p;
        let e = (&p + &aa - &bb) % &p;
        let c = (&x_3 + &z_3) % &p;
        let d = (&p + &x_3 - &z_3) % &p;
        let da = d * a % &p;
        let cb = c * b % &p;
        x_3 = (&da + &cb) % &p;
        x_3 = &x_3 * &x_3 % &p;
        z_3 = (&p + da - cb) % &p;
        z_3 = &x_1 * &z_3 * &z_3 % &p;
        x_2 = &aa * bb % &p;
        z_2 = &e * (aa + &a24 * &e) % &p;
    }
    cswap(&swap, &mut x_2, &mut x_3);
    cswap(&swap, &mut z_2, &mut z_3);
    let mut x = (x_2 * pow(z_2, &p) % &p).to_bytes_le();
    while x.len() < BYTES {
        x.push(0);
    }
    x
}

fn decode_u_coordinate(u: &[u8]) -> BigUint {
    let mut u_vec = u.to_vec();
    if BITS % 8 != 0 {
        if let Some(last) = u_vec.last_mut() {
            *last &= (1 << (BITS % 8)) - 1;
        }
    }
    BigUint::from_bytes_le(&u_vec)
}

fn decode_scalar(k: &[u8]) -> BigUint {
    let mut k_vec = k.to_vec();
    k_vec[0] &= 248;
    k_vec[31] &= 127;
    k_vec[31] |= 64;
    BigUint::from_bytes_le(&k_vec)
}

fn cswap(swap: &BigUint, x_2: &mut BigUint, x_3: &mut BigUint) {
    let dummy = mask(swap) & (&*x_2 ^ &*x_3);
    *x_2 = &*x_2 ^ &dummy;
    *x_3 = &*x_3 ^ &dummy;
}

fn mask(swap: &BigUint) -> BigUint {
    (BigUint::from(1u8) << 255) - swap
}

fn pow(z: BigUint, p: &BigUint) -> BigUint {
    let two: BigUint = 2u8.into();
    let mut res: BigUint = One::one();
    let mut base = z;
    let mut exponent = p - &two;
    while exponent > Zero::zero() {
        if &exponent % &two == One::one() {
            res = res * &base % p;
        }
        exponent = exponent >> 1;
        base = &base * &base % p;
    }
    res
}

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

    fn check(x: &str, k: &str, u: &str) {
        assert_eq!(h2b(x), x25519(&h2b(k), &h2b(u)));
    }

    fn check_decode(k: &str, u: &str, k10: &str, u10: &str) {
        assert_eq!(
            BigUint::parse_bytes(k10.as_bytes(), 10).unwrap(),
            decode_scalar(&h2b(k))
        );
        assert_eq!(
            BigUint::parse_bytes(u10.as_bytes(), 10).unwrap(),
            decode_u_coordinate(&h2b(u))
        );
    }

    #[test]
    fn test_x25519() {
        let mut k = "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4";
        let mut u = "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c";
        let mut x = "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552";
        check(x, k, u);

        let mut k10;
        let mut u10;
        k10 = "31029842492115040904895560451863089656472772604678260265531221036453811406496";
        u10 = "34426434033919594451155107781188821651316167215306631574996226621102155684838";
        check_decode(k, u, k10, u10);

        k = "4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d";
        u = "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493";
        x = "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957";
        check(x, k, u);

        k10 = "35156891815674817266734212754503633747128614016119564763269015315466259359304";
        u10 = "8883857351183929894090759386610649319417338800022198945255395922347792736741";
        check_decode(k, u, k10, u10);

        let mut k = h2b(
            "0900000000000000000000000000000000000000000000000000000000000000",
        );
        let mut u = k.clone();
        // too slow to do 1 mil iterations right now, or 1000 without --release
        for i in 0..1 {
            let x = x25519(&k, &u);
            if i == 0 {
                assert_eq!(
                    h2b(
                        "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079",
                    ),
                    x
                );
            } else if i == 999 {
                assert_eq!(
                    h2b(
                        "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079",
                    ),
                    x
                );
            } else if i == 999999 {
                assert_eq!(
                    h2b(
                        "7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424",
                    ),
                    x
                );
            }
            u = k;
            k = x;
        }
    }

    #[test]
    fn test_gen_pk() {
        let sk_a = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a";
        let pk_a = "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a";
        let sk_b = "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb";
        let pk_b = "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f";
        let k = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742";
        assert_eq!(h2b(pk_a), gen_pk(&h2b(sk_a)));
        assert_eq!(h2b(pk_b), gen_pk(&h2b(sk_b)));
        check(k, sk_a, pk_b);
        check(k, sk_b, pk_a);
    }
}
<commit_msg>curve25519: note on DH<commit_after>use num::{BigUint, One, Zero};

const BITS: usize = 255;
const BYTES: usize = (BITS + 7) / 8;
const A24: u32 = 121665;

/// After geting a shared secret, make sure to abort if it's 0
pub fn gen_pk(sk: &[u8]) -> Vec<u8> {
    let mut u = [0; 32];
    u[0] = 9;
    x25519(sk, &u)
}

/// This is horrible
/// and insecure
pub fn x25519(k: &[u8], u: &[u8]) -> Vec<u8> {
    assert_eq!(BYTES, k.len());
    assert_eq!(BYTES, u.len());
    let k = decode_scalar(k);
    let x_1 = decode_u_coordinate(u);
    let mut x_2 = One::one();
    let mut z_2 = Zero::zero();
    let mut x_3 = x_1.clone();
    let mut z_3 = One::one();
    let mut swap = Zero::zero();
    let a24: BigUint = A24.into();
    let p: BigUint = (BigUint::from(1u8) << 255) - BigUint::from(19u8);

    for t in (0..BITS).rev() {
        let k_t = (&k >> t) & BigUint::from(1u8);
        swap = swap ^ &k_t;
        cswap(&swap, &mut x_2, &mut x_3);
        cswap(&swap, &mut z_2, &mut z_3);
        swap = k_t;

        let a = (&x_2 + &z_2) % &p;
        let aa = &a * &a % &p;
        let b = (&p + &x_2 - &z_2) % &p;
        let bb = &b * &b % &p;
        let e = (&p + &aa - &bb) % &p;
        let c = (&x_3 + &z_3) % &p;
        let d = (&p + &x_3 - &z_3) % &p;
        let da = d * a % &p;
        let cb = c * b % &p;
        x_3 = (&da + &cb) % &p;
        x_3 = &x_3 * &x_3 % &p;
        z_3 = (&p + da - cb) % &p;
        z_3 = &x_1 * &z_3 * &z_3 % &p;
        x_2 = &aa * bb % &p;
        z_2 = &e * (aa + &a24 * &e) % &p;
    }
    cswap(&swap, &mut x_2, &mut x_3);
    cswap(&swap, &mut z_2, &mut z_3);
    let mut x = (x_2 * pow(z_2, &p) % &p).to_bytes_le();
    while x.len() < BYTES {
        x.push(0);
    }
    x
}

fn decode_u_coordinate(u: &[u8]) -> BigUint {
    let mut u_vec = u.to_vec();
    if BITS % 8 != 0 {
        if let Some(last) = u_vec.last_mut() {
            *last &= (1 << (BITS % 8)) - 1;
        }
    }
    BigUint::from_bytes_le(&u_vec)
}

fn decode_scalar(k: &[u8]) -> BigUint {
    let mut k_vec = k.to_vec();
    k_vec[0] &= 248;
    k_vec[31] &= 127;
    k_vec[31] |= 64;
    BigUint::from_bytes_le(&k_vec)
}

fn cswap(swap: &BigUint, x_2: &mut BigUint, x_3: &mut BigUint) {
    let dummy = mask(swap) & (&*x_2 ^ &*x_3);
    *x_2 = &*x_2 ^ &dummy;
    *x_3 = &*x_3 ^ &dummy;
}

fn mask(swap: &BigUint) -> BigUint {
    (BigUint::from(1u8) << 255) - swap
}

fn pow(z: BigUint, p: &BigUint) -> BigUint {
    let two: BigUint = 2u8.into();
    let mut res: BigUint = One::one();
    let mut base = z;
    let mut exponent = p - &two;
    while exponent > Zero::zero() {
        if &exponent % &two == One::one() {
            res = res * &base % p;
        }
        exponent = exponent >> 1;
        base = &base * &base % p;
    }
    res
}

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

    fn check(x: &str, k: &str, u: &str) {
        assert_eq!(h2b(x), x25519(&h2b(k), &h2b(u)));
    }

    fn check_decode(k: &str, u: &str, k10: &str, u10: &str) {
        assert_eq!(
            BigUint::parse_bytes(k10.as_bytes(), 10).unwrap(),
            decode_scalar(&h2b(k))
        );
        assert_eq!(
            BigUint::parse_bytes(u10.as_bytes(), 10).unwrap(),
            decode_u_coordinate(&h2b(u))
        );
    }

    #[test]
    fn test_x25519() {
        let mut k = "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4";
        let mut u = "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c";
        let mut x = "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552";
        check(x, k, u);

        let mut k10;
        let mut u10;
        k10 = "31029842492115040904895560451863089656472772604678260265531221036453811406496";
        u10 = "34426434033919594451155107781188821651316167215306631574996226621102155684838";
        check_decode(k, u, k10, u10);

        k = "4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d";
        u = "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493";
        x = "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957";
        check(x, k, u);

        k10 = "35156891815674817266734212754503633747128614016119564763269015315466259359304";
        u10 = "8883857351183929894090759386610649319417338800022198945255395922347792736741";
        check_decode(k, u, k10, u10);

        let mut k = h2b(
            "0900000000000000000000000000000000000000000000000000000000000000",
        );
        let mut u = k.clone();
        // too slow to do 1 mil iterations right now, or 1000 without --release
        for i in 0..1 {
            let x = x25519(&k, &u);
            if i == 0 {
                assert_eq!(
                    h2b(
                        "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079",
                    ),
                    x
                );
            } else if i == 999 {
                assert_eq!(
                    h2b(
                        "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079",
                    ),
                    x
                );
            } else if i == 999999 {
                assert_eq!(
                    h2b(
                        "7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424",
                    ),
                    x
                );
            }
            u = k;
            k = x;
        }
    }

    #[test]
    fn test_gen_pk() {
        let sk_a = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a";
        let pk_a = "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a";
        let sk_b = "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb";
        let pk_b = "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f";
        let k = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742";
        assert_eq!(h2b(pk_a), gen_pk(&h2b(sk_a)));
        assert_eq!(h2b(pk_b), gen_pk(&h2b(sk_b)));
        check(k, sk_a, pk_b);
        check(k, sk_b, pk_a);
    }
}
<|endoftext|>


<commit_before>pub mod cmd;

use std::mem;
use std::cell::RefCell;
use std::collections::HashMap;

use codegen::codegen::CodeGen;
use mem::CodeMemory;
use parser::ast::ctxt::Context;
use error::diag::Diagnostic;
use error::msg::Msg;

use parser::ast::{self, Function};
use parser::Parser;
use parser::lexer::position::Position;
use semck;
use sym::*;

pub fn compile() -> i32 {
    let args = cmd::parse();

    if args.flag_version {
        println!("dora v0.01b");
        return 0;
    }

    let mut parser = match Parser::from_file(&args.arg_file) {
        Err(_) => {
            println!("unable to read file `{}`", &args.arg_file);
            return 1;
        }

        Ok(parser) => parser
    };

    let (ast, interner) = match parser.parse() {
        Ok(ret) => ret,

        Err(error) => {
            error.print();
            return 1;
        }
    };

    if args.flag_emit_ast {
        ast::dump::dump(&ast, &interner);
    }

    let ast_map = ast::map::build(&ast, &interner);
    let ctxt = Context::new(&args, &interner, &ast_map, &ast);

    semck::check(&ctxt);

    let main = find_main(&ctxt);

    if ctxt.diag.borrow().has_errors() {
        ctxt.diag.borrow().dump();

        println!("{} error(s) found", ctxt.diag.borrow().errors().len());
        return 1;
    }

    let main = main.unwrap();

    let mut cg = CodeGen::new(&ctxt, main);
    let buffer = cg.generate().finish();

    if args.flag_emit_asm {
        dump_asm(&buffer, &ctxt.interner.str(main.name));
    }

    let code = CodeMemory::new(&buffer);

    let fct : extern "C" fn() -> i32 = unsafe { mem::transmute(code.ptr()) };
    let res = fct();

    // main-fct without return value exits with status 0
    if main.return_type.is_none() {
        0

    // use return value of main for exit status
    } else {
        res
    }
}

fn dump_asm(buf: &[u8], name: &str) {
    use capstone::*;

    let engine = Engine::new(Arch::X86, MODE_64).expect("cannot create capstone engine");
    let instrs = engine.disasm(buf, 0, buf.len()).expect("could not disassemble code");

    println!("fn {}", name);
    for instr in instrs {
        println!("  0x{:x}: {} {}", instr.addr, instr.mnemonic, instr.op_str);
    }
}

fn find_main<'a, 'ast>(ctxt: &Context<'a, 'ast>) -> Option<&'ast Function> where 'a: 'ast {
    let name = ctxt.interner.intern("main");
    let fctid = match ctxt.sym.borrow().get_function(name) {
        Some(id) => id,
        None => {
            ctxt.diag.borrow_mut().report(Position::new(1, 1), Msg::MainNotFound);
            return None;
        }
    };

    let fct_infos = ctxt.fct_infos.borrow();
    let fct = fct_infos.get(fctid.0).unwrap();
    let return_type = fct.return_type;

    if (return_type != BuiltinType::Unit && return_type != BuiltinType::Int) ||
        fct.params_types.len() > 0 {
        ctxt.diag.borrow_mut().report(fct.ast.unwrap().pos, Msg::WrongMainDefinition);
        return None;
    }

    Some(fct.ast.unwrap())
}
<commit_msg>better output format for addresses in disasm<commit_after>pub mod cmd;

use std::mem;
use std::cell::RefCell;
use std::collections::HashMap;

use codegen::codegen::CodeGen;
use mem::CodeMemory;
use parser::ast::ctxt::Context;
use error::diag::Diagnostic;
use error::msg::Msg;

use parser::ast::{self, Function};
use parser::Parser;
use parser::lexer::position::Position;
use semck;
use sym::*;

pub fn compile() -> i32 {
    let args = cmd::parse();

    if args.flag_version {
        println!("dora v0.01b");
        return 0;
    }

    let mut parser = match Parser::from_file(&args.arg_file) {
        Err(_) => {
            println!("unable to read file `{}`", &args.arg_file);
            return 1;
        }

        Ok(parser) => parser
    };

    let (ast, interner) = match parser.parse() {
        Ok(ret) => ret,

        Err(error) => {
            error.print();
            return 1;
        }
    };

    if args.flag_emit_ast {
        ast::dump::dump(&ast, &interner);
    }

    let ast_map = ast::map::build(&ast, &interner);
    let ctxt = Context::new(&args, &interner, &ast_map, &ast);

    semck::check(&ctxt);

    let main = find_main(&ctxt);

    if ctxt.diag.borrow().has_errors() {
        ctxt.diag.borrow().dump();

        println!("{} error(s) found", ctxt.diag.borrow().errors().len());
        return 1;
    }

    let main = main.unwrap();

    let mut cg = CodeGen::new(&ctxt, main);
    let buffer = cg.generate().finish();

    if args.flag_emit_asm {
        dump_asm(&buffer, &ctxt.interner.str(main.name));
    }

    let code = CodeMemory::new(&buffer);

    let fct : extern "C" fn() -> i32 = unsafe { mem::transmute(code.ptr()) };
    let res = fct();

    // main-fct without return value exits with status 0
    if main.return_type.is_none() {
        0

    // use return value of main for exit status
    } else {
        res
    }
}

fn dump_asm(buf: &[u8], name: &str) {
    use capstone::*;

    let engine = Engine::new(Arch::X86, MODE_64).expect("cannot create capstone engine");
    let instrs = engine.disasm(buf, 0, buf.len()).expect("could not disassemble code");

    println!("fn {}", name);
    for instr in instrs {
        println!("  {:#06x}: {} {}", instr.addr, instr.mnemonic, instr.op_str);
    }
}

fn find_main<'a, 'ast>(ctxt: &Context<'a, 'ast>) -> Option<&'ast Function> where 'a: 'ast {
    let name = ctxt.interner.intern("main");
    let fctid = match ctxt.sym.borrow().get_function(name) {
        Some(id) => id,
        None => {
            ctxt.diag.borrow_mut().report(Position::new(1, 1), Msg::MainNotFound);
            return None;
        }
    };

    let fct_infos = ctxt.fct_infos.borrow();
    let fct = fct_infos.get(fctid.0).unwrap();
    let return_type = fct.return_type;

    if (return_type != BuiltinType::Unit && return_type != BuiltinType::Int) ||
        fct.params_types.len() > 0 {
        ctxt.diag.borrow_mut().report(fct.ast.unwrap().pos, Msg::WrongMainDefinition);
        return None;
    }

    Some(fct.ast.unwrap())
}
<|endoftext|>