<commit_before>#[allow(warnings)]
#[cfg(target_pointer_width = "16")]
type c_int = i16;
#[allow(warnings)]
#[cfg(not(target_pointer_width = "16"))]
type c_int = i32;

use core::intrinsics::{atomic_load_unordered, atomic_store_unordered, unchecked_div};
use core::mem;
use core::ops::{BitOr, Shl};

#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)]
pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
    let mut i = 0;
    while i < n {
        *dest.offset(i as isize) = *src.offset(i as isize);
        i += 1;
    }
    dest
}

#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)]
pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
    if src < dest as *const u8 {
        // copy from end
        let mut i = n;
        while i != 0 {
            i -= 1;
            *dest.offset(i as isize) = *src.offset(i as isize);
        }
    } else {
        // copy from beginning
        let mut i = 0;
        while i < n {
            *dest.offset(i as isize) = *src.offset(i as isize);
            i += 1;
        }
    }
    dest
}

#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)]
pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 {
    let mut i = 0;
    while i < n {
        *s.offset(i as isize) = c as u8;
        i += 1;
    }
    s
}

#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)]
pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
    let mut i = 0;
    while i < n {
        let a = *s1.offset(i as isize);
        let b = *s2.offset(i as isize);
        if a != b {
            return a as i32 - b as i32;
        }
        i += 1;
    }
    0
}

fn memcpy_element_unordered_atomic<T: Copy>(dest: *mut T, src: *const T, bytes: usize) {
    unsafe {
        let n = unchecked_div(bytes, mem::size_of::<T>());
        let mut i = 0;
        while i < n {
            atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i)));
            i += 1;
        }
    }
}

fn memmove_element_unordered_atomic<T: Copy>(dest: *mut T, src: *const T, bytes: usize) {
    unsafe {
        let n = unchecked_div(bytes, mem::size_of::<T>());
        if src < dest as *const T {
            // copy from end
            let mut i = n;
            while i != 0 {
                i -= 1;
                atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i)));
            }
        } else {
            // copy from beginning
            let mut i = 0;
            while i < n {
                atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i)));
                i += 1;
            }
        }
    }
}

fn memset_element_unordered_atomic<T>(s: *mut T, c: u8, bytes: usize)
where
    T: Copy + From<u8> + Shl<u32, Output = T> + BitOr<T, Output = T>,
{
    unsafe {
        let n = unchecked_div(bytes, mem::size_of::<T>());
        let mut x = T::from(c);
        let mut i = 1;
        while i < mem::size_of::<T>() {
            x = x << 8 | T::from(c);
            i += 1;
        }
        let mut i = 0;
        while i < n {
            atomic_store_unordered(s.add(i), x);
            i += 1;
        }
    }
}

intrinsics! {
    pub extern "C" fn __llvm_memcpy_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () {
        memcpy_element_unordered_atomic(dest, src, bytes);
    }
    pub extern "C" fn __llvm_memcpy_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () {
        memcpy_element_unordered_atomic(dest, src, bytes);
    }
    pub extern "C" fn __llvm_memcpy_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () {
        memcpy_element_unordered_atomic(dest, src, bytes);
    }
    pub extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
        memcpy_element_unordered_atomic(dest, src, bytes);
    }
    pub extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
        memcpy_element_unordered_atomic(dest, src, bytes);
    }

    pub extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () {
        memmove_element_unordered_atomic(dest, src, bytes);
    }
    pub extern "C" fn __llvm_memmove_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () {
        memmove_element_unordered_atomic(dest, src, bytes);
    }
    pub extern "C" fn __llvm_memmove_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () {
        memmove_element_unordered_atomic(dest, src, bytes);
    }
    pub extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
        memmove_element_unordered_atomic(dest, src, bytes);
    }
    pub extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
        memmove_element_unordered_atomic(dest, src, bytes);
    }

    pub extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () {
        memset_element_unordered_atomic(s, c, bytes);
    }
    pub extern "C" fn __llvm_memset_element_unordered_atomic_2(s: *mut u16, c: u8, bytes: usize) -> () {
        memset_element_unordered_atomic(s, c, bytes);
    }
    pub extern "C" fn __llvm_memset_element_unordered_atomic_4(s: *mut u32, c: u8, bytes: usize) -> () {
        memset_element_unordered_atomic(s, c, bytes);
    }
    pub extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () {
        memset_element_unordered_atomic(s, c, bytes);
    }
    pub extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () {
        memset_element_unordered_atomic(s, c, bytes);
    }
}
<commit_msg>Tidy up unordered elementwise atomic memory intrinsics<commit_after>#[allow(warnings)]
#[cfg(target_pointer_width = "16")]
type c_int = i16;
#[allow(warnings)]
#[cfg(not(target_pointer_width = "16"))]
type c_int = i32;

use core::intrinsics::{atomic_load_unordered, atomic_store_unordered, exact_div};
use core::mem;
use core::ops::{BitOr, Shl};

#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)]
pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
    let mut i = 0;
    while i < n {
        *dest.offset(i as isize) = *src.offset(i as isize);
        i += 1;
    }
    dest
}

#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)]
pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
    if src < dest as *const u8 {
        // copy from end
        let mut i = n;
        while i != 0 {
            i -= 1;
            *dest.offset(i as isize) = *src.offset(i as isize);
        }
    } else {
        // copy from beginning
        let mut i = 0;
        while i < n {
            *dest.offset(i as isize) = *src.offset(i as isize);
            i += 1;
        }
    }
    dest
}

#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)]
pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 {
    let mut i = 0;
    while i < n {
        *s.offset(i as isize) = c as u8;
        i += 1;
    }
    s
}

#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)]
pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
    let mut i = 0;
    while i < n {
        let a = *s1.offset(i as isize);
        let b = *s2.offset(i as isize);
        if a != b {
            return a as i32 - b as i32;
        }
        i += 1;
    }
    0
}

// `bytes` must be a multiple of `mem::size_of::<T>()`
fn memcpy_element_unordered_atomic<T: Copy>(dest: *mut T, src: *const T, bytes: usize) {
    unsafe {
        let n = exact_div(bytes, mem::size_of::<T>());
        let mut i = 0;
        while i < n {
            atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i)));
            i += 1;
        }
    }
}

// `bytes` must be a multiple of `mem::size_of::<T>()`
fn memmove_element_unordered_atomic<T: Copy>(dest: *mut T, src: *const T, bytes: usize) {
    unsafe {
        let n = exact_div(bytes, mem::size_of::<T>());
        if src < dest as *const T {
            // copy from end
            let mut i = n;
            while i != 0 {
                i -= 1;
                atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i)));
            }
        } else {
            // copy from beginning
            let mut i = 0;
            while i < n {
                atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i)));
                i += 1;
            }
        }
    }
}

// `T` must be a primitive integer type, and `bytes` must be a multiple of `mem::size_of::<T>()`
fn memset_element_unordered_atomic<T>(s: *mut T, c: u8, bytes: usize)
where
    T: Copy + From<u8> + Shl<u32, Output = T> + BitOr<T, Output = T>,
{
    unsafe {
        let n = exact_div(bytes, mem::size_of::<T>());

        // Construct a value of type `T` consisting of repeated `c`
        // bytes, to let us ensure we write each `T` atomically.
        let mut x = T::from(c);
        let mut i = 1;
        while i < mem::size_of::<T>() {
            x = x << 8 | T::from(c);
            i += 1;
        }

        // Write it to `s`
        let mut i = 0;
        while i < n {
            atomic_store_unordered(s.add(i), x);
            i += 1;
        }
    }
}

intrinsics! {
    pub extern "C" fn __llvm_memcpy_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () {
        memcpy_element_unordered_atomic(dest, src, bytes);
    }
    pub extern "C" fn __llvm_memcpy_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () {
        memcpy_element_unordered_atomic(dest, src, bytes);
    }
    pub extern "C" fn __llvm_memcpy_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () {
        memcpy_element_unordered_atomic(dest, src, bytes);
    }
    pub extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
        memcpy_element_unordered_atomic(dest, src, bytes);
    }
    pub extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
        memcpy_element_unordered_atomic(dest, src, bytes);
    }

    pub extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () {
        memmove_element_unordered_atomic(dest, src, bytes);
    }
    pub extern "C" fn __llvm_memmove_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () {
        memmove_element_unordered_atomic(dest, src, bytes);
    }
    pub extern "C" fn __llvm_memmove_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () {
        memmove_element_unordered_atomic(dest, src, bytes);
    }
    pub extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
        memmove_element_unordered_atomic(dest, src, bytes);
    }
    pub extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
        memmove_element_unordered_atomic(dest, src, bytes);
    }

    pub extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () {
        memset_element_unordered_atomic(s, c, bytes);
    }
    pub extern "C" fn __llvm_memset_element_unordered_atomic_2(s: *mut u16, c: u8, bytes: usize) -> () {
        memset_element_unordered_atomic(s, c, bytes);
    }
    pub extern "C" fn __llvm_memset_element_unordered_atomic_4(s: *mut u32, c: u8, bytes: usize) -> () {
        memset_element_unordered_atomic(s, c, bytes);
    }
    pub extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () {
        memset_element_unordered_atomic(s, c, bytes);
    }
    pub extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () {
        memset_element_unordered_atomic(s, c, bytes);
    }
}
<|endoftext|>


<commit_before>#![crate_name = "serde_macros"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]

#![feature(plugin_registrar, quote)]

extern crate syntax;
extern crate rustc;

use std::gc::Gc;

use syntax::ast::{
    Ident,
    MetaItem,
    Item,
    Expr,
    MutMutable,
    LitNil,
};
use syntax::ast;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, ItemDecorator};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic::{
    EnumMatching,
    FieldInfo,
    MethodDef,
    Named,
    StaticFields,
    StaticStruct,
    StaticEnum,
    Struct,
    Substructure,
    TraitDef,
    Unnamed,
    combine_substructure,
};
use syntax::ext::deriving::generic::ty::{
    Borrowed,
    LifetimeBounds,
    Literal,
    Path,
    Ptr,
    Self,
    Tuple,
    borrowed_explicit_self,
};
use syntax::parse::token;

use rustc::plugin::Registry;

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
        token::intern("deriving_serializable"),
        ItemDecorator(expand_deriving_serializable));

    reg.register_syntax_extension(
        token::intern("deriving_deserializable"),
        ItemDecorator(expand_deriving_deserializable));
}

fn expand_deriving_serializable(cx: &mut ExtCtxt,
                                sp: Span,
                                mitem: Gc<MetaItem>,
                                item: Gc<Item>,
                                push: |Gc<ast::Item>|) {
    let inline = cx.meta_word(sp, token::InternedString::new("inline"));
    let attrs = vec!(cx.attribute(sp, inline));

    let trait_def = TraitDef {
        span: sp,
        attributes: vec!(),
        path: Path::new_(vec!("serde", "ser", "Serializable"), None,
                         vec!(box Literal(Path::new_local("__S")),
                              box Literal(Path::new_local("__E"))), true),
        additional_bounds: Vec::new(),
        generics: LifetimeBounds {
            lifetimes: Vec::new(),
            bounds: vec!(("__S", None, vec!(Path::new_(
                            vec!("serde", "ser", "Serializer"), None,
                            vec!(box Literal(Path::new_local("__E"))), true))),
                         ("__E", None, vec!()))
        },
        methods: vec!(
            MethodDef {
                name: "serialize",
                generics: LifetimeBounds::empty(),
                explicit_self: borrowed_explicit_self(),
                args: vec!(Ptr(box Literal(Path::new_local("__S")),
                            Borrowed(None, MutMutable))),
                ret_ty: Literal(
                    Path::new_(
                        vec!("std", "result", "Result"),
                        None,
                        vec!(
                            box Tuple(Vec::new()),
                            box Literal(Path::new_local("__E"))
                        ),
                        true
                    )
                ),
                attributes: attrs,
                combine_substructure: combine_substructure(|a, b, c| {
                    serializable_substructure(a, b, c)
                }),
            })
    };

    trait_def.expand(cx, mitem, item, push)
}

fn serializable_substructure(cx: &ExtCtxt, span: Span,
                          substr: &Substructure) -> Gc<Expr> {
    let serializer = substr.nonself_args[0];

    return match *substr.fields {
        Struct(ref fields) => {
            if fields.is_empty() {
                // unit structs have no fields and need to return `Ok()`
                quote_expr!(cx, Ok(()))
            } else {
                let type_name = cx.expr_str(
                    span,
                    token::get_ident(substr.type_ident)
                );
                let len = fields.len();

                let mut stmts: Vec<Gc<ast::Stmt>> = fields.iter()
                    .enumerate()
                    .map(|(i, &FieldInfo { name, self_, span, .. })| {
                        let name = match name {
                            Some(id) => token::get_ident(id),
                            None => token::intern_and_get_ident(format!("_field{}", i).as_slice()),
                        };

                        let name = cx.expr_str(span, name);

                        quote_stmt!(
                            cx,
                            try!($serializer.serialize_struct_elt($name, &$self_))
                        )
                    })
                    .collect();

                quote_expr!(cx, {
                    try!($serializer.serialize_struct_start($type_name, $len));
                    $stmts
                    $serializer.serialize_struct_end()
                })
            }
        }

        EnumMatching(_idx, variant, ref fields) => {
            let type_name = cx.expr_str(
                span,
                token::get_ident(substr.type_ident)
            );
            let variant_name = cx.expr_str(
                span,
                token::get_ident(variant.node.name)
            );
            let len = fields.len();

            let stmts: Vec<Gc<ast::Stmt>> = fields.iter()
                .map(|&FieldInfo { self_, span, .. }| {
                    quote_stmt!(
                        cx,
                        try!($serializer.serialize_enum_elt(&$self_))
                    )
                })
                .collect();

            quote_expr!(cx, {
                try!($serializer.serialize_enum_start($type_name, $variant_name, $len));
                $stmts
                $serializer.serialize_enum_end()
            })
        }

        _ => cx.bug("expected Struct or EnumMatching in deriving_serializable")
    }
}

pub fn expand_deriving_deserializable(cx: &mut ExtCtxt,
                                      span: Span,
                                      mitem: Gc<MetaItem>,
                                      item: Gc<Item>,
                                      push: |Gc<Item>|) {
    let trait_def = TraitDef {
        span: span,
        attributes: Vec::new(),
        path: Path::new_(vec!("serde", "de", "Deserializable"), None,
                         vec!(box Literal(Path::new_local("__D")),
                              box Literal(Path::new_local("__E"))), true),
        additional_bounds: Vec::new(),
        generics: LifetimeBounds {
            lifetimes: Vec::new(),
            bounds: vec!(("__D", None, vec!(Path::new_(
                            vec!("serde", "de", "Deserializer"), None,
                            vec!(box Literal(Path::new_local("__E"))), true))),
                         ("__E", None, vec!()))
        },
        methods: vec!(
            MethodDef {
                name: "deserialize_token",
                generics: LifetimeBounds::empty(),
                explicit_self: None,
                args: vec!(
                    Ptr(
                        box Literal(Path::new_local("__D")),
                        Borrowed(None, MutMutable)
                    ),
                    Literal(Path::new(vec!("serde", "de", "Token"))),
                ),
                ret_ty: Literal(
                    Path::new_(
                        vec!("std", "result", "Result"),
                        None,
                        vec!(
                            box Self,
                            box Literal(Path::new_local("__E"))
                        ),
                        true
                    )
                ),
                attributes: Vec::new(),
                combine_substructure: combine_substructure(|a, b, c| {
                    deserializable_substructure(a, b, c)
                }),
            })
    };

    trait_def.expand(cx, mitem, item, push)
}

fn deserializable_substructure(cx: &mut ExtCtxt, span: Span,
                               substr: &Substructure) -> Gc<Expr> {
    let deserializer = substr.nonself_args[0];
    let token = substr.nonself_args[1];

    match *substr.fields {
        StaticStruct(_, ref fields) => {
            deserialize_struct(
                cx,
                span,
                substr.type_ident,
                fields,
                deserializer,
                token)
        }
        StaticEnum(_, ref fields) => {
            deserialize_enum(
                cx,
                span,
                substr.type_ident,
                fields.as_slice(),
                deserializer,
                token)
        }
        _ => cx.bug("expected StaticEnum or StaticStruct in deriving(Deserializable)")
    }
}

fn deserialize_struct(
    cx: &ExtCtxt,
    span: Span,
    type_ident: Ident,
    fields: &StaticFields,
    deserializer: Gc<ast::Expr>,
    token: Gc<ast::Expr>
) -> Gc<ast::Expr> {
    let struct_block = deserialize_struct_from_struct(
        cx,
        span,
        type_ident,
        fields,
        deserializer
    );

    let map_block = deserialize_struct_from_map(
        cx,
        span,
        type_ident,
        fields,
        deserializer
    );

    quote_expr!(
        cx,
        match $token {
            ::serde::de::StructStart(_, _) => $struct_block,
            ::serde::de::MapStart(_) => $map_block,
            token => {
                let expected_tokens = [
                    ::serde::de::StructStartKind,
                    ::serde::de::MapStartKind,
                ];
                Err($deserializer.syntax_error(token, expected_tokens))
            }
        }
    )
}

fn deserialize_struct_from_struct(
    cx: &ExtCtxt,
    span: Span,
    type_ident: Ident,
    fields: &StaticFields,
    deserializer: Gc<ast::Expr>
) -> Gc<ast::Expr> {
    let expect_struct_field = cx.ident_of("expect_struct_field");

    let call = deserializable_static_fields(
        cx,
        span,
        type_ident,
        fields,
        |cx, span, name| {
            let name = cx.expr_str(span, name);
            quote_expr!(
                cx,
                try!($deserializer.expect_struct_field($name))
            )
        }
    );

    quote_expr!(cx, {
        let result = $call;
        try!($deserializer.expect_struct_end());
        Ok(result)
    })
}

fn deserialize_struct_from_map(
    cx: &ExtCtxt,
    span: Span,
    type_ident: Ident,
    fields: &StaticFields,
    deserializer: Gc<ast::Expr>
) -> Gc<ast::Expr> {
    let fields = match *fields {
        Unnamed(_) => fail!(),
        Named(ref fields) => fields.as_slice(),
    };

    // Declare each field.
    let let_fields: Vec<Gc<ast::Stmt>> = fields.iter()
        .map(|&(name, span)| {
            quote_stmt!(cx, let mut $name = None)
        })
        .collect();

    // Declare key arms.
    let key_arms: Vec<ast::Arm> = fields.iter()
        .map(|&(name, span)| {
            let s = cx.expr_str(span, token::get_ident(name));
            quote_arm!(cx,
                $s => {
                    $name = Some(
                        try!(::serde::de::Deserializable::deserialize($deserializer))
                    );
                    continue;
                })
        })
        .collect();

    let extract_fields: Vec<Gc<ast::Stmt>> = fields.iter()
        .map(|&(name, span)| {
            let name_str = cx.expr_str(span, token::get_ident(name));
            quote_stmt!(cx,
                let $name = match $name {
                    Some($name) => $name,
                    None => try!($deserializer.missing_field($name_str)),
                };
            )
        })
        .collect();

    let result = cx.expr_struct_ident(
        span,
        type_ident,
        fields.iter()
            .map(|&(name, span)| {
                cx.field_imm(span, name, cx.expr_ident(span, name))
            })
            .collect()
    );

    quote_expr!(cx, {
        $let_fields

        loop {
            let token = match try!($deserializer.expect_token()) {
                ::serde::de::End => { break; }
                token => token,
            };

            {
                let key = match token {
                    ::serde::de::Str(s) => s,
                    ::serde::de::String(ref s) => s.as_slice(),
                    token => {
                        let expected_tokens = [
                            ::serde::de::StrKind,
                            ::serde::de::StringKind,
                        ];
                        return Err($deserializer.syntax_error(token, expected_tokens));
                    }
                };

                match key {
                    $key_arms
                    _ => { }
                }
            }

            try!($deserializer.ignore_field(token))
        }

        $extract_fields
        Ok($result)
    })
}

fn deserialize_enum(
    cx: &ExtCtxt,
    span: Span,
    type_ident: Ident,
    fields: &[(Ident, Span, StaticFields)],
    deserializer: Gc<ast::Expr>,
    token: Gc<ast::Expr>
) -> Gc<ast::Expr> {
    let type_name = cx.expr_str(span, token::get_ident(type_ident));

    let variants = fields.iter()
        .map(|&(name, span, _)| {
            cx.expr_str(span, token::get_ident(name))
        })
        .collect();

    let variants = cx.expr_vec(span, variants);

    let arms: Vec<ast::Arm> = fields.iter()
        .enumerate()
        .map(|(i, &(name, span, ref parts))| {
            let call = deserializable_static_fields(
                cx,
                span,
                name,
                parts,
                |cx, span, _| {
                    quote_expr!(cx, try!($deserializer.expect_enum_elt()))
                }
            );

            quote_arm!(cx, $i => $call,)
        })
        .collect();

    quote_expr!(cx, {
        let i = try!($deserializer.expect_enum_start($token, $type_name, $variants));

        let result = match i {
            $arms
            _ => { unreachable!() }
        };

        try!($deserializer.expect_enum_end());

        Ok(result)
    })
}

/// Create a deserializer for a single enum variant/struct:
/// - `outer_pat_ident` is the name of this enum variant/struct
/// - `getarg` should retrieve the `uint`-th field with name `&str`.
fn deserializable_static_fields(
    cx: &ExtCtxt,
    span: Span,
    outer_pat_ident: Ident,
    fields: &StaticFields,
    getarg: |&ExtCtxt, Span, token::InternedString| -> Gc<Expr>
) -> Gc<Expr> {
    match *fields {
        Unnamed(ref fields) => {
            if fields.is_empty() {
                cx.expr_ident(span, outer_pat_ident)
            } else {
                let fields = fields.iter().enumerate().map(|(i, &span)| {
                    getarg(
                        cx,
                        span,
                        token::intern_and_get_ident(format!("_field{}", i).as_slice())
                    )
                }).collect();

                cx.expr_call_ident(span, outer_pat_ident, fields)
            }
        }
        Named(ref fields) => {
            // use the field's span to get nicer error messages.
            let fields = fields.iter().map(|&(name, span)| {
                let arg = getarg(
                    cx,
                    span,
                    token::get_ident(name)
                );
                cx.field_imm(span, name, arg)
            }).collect();

            cx.expr_struct_ident(span, outer_pat_ident, fields)
        }
    }
}
<commit_msg>Implemented serial_name attribute<commit_after>#![crate_name = "serde_macros"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]

#![feature(plugin_registrar, quote)]

extern crate syntax;
extern crate rustc;

use std::gc::Gc;

use syntax::ast::{
    Attribute,
    Ident,
    MetaItem,
    MetaNameValue,
    Item,
    Expr,
    MutMutable,
    LitNil,
    LitStr,
    P,
    StructField,
    Variant,
};
use syntax::ast;
use syntax::attr;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, ItemDecorator};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic::{
    EnumMatching,
    FieldInfo,
    MethodDef,
    Named,
    StaticFields,
    StaticStruct,
    StaticEnum,
    Struct,
    Substructure,
    TraitDef,
    Unnamed,
    combine_substructure,
};
use syntax::ext::deriving::generic::ty::{
    Borrowed,
    LifetimeBounds,
    Literal,
    Path,
    Ptr,
    Self,
    Tuple,
    borrowed_explicit_self,
};
use syntax::parse::token;

use rustc::plugin::Registry;

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
        token::intern("deriving_serializable"),
        ItemDecorator(expand_deriving_serializable));

    reg.register_syntax_extension(
        token::intern("deriving_deserializable"),
        ItemDecorator(expand_deriving_deserializable));
}

fn expand_deriving_serializable(cx: &mut ExtCtxt,
                                sp: Span,
                                mitem: Gc<MetaItem>,
                                item: Gc<Item>,
                                push: |Gc<ast::Item>|) {
    let inline = cx.meta_word(sp, token::InternedString::new("inline"));
    let attrs = vec!(cx.attribute(sp, inline));

    let trait_def = TraitDef {
        span: sp,
        attributes: vec!(),
        path: Path::new_(vec!("serde", "ser", "Serializable"), None,
                         vec!(box Literal(Path::new_local("__S")),
                              box Literal(Path::new_local("__E"))), true),
        additional_bounds: Vec::new(),
        generics: LifetimeBounds {
            lifetimes: Vec::new(),
            bounds: vec!(("__S", None, vec!(Path::new_(
                            vec!("serde", "ser", "Serializer"), None,
                            vec!(box Literal(Path::new_local("__E"))), true))),
                         ("__E", None, vec!()))
        },
        methods: vec!(
            MethodDef {
                name: "serialize",
                generics: LifetimeBounds::empty(),
                explicit_self: borrowed_explicit_self(),
                args: vec!(Ptr(box Literal(Path::new_local("__S")),
                            Borrowed(None, MutMutable))),
                ret_ty: Literal(
                    Path::new_(
                        vec!("std", "result", "Result"),
                        None,
                        vec!(
                            box Tuple(Vec::new()),
                            box Literal(Path::new_local("__E"))
                        ),
                        true
                    )
                ),
                attributes: attrs,
                combine_substructure: combine_substructure(|a, b, c| {
                    serializable_substructure(a, b, c)
                }),
            })
    };

    trait_def.expand(cx, mitem, item, push)
}

fn serializable_substructure(cx: &ExtCtxt, span: Span,
                          substr: &Substructure) -> Gc<Expr> {
    let serializer = substr.nonself_args[0];

    return match *substr.fields {
        Struct(ref fields) => {
            if fields.is_empty() {
                // unit structs have no fields and need to return `Ok()`
                quote_expr!(cx, Ok(()))
            } else {
                let type_name = cx.expr_str(
                    span,
                    token::get_ident(substr.type_ident)
                );
                let len = fields.len();

                let mut stmts: Vec<Gc<ast::Stmt>> = fields.iter()
                    .enumerate()
                    .map(|(i, &FieldInfo { name, self_, span, .. })| {
                        let name = match name {
                            Some(id) => token::get_ident(id),
                            None => token::intern_and_get_ident(format!("_field{}", i).as_slice()),
                        };

                        let name = cx.expr_str(span, name);

                        quote_stmt!(
                            cx,
                            try!($serializer.serialize_struct_elt($name, &$self_))
                        )
                    })
                    .collect();

                quote_expr!(cx, {
                    try!($serializer.serialize_struct_start($type_name, $len));
                    $stmts
                    $serializer.serialize_struct_end()
                })
            }
        }

        EnumMatching(_idx, variant, ref fields) => {
            let type_name = cx.expr_str(
                span,
                token::get_ident(substr.type_ident)
            );
            let variant_name = cx.expr_str(
                span,
                token::get_ident(variant.node.name)
            );
            let len = fields.len();

            let stmts: Vec<Gc<ast::Stmt>> = fields.iter()
                .map(|&FieldInfo { self_, span, .. }| {
                    quote_stmt!(
                        cx,
                        try!($serializer.serialize_enum_elt(&$self_))
                    )
                })
                .collect();

            quote_expr!(cx, {
                try!($serializer.serialize_enum_start($type_name, $variant_name, $len));
                $stmts
                $serializer.serialize_enum_end()
            })
        }

        _ => cx.bug("expected Struct or EnumMatching in deriving_serializable")
    }
}

pub fn expand_deriving_deserializable(cx: &mut ExtCtxt,
                                      span: Span,
                                      mitem: Gc<MetaItem>,
                                      item: Gc<Item>,
                                      push: |Gc<Item>|) {
    let trait_def = TraitDef {
        span: span,
        attributes: Vec::new(),
        path: Path::new_(vec!("serde", "de", "Deserializable"), None,
                         vec!(box Literal(Path::new_local("__D")),
                              box Literal(Path::new_local("__E"))), true),
        additional_bounds: Vec::new(),
        generics: LifetimeBounds {
            lifetimes: Vec::new(),
            bounds: vec!(("__D", None, vec!(Path::new_(
                            vec!("serde", "de", "Deserializer"), None,
                            vec!(box Literal(Path::new_local("__E"))), true))),
                         ("__E", None, vec!()))
        },
        methods: vec!(
            MethodDef {
                name: "deserialize_token",
                generics: LifetimeBounds::empty(),
                explicit_self: None,
                args: vec!(
                    Ptr(
                        box Literal(Path::new_local("__D")),
                        Borrowed(None, MutMutable)
                    ),
                    Literal(Path::new(vec!("serde", "de", "Token"))),
                ),
                ret_ty: Literal(
                    Path::new_(
                        vec!("std", "result", "Result"),
                        None,
                        vec!(
                            box Self,
                            box Literal(Path::new_local("__E"))
                        ),
                        true
                    )
                ),
                attributes: Vec::new(),
                combine_substructure: combine_substructure(|a, b, c| {
                    deserializable_substructure(a, b, c)
                }),
            })
    };

    trait_def.expand(cx, mitem, item, push)
}

fn deserializable_substructure(cx: &mut ExtCtxt, span: Span,
                               substr: &Substructure) -> Gc<Expr> {
    let deserializer = substr.nonself_args[0];
    let token = substr.nonself_args[1];

    match *substr.fields {
        StaticStruct(ref definition, ref fields) => {
            deserialize_struct(
                cx,
                span,
                substr.type_ident,
                definition.fields.as_slice(),
                fields,
                deserializer,
                token)
        }
        StaticEnum(ref definition, ref fields) => {
            deserialize_enum(
                cx,
                span,
                substr.type_ident,
                definition.variants.as_slice(),
                fields.as_slice(),
                deserializer,
                token)
        }
        _ => cx.bug("expected StaticEnum or StaticStruct in deriving(Deserializable)")
    }
}

fn find_serial_name<'a, I: Iterator<&'a Attribute>>(mut iterator: I)
                    -> Option<token::InternedString> {
    for at in iterator {
        match at.node.value.node {
            MetaNameValue(ref at_name, ref value) => {
                match (at_name.get(), &value.node) {
                    ("serial_name", &LitStr(ref string, _)) => {
                        attr::mark_used(at);
                        return Some(string.clone());
                    },
                    _ => ()
                }
            },
            _ => ()
        }
    }
    None
}

fn deserialize_struct(
    cx: &ExtCtxt,
    span: Span,
    type_ident: Ident,
    definitions: &[StructField],
    fields: &StaticFields,
    deserializer: Gc<ast::Expr>,
    token: Gc<ast::Expr>
) -> Gc<ast::Expr> {
    let serial_names = definitions.iter().map(|def|
        find_serial_name(def.node.attrs.iter())
    ).collect();

    let struct_block = deserialize_struct_from_struct(
        cx,
        span,
        type_ident,
        serial_names,
        fields,
        deserializer
    );

    let map_block = deserialize_struct_from_map(
        cx,
        span,
        type_ident,
        fields,
        deserializer
    );

    quote_expr!(
        cx,
        match $token {
            ::serde::de::StructStart(_, _) => $struct_block,
            ::serde::de::MapStart(_) => $map_block,
            token => {
                let expected_tokens = [
                    ::serde::de::StructStartKind,
                    ::serde::de::MapStartKind,
                ];
                Err($deserializer.syntax_error(token, expected_tokens))
            }
        }
    )
}

fn deserialize_struct_from_struct(
    cx: &ExtCtxt,
    span: Span,
    type_ident: Ident,
    serial_names: Vec<Option<token::InternedString>>,
    fields: &StaticFields,
    deserializer: Gc<ast::Expr>
) -> Gc<ast::Expr> {
    let expect_struct_field = cx.ident_of("expect_struct_field");

    let call = deserializable_static_fields(
        cx,
        span,
        type_ident,
        serial_names.as_slice(),
        fields,
        |cx, span, name| {
            let name = cx.expr_str(span, name);
            quote_expr!(
                cx,
                try!($deserializer.expect_struct_field($name))
            )
        }
    );

    quote_expr!(cx, {
        let result = $call;
        try!($deserializer.expect_struct_end());
        Ok(result)
    })
}

fn deserialize_struct_from_map(
    cx: &ExtCtxt,
    span: Span,
    type_ident: Ident,
    fields: &StaticFields,
    deserializer: Gc<ast::Expr>
) -> Gc<ast::Expr> {
    let fields = match *fields {
        Unnamed(_) => fail!(),
        Named(ref fields) => fields.as_slice(),
    };

    // Declare each field.
    let let_fields: Vec<Gc<ast::Stmt>> = fields.iter()
        .map(|&(name, span)| {
            quote_stmt!(cx, let mut $name = None)
        })
        .collect();

    // Declare key arms.
    let key_arms: Vec<ast::Arm> = fields.iter()
        .map(|&(name, span)| {
            let s = cx.expr_str(span, token::get_ident(name));
            quote_arm!(cx,
                $s => {
                    $name = Some(
                        try!(::serde::de::Deserializable::deserialize($deserializer))
                    );
                    continue;
                })
        })
        .collect();

    let extract_fields: Vec<Gc<ast::Stmt>> = fields.iter()
        .map(|&(name, span)| {
            let name_str = cx.expr_str(span, token::get_ident(name));
            quote_stmt!(cx,
                let $name = match $name {
                    Some($name) => $name,
                    None => try!($deserializer.missing_field($name_str)),
                };
            )
        })
        .collect();

    let result = cx.expr_struct_ident(
        span,
        type_ident,
        fields.iter()
            .map(|&(name, span)| {
                cx.field_imm(span, name, cx.expr_ident(span, name))
            })
            .collect()
    );

    quote_expr!(cx, {
        $let_fields

        loop {
            let token = match try!($deserializer.expect_token()) {
                ::serde::de::End => { break; }
                token => token,
            };

            {
                let key = match token {
                    ::serde::de::Str(s) => s,
                    ::serde::de::String(ref s) => s.as_slice(),
                    token => {
                        let expected_tokens = [
                            ::serde::de::StrKind,
                            ::serde::de::StringKind,
                        ];
                        return Err($deserializer.syntax_error(token, expected_tokens));
                    }
                };

                match key {
                    $key_arms
                    _ => { }
                }
            }

            try!($deserializer.ignore_field(token))
        }

        $extract_fields
        Ok($result)
    })
}

fn deserialize_enum(
    cx: &ExtCtxt,
    span: Span,
    type_ident: Ident,
    definitions: &[P<Variant>],
    fields: &[(Ident, Span, StaticFields)],
    deserializer: Gc<ast::Expr>,
    token: Gc<ast::Expr>
) -> Gc<ast::Expr> {
    let type_name = cx.expr_str(span, token::get_ident(type_ident));

    let serial_names = definitions.iter().map(|def|
        find_serial_name(def.node.attrs.iter())
    ).collect::<Vec<Option<token::InternedString>>>();

    let variants = fields.iter()
        .map(|&(name, span, _)| {
            cx.expr_str(span, token::get_ident(name))
        })
        .collect();

    let variants = cx.expr_vec(span, variants);

    let arms: Vec<ast::Arm> = fields.iter()
        .enumerate()
        .map(|(i, &(name, span, ref parts))| {
            let call = deserializable_static_fields(
                cx,
                span,
                name,
                serial_names.as_slice(),
                parts,
                |cx, span, _| {
                    quote_expr!(cx, try!($deserializer.expect_enum_elt()))
                }
            );

            quote_arm!(cx, $i => $call,)
        })
        .collect();

    quote_expr!(cx, {
        let i = try!($deserializer.expect_enum_start($token, $type_name, $variants));

        let result = match i {
            $arms
            _ => { unreachable!() }
        };

        try!($deserializer.expect_enum_end());

        Ok(result)
    })
}

/// Create a deserializer for a single enum variant/struct:
/// - `outer_pat_ident` is the name of this enum variant/struct
/// - `getarg` should retrieve the `uint`-th field with name `&str`.
fn deserializable_static_fields(
    cx: &ExtCtxt,
    span: Span,
    outer_pat_ident: Ident,
    serial_names: &[Option<token::InternedString>],
    fields: &StaticFields,
    getarg: |&ExtCtxt, Span, token::InternedString| -> Gc<Expr>
) -> Gc<Expr> {
    match *fields {
        Unnamed(ref fields) => {
            if fields.is_empty() {
                cx.expr_ident(span, outer_pat_ident)
            } else {
                let fields = fields.iter().enumerate().map(|(i, &span)| {
                    getarg(
                        cx,
                        span,
                        token::intern_and_get_ident(format!("_field{}", i).as_slice())
                    )
                }).collect();

                cx.expr_call_ident(span, outer_pat_ident, fields)
            }
        }
        Named(ref fields) => {
            // use the field's span to get nicer error messages.
            let fields = serial_names.iter()
                .zip(fields.iter()).map(|(serial_name, &(name, span))| {
                let effective_name = serial_name.clone().unwrap_or(
                    token::get_ident(name)
                );
                let arg = getarg(
                    cx,
                    span,
                    effective_name
                );
                cx.field_imm(span, name, arg)
            }).collect();

            cx.expr_struct_ident(span, outer_pat_ident, fields)
        }
    }
}
<|endoftext|>


<commit_before>#![allow(non_upper_case_globals)]

const cobalt_yml: &'static [u8] = b"name: cobalt blog
source: \".\"
dest: \"build\"
ignore:
  - .git/*
  - build/*
";

const default_liquid: &'static [u8] = b"<!DOCTYPE html>

        {% if is_post %}
          <title>{{ title }}</title>
        {% else %}
       	  <title>Cobalt.rs Blog</title>
        {% endif %}

      {% if is_post %}
        {% include '_layouts/post.liquid' %}
      {% else %}
        {{ content }}
      {% endif %}

";

const post_liquid: &'static [u8] = b"

{{ title }}

    {{content}}

";

const post_1_md: &'static [u8] = b"extends: default.liquid

title: First Post
date: 14 January 2016 21:00:30 -0500
---

# This is our first Post!

Welcome to the first post ever on cobalt.rs!
";

const index_liquid: &'static [u8] = b"extends: default.liquid
---

Blog!

    {% for post in posts %}

{{post.title}}

{{ post.title }}

    {% endfor %}

";

use std::path::Path;
use std::fs::{DirBuilder, OpenOptions};
use std::io::Write;
use error::Result;

pub fn create_new_project<P: AsRef<Path>>(dest: P) -> Result<()> {
    let dest = dest.as_ref();

    try!(create_folder(&dest));

    try!(create_file(&dest.join(".cobalt.yml"), cobalt_yml));
    try!(create_file(&dest.join("index.liquid"), index_liquid));

    try!(create_folder(&dest.join("_layouts")));
    try!(create_file(&dest.join("_layouts/default.liquid"), default_liquid));
    try!(create_file(&dest.join("_layouts/post.liquid"), post_liquid));

    try!(create_folder(&dest.join("posts")));
    try!(create_file(&dest.join("posts/post-1.md"), post_1_md));

    Ok(())
}

fn create_folder<P: AsRef<Path>>(path: P) -> Result<()> {
    trace!("Creating folder {:?}", &path.as_ref());

    try!(DirBuilder::new()
        .recursive(true)
        .create(path));

    Ok(())
}

fn create_file<P: AsRef<Path>>(name: P, content: &[u8]) -> Result<()> {
    trace!("Creating file {:?}", &name.as_ref());

    let mut file = try!(OpenOptions::new()
        .write(true)
        .create(true)
        .open(name));

    try!(file.write_all(content));

    Ok(())
}
<commit_msg>Set charset utf-8 in the default template<commit_after>#![allow(non_upper_case_globals)]

const cobalt_yml: &'static [u8] = b"name: cobalt blog
source: \".\"
dest: \"build\"
ignore:
  - .git/*
  - build/*
";

const default_liquid: &'static [u8] = b"<!DOCTYPE html>

        <meta charset=\"utf-8\">
        {% if is_post %}
          <title>{{ title }}</title>
        {% else %}
       	  <title>Cobalt.rs Blog</title>
        {% endif %}

      {% if is_post %}
        {% include '_layouts/post.liquid' %}
      {% else %}
        {{ content }}
      {% endif %}

";

const post_liquid: &'static [u8] = b"

{{ title }}

    {{content}}

";

const post_1_md: &'static [u8] = b"extends: default.liquid

title: First Post
date: 14 January 2016 21:00:30 -0500
---

# This is our first Post!

Welcome to the first post ever on cobalt.rs!
";

const index_liquid: &'static [u8] = b"extends: default.liquid
---

Blog!

    {% for post in posts %}

{{post.title}}

{{ post.title }}

    {% endfor %}

";

use std::path::Path;
use std::fs::{DirBuilder, OpenOptions};
use std::io::Write;
use error::Result;

pub fn create_new_project<P: AsRef<Path>>(dest: P) -> Result<()> {
    let dest = dest.as_ref();

    try!(create_folder(&dest));

    try!(create_file(&dest.join(".cobalt.yml"), cobalt_yml));
    try!(create_file(&dest.join("index.liquid"), index_liquid));

    try!(create_folder(&dest.join("_layouts")));
    try!(create_file(&dest.join("_layouts/default.liquid"), default_liquid));
    try!(create_file(&dest.join("_layouts/post.liquid"), post_liquid));

    try!(create_folder(&dest.join("posts")));
    try!(create_file(&dest.join("posts/post-1.md"), post_1_md));

    Ok(())
}

fn create_folder<P: AsRef<Path>>(path: P) -> Result<()> {
    trace!("Creating folder {:?}", &path.as_ref());

    try!(DirBuilder::new()
        .recursive(true)
        .create(path));

    Ok(())
}

fn create_file<P: AsRef<Path>>(name: P, content: &[u8]) -> Result<()> {
    trace!("Creating file {:?}", &name.as_ref());

    let mut file = try!(OpenOptions::new()
        .write(true)
        .create(true)
        .open(name));

    try!(file.write_all(content));

    Ok(())
}
<|endoftext|>


<commit_before>use std::error::{Error};
use std::fmt;

use base::{FromAscii};

/// An error returned when parsing a numeric value from a ascii string fails.
#[derive(Debug, Clone, PartialEq)]
pub struct ParseIntError {
    kind: IntErrorKind
}

#[derive(Debug, Clone, PartialEq)]
enum IntErrorKind {
    Empty,
    InvalidDigit(u8),
    Overflow,
    Underflow,
    InvalidRadix(u8),
}

impl IntErrorKind {
    fn description(&self) -> &str {
        match self {
            &IntErrorKind::Empty => "cannot parse integer from empty string",
            &IntErrorKind::InvalidDigit(_) => "invalid digit found in string",
            &IntErrorKind::Overflow => "number too large to fit in target type",
            &IntErrorKind::Underflow => "number too small to fit in target type",
            &IntErrorKind::InvalidRadix(_) => "radix should be in 2..36 range",
        }
    }
}

impl fmt::Display for ParseIntError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.kind.description().fmt(f)
    }
}

impl Error for ParseIntError {
    fn description(&self) -> &str {
        self.kind.description()
    }
}

#[inline]
pub fn dec_to_digit(c: u8, radix: u8) -> Option<u8> {
    let val = match c {
        b'0' ... b'9' => c - b'0',
        b'a' ... b'z' => c - b'a' + 10,
        b'A' ... b'Z' => c - b'A' + 10,
        _ => return None,
    };
    if val < radix {
        Some(val)
    } else {
        None
    }
}

trait FromAsciiHelper: {
    fn signed() -> bool;
}

/// A trait to abstract the idea of creating a new instance of a numeric type from a
/// ascii string with given radix.
///
/// It's a near clone of standard `FromStr` trait.
pub trait FromAsciiRadix: Sized {
    /// The associated error which can be returned from parsing.
    type Err;

    /// Parses a ascii string `s` to return a value of this type.
    ///
    /// If parsing succeeds, return the value inside `Ok`, otherwise
    /// when the string is ill-formatted return an error specific to the
    /// inside `Err`. The error type is specific to implementation of the trait.
    ///
    /// # Examples
    ///
    /// Basic usage with `i32`, a type that implements `FromAsciiRadix`:
    ///
    /// ```
    /// use from_ascii::FromAsciiRadix;
    ///
    /// let s = b"FA";
    /// let x = i32::from_ascii_radix(s, 16).unwrap();
    ///
    /// assert_eq!(250, x);
    /// ```
    fn from_ascii_radix(s: &[u8], radix: u8) -> Result<Self, Self::Err>;
}

macro_rules! implement {
    ($t:ty, $signed: expr) => {
        impl FromAsciiHelper for $t {
            #[inline]
            fn signed() -> bool { $signed }
        }

        impl FromAsciiRadix for $t {
            type Err = ParseIntError;

            #[inline]
            fn from_ascii_radix(src: &[u8], radix: u8) -> Result<Self, Self::Err> {
                if radix < 2 || radix > 36 {
                    return Err(ParseIntError { kind: IntErrorKind::InvalidRadix(radix) })
                }

                let (is_positive, digits) = match src.get(0) {
                    Some(&b'+') => (true, &src[1..]),
                    Some(&b'-') if <$t>::signed() => (false, &src[1..]),
                    Some(_) => (true, src),
                    None => return Err(ParseIntError { kind: IntErrorKind::Empty }),
                };

                if digits.is_empty() {
                    return Err(ParseIntError { kind: IntErrorKind::Empty });
                }

                let mut result: $t = 0;

                if is_positive {
                    for &c in digits {
                        let x = match dec_to_digit(c, radix) {
                            Some(x) => x as $t,
                            None => return Err(ParseIntError { kind: IntErrorKind::InvalidDigit(c) } ),
                        };
                        result = match result.checked_mul(radix as $t) {
                            Some(result) => result,
                            None => return Err(ParseIntError { kind: IntErrorKind::Overflow }),
                        };
                        result = match result.checked_add(x) {
                            Some(result) => result,
                            None => return Err(ParseIntError { kind: IntErrorKind::Overflow }),
                        };
                    }
                } else {
                    for &c in digits {
                        let x = match dec_to_digit(c, radix) {
                            Some(x) => x as $t,
                            None => return Err(ParseIntError { kind: IntErrorKind::InvalidDigit(c) }),
                        };
                        result = match result.checked_mul(radix as $t) {
                            Some(result) => result,
                            None => return Err(ParseIntError { kind: IntErrorKind::Underflow }),
                        };
                        result = match result.checked_sub(x) {
                            Some(result) => result,
                            None => return Err(ParseIntError { kind: IntErrorKind::Underflow }),
                        };
                    }
                }
                Ok(result)
            }
        }

        impl FromAscii for $t {
            type Err = ParseIntError;

            #[inline]
            fn from_ascii(src: &[u8]) -> Result<Self, Self::Err> {
                <$t>::from_ascii_radix(src, 10)
            }
        }
    }
}

implement!(i8, true);
implement!(i16, true);
implement!(i32, true);
implement!(i64, true);
implement!(isize, true);
implement!(u8, false);
implement!(u16, false);
implement!(u32, false);
implement!(u64, false);
implement!(usize, false);

#[cfg(test)]
mod tests {
    use super::super::base::FromAscii;
}<commit_msg>Add tests<commit_after>use std::error::{Error};
use std::fmt;

use base::{FromAscii};

/// An error returned when parsing a numeric value from a ascii string fails.
#[derive(Debug, Clone, PartialEq)]
pub struct ParseIntError {
    kind: IntErrorKind
}

#[derive(Debug, Clone, PartialEq)]
enum IntErrorKind {
    Empty,
    InvalidDigit(u8),
    Overflow,
    Underflow,
    InvalidRadix(u8),
}

impl IntErrorKind {
    fn description(&self) -> &str {
        match self {
            &IntErrorKind::Empty => "cannot parse integer from empty string",
            &IntErrorKind::InvalidDigit(_) => "invalid digit found in string",
            &IntErrorKind::Overflow => "number too large to fit in target type",
            &IntErrorKind::Underflow => "number too small to fit in target type",
            &IntErrorKind::InvalidRadix(_) => "radix should be in 2..36 range",
        }
    }
}

impl fmt::Display for ParseIntError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.kind.description().fmt(f)
    }
}

impl Error for ParseIntError {
    fn description(&self) -> &str {
        self.kind.description()
    }
}

#[inline]
pub fn dec_to_digit(c: u8, radix: u8) -> Option<u8> {
    let val = match c {
        b'0' ... b'9' => c - b'0',
        b'a' ... b'z' => c - b'a' + 10,
        b'A' ... b'Z' => c - b'A' + 10,
        _ => return None,
    };
    if val < radix {
        Some(val)
    } else {
        None
    }
}

trait FromAsciiHelper: {
    fn signed() -> bool;
}

/// A trait to abstract the idea of creating a new instance of a numeric type from a
/// ascii string with given radix.
///
/// It's a near clone of standard `FromStr` trait.
pub trait FromAsciiRadix: Sized {
    /// The associated error which can be returned from parsing.
    type Err;

    /// Parses a ascii string `s` to return a value of this type.
    ///
    /// If parsing succeeds, return the value inside `Ok`, otherwise
    /// when the string is ill-formatted return an error specific to the
    /// inside `Err`. The error type is specific to implementation of the trait.
    ///
    /// # Examples
    ///
    /// Basic usage with `i32`, a type that implements `FromAsciiRadix`:
    ///
    /// ```
    /// use from_ascii::FromAsciiRadix;
    ///
    /// let s = b"FA";
    /// let x = i32::from_ascii_radix(s, 16).unwrap();
    ///
    /// assert_eq!(250, x);
    /// ```
    fn from_ascii_radix(s: &[u8], radix: u8) -> Result<Self, Self::Err>;
}

macro_rules! implement {
    ($t:ty, $signed: expr) => {
        impl FromAsciiHelper for $t {
            #[inline]
            fn signed() -> bool { $signed }
        }

        impl FromAsciiRadix for $t {
            type Err = ParseIntError;

            #[inline]
            fn from_ascii_radix(src: &[u8], radix: u8) -> Result<Self, Self::Err> {
                if radix < 2 || radix > 36 {
                    return Err(ParseIntError { kind: IntErrorKind::InvalidRadix(radix) })
                }

                let (is_positive, digits) = match src.get(0) {
                    Some(&b'+') => (true, &src[1..]),
                    Some(&b'-') if <$t>::signed() => (false, &src[1..]),
                    Some(_) => (true, src),
                    None => return Err(ParseIntError { kind: IntErrorKind::Empty }),
                };

                if digits.is_empty() {
                    return Err(ParseIntError { kind: IntErrorKind::Empty });
                }

                let mut result: $t = 0;

                if is_positive {
                    for &c in digits {
                        let x = match dec_to_digit(c, radix) {
                            Some(x) => x as $t,
                            None => return Err(ParseIntError { kind: IntErrorKind::InvalidDigit(c) } ),
                        };
                        result = match result.checked_mul(radix as $t) {
                            Some(result) => result,
                            None => return Err(ParseIntError { kind: IntErrorKind::Overflow }),
                        };
                        result = match result.checked_add(x) {
                            Some(result) => result,
                            None => return Err(ParseIntError { kind: IntErrorKind::Overflow }),
                        };
                    }
                } else {
                    for &c in digits {
                        let x = match dec_to_digit(c, radix) {
                            Some(x) => x as $t,
                            None => return Err(ParseIntError { kind: IntErrorKind::InvalidDigit(c) }),
                        };
                        result = match result.checked_mul(radix as $t) {
                            Some(result) => result,
                            None => return Err(ParseIntError { kind: IntErrorKind::Underflow }),
                        };
                        result = match result.checked_sub(x) {
                            Some(result) => result,
                            None => return Err(ParseIntError { kind: IntErrorKind::Underflow }),
                        };
                    }
                }
                Ok(result)
            }
        }

        impl FromAscii for $t {
            type Err = ParseIntError;

            #[inline]
            fn from_ascii(src: &[u8]) -> Result<Self, Self::Err> {
                <$t>::from_ascii_radix(src, 10)
            }
        }
    }
}

implement!(i8, true);
implement!(i16, true);
implement!(i32, true);
implement!(i64, true);
implement!(isize, true);
implement!(u8, false);
implement!(u16, false);
implement!(u32, false);
implement!(u64, false);
implement!(usize, false);

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

    #[test]
    fn test_from_ascii() {
        assert_eq!(i8::from_ascii(b"10"), Ok(10));
        assert_eq!(u8::from_ascii(b"10"), Ok(10));
        assert_eq!(i64::from_ascii(b"10"), Ok(10));
        assert_eq!(u64::from_ascii(b"10"), Ok(10));

        assert_eq!(i8::from_ascii(b"-10"), Ok(-10));
        assert_eq!(u8::from_ascii(b"-10").is_err(), true);
        assert_eq!(i64::from_ascii(b"-10"), Ok(-10));
        assert_eq!(u64::from_ascii(b"-10").is_err(), true);

        assert_eq!(i8::from_ascii(b"1000").is_err(), true);
        assert_eq!(u8::from_ascii(b"1000").is_err(), true);
        assert_eq!(i64::from_ascii(b"1000"), Ok(1000));
        assert_eq!(u64::from_ascii(b"1000"), Ok(1000));

        assert_eq!(i8::from_ascii(b"-1000").is_err(), true);
        assert_eq!(u8::from_ascii(b"-1000").is_err(), true);
        assert_eq!(i64::from_ascii(b"-1000"), Ok(-1000));
        assert_eq!(u64::from_ascii(b"-1000").is_err(), true);
    }
}<|endoftext|>


<commit_before>use cocoa::base::{id, nil};
use cocoa::foundation::{NSInteger, NSUInteger};
use core_foundation::base::CFRange;
use objc::runtime::YES;
use std::ops::Range;
use sys::{MTLTexture, MTLTextureType, MTLTextureUsage};
use {FromRaw, FromRawError, PixelFormat, Region, Resource, Size};
#[cfg(target_os = "ios")]
use Buffer;

pub struct Texture(id);

impl Texture {
    pub fn with_pixel_format(format: PixelFormat) -> Result<Self, FromRawError> {
        let raw_tex = unsafe { MTLTexture::newTextureViewWithPixelFormat(nil, format.into()) };
        Self::from_raw(raw_tex)
    }

    pub fn new(format: PixelFormat, tex_type: TextureType, levels: Range<isize>, slices: usize)
               -> Result<Self, FromRawError> {
        let cf_levels = CFRange::init(levels.start as NSInteger,
                                      (levels.end - levels.start) as NSInteger);
        let raw_tex = unsafe {
            MTLTexture::newTextureViewWithPixelFormat_textureType_levels_slices(
                nil, format.into(), tex_type.into(), cf_levels,
                slices as NSUInteger)
        };
        Self::from_raw(raw_tex)
    }

    pub fn replace_region_at_slice(&mut self, region: Region, slice: usize, mipmap_level: usize,
                                   bytes: &AsRef<[u8]>, bytes_per_row: usize,
                                   bytes_per_image: usize) {
        unsafe {
            self.0.replaceRegion_mipmapLevel_slice_withBytes_bytesPerRow_bytesPerImage(
                region.into(), mipmap_level as NSUInteger, slice as NSUInteger,
                bytes.as_ref().as_ptr() as *const _, bytes_per_row as NSUInteger,
                bytes_per_image as NSUInteger);
        }
    }

    pub fn replace_region(&mut self, mipmap_level: usize, region: Region, bytes: &AsRef<[u8]>,
                          bytes_per_row: usize) {
        let bytes = bytes.as_ref();
        if bytes.len() % bytes_per_row != 0 {
            return;
        }
        unsafe {
            self.0.replaceRegion_mipmapLevel_withBytes_bytesPerRow(region.into(),
                                                                   mipmap_level as NSUInteger,
                                                                   bytes.as_ptr() as *const _,
                                                                   bytes_per_row as NSUInteger);
        }
    }

    // TODO(George): Investiage non-allocating APIs, and add predicates in rust code so that
    // panics can be generated
    pub fn get_bytes_at_slice(&self, bytes_storage: &mut Vec<u8>, bytes_per_row: usize,
                              bytes_per_image: usize, region: Region, mipmap_level: usize,
                              slice: usize) {
        bytes_storage.resize(self.width() * self.height() * self.depth(), 0u8);
        unsafe {
            self.0.getBytes_bytesPerRow_bytesPerImage_fromRegion_mipmapLevel_slice(
                bytes_storage.as_mut_ptr() as *mut _, bytes_per_row as NSUInteger,
                bytes_per_image as NSUInteger, region.into(), mipmap_level as NSUInteger,
                slice as NSUInteger);
        }
        bytes_storage.shrink_to_fit();
    }

    pub fn get_bytes(&self, bytes_storage: &mut Vec<u8>, bytes_per_row: usize, region: Region,
                     mipmap_level: usize) {
        bytes_storage.resize(self.width() * self.height() * self.depth(), 0u8);
        unsafe {
            self.0
                .getBytes_bytesPerRow_fromRegion_mipmapLevel(bytes_storage.as_mut_ptr() as *mut _,
                                                             bytes_per_row as NSUInteger,
                                                             region.into(),
                                                             mipmap_level as NSUInteger);
        }
        bytes_storage.shrink_to_fit();
    }

    pub fn texture_type(&self) -> TextureType {
        unsafe { self.0.textureType().into() }
    }

    pub fn pixel_format(&self) -> PixelFormat {
        unsafe { self.0.pixelFormat().into() }
    }

    pub fn width(&self) -> usize {
        unsafe { self.0.width() as usize }
    }

    pub fn height(&self) -> usize {
        unsafe { self.0.height() as usize }
    }

    pub fn depth(&self) -> usize {
        unsafe { self.0.depth() as usize }
    }

    pub fn dimensions(&self) -> Size {
        Size::new(self.width(), self.height(), self.depth())
    }

    pub fn mipmap_level_count(&self) -> usize {
        unsafe { self.0.mipmapLevelCount() as usize }
    }

    pub fn array_length(&self) -> usize {
        unsafe { self.0.arrayLength() as usize }
    }

    pub fn sample_count(&self) -> usize {
        unsafe { self.0.sampleCount() as usize }
    }

    pub fn is_frame_buffer_only(&self) -> bool {
        unsafe { self.0.frameBufferOnly() == YES }
    }

    pub fn root_resource(&self) -> Option<Resource> {
        unsafe { FromRaw::from_raw(self.0.rootResource()).ok() }
    }

    pub fn usage(&self) -> TextureUsage {
        unsafe { self.0.usage().into() }
    }

    pub fn parent_texture(&self) -> Option<Self> {
        unsafe { Self::from_raw(self.0.parentTexture()).ok() }
    }

    pub fn parent_relative_level(&self) -> usize {
        unsafe { self.0.parentRelativeLevel() as usize }
    }

    pub fn parent_relative_slice(&self) -> usize {
        unsafe { self.0.parentRelativeSlice() as usize }
    }
}

#[cfg(target_os = "macos")]
impl Texture {}

#[cfg(target_os = "ios")]
impl Texture {
    pub fn buffer(&self) -> Option<Buffer> {
        unsafe { FromRaw::from_raw(MTLTexture::buffer(self.0)).ok() }
    }

    pub fn buffer_offset(&self) -> usize {
        unsafe { self.0.bufferOffset() as usize }
    }

    pub fn buffer_bytes_per_row(&self) -> usize {
        unsafe { self.0.bufferBytesPerRow() as usize }
    }
}

impl_from_into_raw!(Texture, of protocol "MTLTexture");

convertible_enum! {
    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
    pub enum TextureType: MTLTextureType {
        Type1D => MTLTextureType1D,
        Type1DArray => MTLTextureType1DArray,
        Type2D => MTLTextureType2D,
        Type2DArray => MTLTextureType2DArray,
        Type2DMultisample => MTLTextureType2DMultisample,
        TypeCube => MTLTextureTypeCube,
        Type3D => MTLTextureType3D
    }
}

convertible_enum! {
    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
    pub enum TextureUsage: MTLTextureUsage {
        Unknown => MTLTextureUsageUnknown,
        ShaderRead => MTLTextureUsageShaderRead,
        ShaderWrite => MTLTextureUsageShaderWrite,
        RenderTarget => MTLTextureUsageRenderTarget,
        PixelFormatView => MTLTextureUsagePixelFormatView
    }
}
<commit_msg>Fix typo<commit_after>use cocoa::base::{id, nil};
use cocoa::foundation::{NSInteger, NSUInteger};
use core_foundation::base::CFRange;
use objc::runtime::YES;
use std::ops::Range;
use sys::{MTLTexture, MTLTextureType, MTLTextureUsage};
use {FromRaw, FromRawError, PixelFormat, Region, Resource, Size};
#[cfg(target_os = "ios")]
use Buffer;

pub struct Texture(id);

impl Texture {
    pub fn with_pixel_format(format: PixelFormat) -> Result<Self, FromRawError> {
        let raw_tex = unsafe { MTLTexture::newTextureViewWithPixelFormat(nil, format.into()) };
        Self::from_raw(raw_tex)
    }

    pub fn new(format: PixelFormat, tex_type: TextureType, levels: Range<isize>, slices: usize)
               -> Result<Self, FromRawError> {
        let cf_levels = CFRange::init(levels.start as NSInteger,
                                      (levels.end - levels.start) as NSInteger);
        let raw_tex = unsafe {
            MTLTexture::newTextureViewWithPixelFormat_textureType_levels_slices(
                nil, format.into(), tex_type.into(), cf_levels,
                slices as NSUInteger)
        };
        Self::from_raw(raw_tex)
    }

    pub fn replace_region_at_slice(&mut self, region: Region, slice: usize, mipmap_level: usize,
                                   bytes: &AsRef<[u8]>, bytes_per_row: usize,
                                   bytes_per_image: usize) {
        unsafe {
            self.0.replaceRegion_mipmapLevel_slice_withBytes_bytesPerRow_bytesPerImage(
                region.into(), mipmap_level as NSUInteger, slice as NSUInteger,
                bytes.as_ref().as_ptr() as *const _, bytes_per_row as NSUInteger,
                bytes_per_image as NSUInteger);
        }
    }

    pub fn replace_region(&mut self, mipmap_level: usize, region: Region, bytes: &AsRef<[u8]>,
                          bytes_per_row: usize) {
        let bytes = bytes.as_ref();
        if bytes.len() % bytes_per_row != 0 {
            return;
        }
        unsafe {
            self.0.replaceRegion_mipmapLevel_withBytes_bytesPerRow(region.into(),
                                                                   mipmap_level as NSUInteger,
                                                                   bytes.as_ptr() as *const _,
                                                                   bytes_per_row as NSUInteger);
        }
    }

    // TODO(George): Investigate non-allocating APIs, and add predicates in rust code so that
    // panics can be generated
    pub fn get_bytes_at_slice(&self, bytes_storage: &mut Vec<u8>, bytes_per_row: usize,
                              bytes_per_image: usize, region: Region, mipmap_level: usize,
                              slice: usize) {
        bytes_storage.resize(self.width() * self.height() * self.depth(), 0u8);
        unsafe {
            self.0.getBytes_bytesPerRow_bytesPerImage_fromRegion_mipmapLevel_slice(
                bytes_storage.as_mut_ptr() as *mut _, bytes_per_row as NSUInteger,
                bytes_per_image as NSUInteger, region.into(), mipmap_level as NSUInteger,
                slice as NSUInteger);
        }
        bytes_storage.shrink_to_fit();
    }

    pub fn get_bytes(&self, bytes_storage: &mut Vec<u8>, bytes_per_row: usize, region: Region,
                     mipmap_level: usize) {
        bytes_storage.resize(self.width() * self.height() * self.depth(), 0u8);
        unsafe {
            self.0
                .getBytes_bytesPerRow_fromRegion_mipmapLevel(bytes_storage.as_mut_ptr() as *mut _,
                                                             bytes_per_row as NSUInteger,
                                                             region.into(),
                                                             mipmap_level as NSUInteger);
        }
        bytes_storage.shrink_to_fit();
    }

    pub fn texture_type(&self) -> TextureType {
        unsafe { self.0.textureType().into() }
    }

    pub fn pixel_format(&self) -> PixelFormat {
        unsafe { self.0.pixelFormat().into() }
    }

    pub fn width(&self) -> usize {
        unsafe { self.0.width() as usize }
    }

    pub fn height(&self) -> usize {
        unsafe { self.0.height() as usize }
    }

    pub fn depth(&self) -> usize {
        unsafe { self.0.depth() as usize }
    }

    pub fn dimensions(&self) -> Size {
        Size::new(self.width(), self.height(), self.depth())
    }

    pub fn mipmap_level_count(&self) -> usize {
        unsafe { self.0.mipmapLevelCount() as usize }
    }

    pub fn array_length(&self) -> usize {
        unsafe { self.0.arrayLength() as usize }
    }

    pub fn sample_count(&self) -> usize {
        unsafe { self.0.sampleCount() as usize }
    }

    pub fn is_frame_buffer_only(&self) -> bool {
        unsafe { self.0.frameBufferOnly() == YES }
    }

    pub fn root_resource(&self) -> Option<Resource> {
        unsafe { FromRaw::from_raw(self.0.rootResource()).ok() }
    }

    pub fn usage(&self) -> TextureUsage {
        unsafe { self.0.usage().into() }
    }

    pub fn parent_texture(&self) -> Option<Self> {
        unsafe { Self::from_raw(self.0.parentTexture()).ok() }
    }

    pub fn parent_relative_level(&self) -> usize {
        unsafe { self.0.parentRelativeLevel() as usize }
    }

    pub fn parent_relative_slice(&self) -> usize {
        unsafe { self.0.parentRelativeSlice() as usize }
    }
}

#[cfg(target_os = "macos")]
impl Texture {}

#[cfg(target_os = "ios")]
impl Texture {
    pub fn buffer(&self) -> Option<Buffer> {
        unsafe { FromRaw::from_raw(MTLTexture::buffer(self.0)).ok() }
    }

    pub fn buffer_offset(&self) -> usize {
        unsafe { self.0.bufferOffset() as usize }
    }

    pub fn buffer_bytes_per_row(&self) -> usize {
        unsafe { self.0.bufferBytesPerRow() as usize }
    }
}

impl_from_into_raw!(Texture, of protocol "MTLTexture");

convertible_enum! {
    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
    pub enum TextureType: MTLTextureType {
        Type1D => MTLTextureType1D,
        Type1DArray => MTLTextureType1DArray,
        Type2D => MTLTextureType2D,
        Type2DArray => MTLTextureType2DArray,
        Type2DMultisample => MTLTextureType2DMultisample,
        TypeCube => MTLTextureTypeCube,
        Type3D => MTLTextureType3D
    }
}

convertible_enum! {
    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
    pub enum TextureUsage: MTLTextureUsage {
        Unknown => MTLTextureUsageUnknown,
        ShaderRead => MTLTextureUsageShaderRead,
        ShaderWrite => MTLTextureUsageShaderWrite,
        RenderTarget => MTLTextureUsageRenderTarget,
        PixelFormatView => MTLTextureUsagePixelFormatView
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::marker::PhantomData;
use serde::de::{self, Deserialize, Deserializer};

#[derive(Debug, Deserialize, Clone)]
pub struct Instance {
    #[serde(rename = "InstanceId")]
    pub id: String,
    #[serde(rename = "InstanceName")]
    pub name: String,
    #[serde(deserialize_with = "deserialize_single_key_map_to_vec")]
    #[serde(rename = "PublicIpAddress")]
    pub public_ip_address: Vec<String>,
}

impl Instance {
    pub fn ip(&self) -> &str {
        &self.public_ip_address[0]
    }
}

#[derive(Debug, Deserialize, Clone)]
pub struct Instances {
    #[serde(deserialize_with = "deserialize_single_key_map_to_vec")]
    #[serde(rename = "Instances")]
    pub instances: Vec<Instance>,
    #[serde(rename = "TotalCount")]
    pub total: usize,
    #[serde(rename = "PageNumber")]
    pub page: usize,
    #[serde(rename = "PageSize")]
    pub size: usize,
}

fn deserialize_single_key_map_to_vec<V, D>(d: D) -> Result<Vec<V>, D::Error>
    where D: Deserializer,
          V: Deserialize
{
    struct SingleKeyMapToVecVisitor<V: Deserialize>(PhantomData<V>);

    impl<V> de::Visitor for SingleKeyMapToVecVisitor<V>
        where V: Deserialize
    {
        type Value = Vec<V>;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a map")
        }

        #[inline]
        fn visit_unit<E>(self) -> Result<Vec<V>, E> {
            Ok(Vec::new())
        }

        #[inline]
        fn visit_map<T>(self, mut visitor: T) -> Result<Vec<V>, T::Error>
            where T: de::MapVisitor
        {
            let item: Option<(String, Vec<V>)> = visitor.visit()?;
            if let Some((_, value)) = item {
                return Ok(value);
            }
            Ok(Vec::new())
        }
    }
    d.deserialize_map(SingleKeyMapToVecVisitor(PhantomData))
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_deserialize_instances() {
        let json = r#"{
  "Instances": {
    "Instance": [
      {
        "CreationTime": "2015-07-27T07:08Z",
        "DeviceAvailable": true,
        "EipAddress": {},
        "ExpiredTime": "2011-09-08T16:00Z",
        "HostName": "iZ94t3s0jxkZ",
        "ImageId": "centos6u5_64_20G_aliaegis_20150130.vhd",
        "InnerIpAddress": {
          "IpAddress": [
            "10.170.106.80"
          ]
        },
        "InstanceChargeType": "PostPaid",
        "InstanceId": "i-94t3s0jxk",
        "InstanceName": "dd\u6027\u80fd\u6d4b\u8bd5",
        "InstanceNetworkType": "classic",
        "InstanceType": "ecs.s2.large",
        "InternetChargeType": "PayByTraffic",
        "InternetMaxBandwidthIn": -1,
        "InternetMaxBandwidthOut": 1,
        "IoOptimized": false,
        "OperationLocks": {
          "LockReason": []
        },
        "PublicIpAddress": {
          "IpAddress": [
            "120.25.13.106"
          ]
        },
        "RegionId": "cn-shenzhen",
        "SecurityGroupIds": {
          "SecurityGroupId": [
            "sg-94kd0cyg0"
          ]
        },
        "SerialNumber": "51d1353b-22bf-4567-a176-8b3e12e43135",
        "Status": "Running",
        "VpcAttributes": {
          "PrivateIpAddress": {
            "IpAddress": []
          }
        },
        "ZoneId": "cn-shenzhen-a"
      }
    ]
  },
  "PageNumber": 1,
  "PageSize": 10,
  "RequestId": "14A07460-EBE7-47CA-9757-12CC4761D47A",
  "TotalCount": 1
}"#;
        let instances = ::serde_json::from_str::<super::Instances>(json).unwrap();
        assert_eq!(instances.page, 1);
        assert_eq!(instances.size, 10);
        assert_eq!(instances.total, 1);
        assert_eq!(instances.instances.len(), 1);
        let instance = &instances.instances[0];
        assert_eq!(instance.id, "i-94t3s0jxk");
        assert_eq!(instance.ip(), "120.25.13.106");
    }
}
<commit_msg>deserialize_single_key_map generic over type `T` instead of `Vec<T>`<commit_after>use std::fmt;
use std::marker::PhantomData;
use serde::de::{self, Deserialize, Deserializer};

#[derive(Debug, Deserialize, Clone)]
pub struct Instance {
    #[serde(rename = "InstanceId")]
    pub id: String,
    #[serde(rename = "InstanceName")]
    pub name: String,
    #[serde(deserialize_with = "deserialize_single_key_map")]
    #[serde(rename = "PublicIpAddress")]
    pub public_ip_address: Vec<String>,
}

impl Instance {
    pub fn ip(&self) -> &str {
        &self.public_ip_address[0]
    }
}

#[derive(Debug, Deserialize, Clone)]
pub struct Instances {
    #[serde(deserialize_with = "deserialize_single_key_map")]
    #[serde(rename = "Instances")]
    pub instances: Vec<Instance>,
    #[serde(rename = "TotalCount")]
    pub total: usize,
    #[serde(rename = "PageNumber")]
    pub page: usize,
    #[serde(rename = "PageSize")]
    pub size: usize,
}

fn deserialize_single_key_map<V, D>(d: D) -> Result<V, D::Error>
    where D: Deserializer,
          V: Deserialize
{
    struct SingleKeyMapToVecVisitor<V: Deserialize>(PhantomData<V>);

    impl<V> de::Visitor for SingleKeyMapToVecVisitor<V>
        where V: Deserialize
    {
        type Value = V;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a map")
        }

        #[inline]
        fn visit_map<T>(self, mut visitor: T) -> Result<V, T::Error>
            where T: de::MapVisitor
        {
            let item: Option<(String, V)> = visitor.visit()?;
            if let Some((_, value)) = item {
                return Ok(value);
            }
            Err(de::Error::custom("No single key value in map"))
        }
    }
    d.deserialize_map(SingleKeyMapToVecVisitor(PhantomData))
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_deserialize_instances() {
        let json = r#"{
  "Instances": {
    "Instance": [
      {
        "CreationTime": "2015-07-27T07:08Z",
        "DeviceAvailable": true,
        "EipAddress": {},
        "ExpiredTime": "2011-09-08T16:00Z",
        "HostName": "iZ94t3s0jxkZ",
        "ImageId": "centos6u5_64_20G_aliaegis_20150130.vhd",
        "InnerIpAddress": {
          "IpAddress": [
            "10.170.106.80"
          ]
        },
        "InstanceChargeType": "PostPaid",
        "InstanceId": "i-94t3s0jxk",
        "InstanceName": "dd\u6027\u80fd\u6d4b\u8bd5",
        "InstanceNetworkType": "classic",
        "InstanceType": "ecs.s2.large",
        "InternetChargeType": "PayByTraffic",
        "InternetMaxBandwidthIn": -1,
        "InternetMaxBandwidthOut": 1,
        "IoOptimized": false,
        "OperationLocks": {
          "LockReason": []
        },
        "PublicIpAddress": {
          "IpAddress": [
            "120.25.13.106"
          ]
        },
        "RegionId": "cn-shenzhen",
        "SecurityGroupIds": {
          "SecurityGroupId": [
            "sg-94kd0cyg0"
          ]
        },
        "SerialNumber": "51d1353b-22bf-4567-a176-8b3e12e43135",
        "Status": "Running",
        "VpcAttributes": {
          "PrivateIpAddress": {
            "IpAddress": []
          }
        },
        "ZoneId": "cn-shenzhen-a"
      }
    ]
  },
  "PageNumber": 1,
  "PageSize": 10,
  "RequestId": "14A07460-EBE7-47CA-9757-12CC4761D47A",
  "TotalCount": 1
}"#;
        let instances = ::serde_json::from_str::<super::Instances>(json).unwrap();
        assert_eq!(instances.page, 1);
        assert_eq!(instances.size, 10);
        assert_eq!(instances.total, 1);
        assert_eq!(instances.instances.len(), 1);
        let instance = &instances.instances[0];
        assert_eq!(instance.id, "i-94t3s0jxk");
        assert_eq!(instance.ip(), "120.25.13.106");
    }
}
<|endoftext|>


<commit_before><commit_msg>Implemented BooleanQueryBuilder<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! record data enum variants

use error::*;
use rr::{Name, RData, RecordType};
use rr::rdata::DNSSECRecordType;
use serialize::txt::rdata_parsers::*;

pub trait RDataParser: Sized {
    fn parse<'i, I: Iterator<Item=&'i str>>(
        record_type: RecordType,
        tokens: I,
        origin: Option<&Name>,
    ) -> ParseResult<Self>;
}

impl RDataParser for RData {
    /// Parse the RData from a set of Tokens
    fn parse<'i, I: Iterator<Item=&'i str>>(
        record_type: RecordType,
        tokens: I,
        origin: Option<&Name>,
    ) -> ParseResult<Self> {
        let rdata = match record_type {
            RecordType::A => RData::A(a::parse(tokens)?),
            RecordType::AAAA => RData::AAAA(aaaa::parse(tokens)?),
            RecordType::ANY => panic!("parsing ANY doesn't make sense"), // valid panic, never should happen
            RecordType::AXFR => panic!("parsing AXFR doesn't make sense"), // valid panic, never should happen
            RecordType::CAA => caa::parse(tokens).map(RData::CAA)?,
            RecordType::CNAME => RData::CNAME(name::parse(tokens, origin)?),
            RecordType::IXFR => panic!("parsing IXFR doesn't make sense"), // valid panic, never should happen
            RecordType::MX => RData::MX(mx::parse(tokens, origin)?),
            RecordType::NULL => RData::NULL(null::parse(tokens)?),
            RecordType::NS => RData::NS(name::parse(tokens, origin)?),
            RecordType::OPT => panic!("parsing OPT doesn't make sense"), // valid panic, never should happen
            RecordType::PTR => RData::PTR(name::parse(tokens, origin)?),
            RecordType::SOA => RData::SOA(soa::parse(tokens, origin)?),
            RecordType::SRV => RData::SRV(srv::parse(tokens, origin)?),
            RecordType::TLSA => RData::TLSA(tlsa::parse(tokens)?),//RData::TLSA(tlsa::parse(tokens, origin)?),
            RecordType::TXT => RData::TXT(txt::parse(tokens)?),
            RecordType::DNSSEC(DNSSECRecordType::SIG) => panic!("parsing SIG doesn't make sense"), // valid panic, never should happen
            RecordType::DNSSEC(DNSSECRecordType::DNSKEY) => panic!("DNSKEY should be dynamically generated"), // valid panic, never should happen
            RecordType::DNSSEC(DNSSECRecordType::KEY) => panic!("KEY should be dynamically generated"), // valid panic, never should happen
            RecordType::DNSSEC(DNSSECRecordType::DS) => panic!("DS should be dynamically generated"), // valid panic, never should happen
            RecordType::DNSSEC(DNSSECRecordType::NSEC) => panic!("NSEC should be dynamically generated"), // valid panic, never should happen
            RecordType::DNSSEC(DNSSECRecordType::NSEC3) => panic!("NSEC3 should be dynamically generated"), // valid panic, never should happen
            RecordType::DNSSEC(DNSSECRecordType::NSEC3PARAM) => panic!("NSEC3PARAM should be dynamically generated"), // valid panic, never should happen
            RecordType::DNSSEC(DNSSECRecordType::RRSIG) => panic!("RRSIG should be dynamically generated"), // valid panic, never should happen
        };

        Ok(rdata)
    }
}
<commit_msg>clean up some unneeded comments<commit_after>/*
 * Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! record data enum variants

use error::*;
use rr::{Name, RData, RecordType};
use rr::rdata::DNSSECRecordType;
use serialize::txt::rdata_parsers::*;

pub trait RDataParser: Sized {
    fn parse<'i, I: Iterator<Item = &'i str>>(
        record_type: RecordType,
        tokens: I,
        origin: Option<&Name>,
    ) -> ParseResult<Self>;
}

impl RDataParser for RData {
    /// Parse the RData from a set of Tokens
    fn parse<'i, I: Iterator<Item = &'i str>>(
        record_type: RecordType,
        tokens: I,
        origin: Option<&Name>,
    ) -> ParseResult<Self> {
        let rdata = match record_type {
            RecordType::A => RData::A(a::parse(tokens)?),
            RecordType::AAAA => RData::AAAA(aaaa::parse(tokens)?),
            RecordType::ANY => panic!("parsing ANY doesn't make sense"), // valid panic, never should happen
            RecordType::AXFR => panic!("parsing AXFR doesn't make sense"), // valid panic, never should happen
            RecordType::CAA => caa::parse(tokens).map(RData::CAA)?,
            RecordType::CNAME => RData::CNAME(name::parse(tokens, origin)?),
            RecordType::IXFR => panic!("parsing IXFR doesn't make sense"), // valid panic, never should happen
            RecordType::MX => RData::MX(mx::parse(tokens, origin)?),
            RecordType::NULL => RData::NULL(null::parse(tokens)?),
            RecordType::NS => RData::NS(name::parse(tokens, origin)?),
            RecordType::OPT => panic!("parsing OPT doesn't make sense"), // valid panic, never should happen
            RecordType::PTR => RData::PTR(name::parse(tokens, origin)?),
            RecordType::SOA => RData::SOA(soa::parse(tokens, origin)?),
            RecordType::SRV => RData::SRV(srv::parse(tokens, origin)?),
            RecordType::TLSA => RData::TLSA(tlsa::parse(tokens)?),
            RecordType::TXT => RData::TXT(txt::parse(tokens)?),
            RecordType::DNSSEC(DNSSECRecordType::SIG) => panic!("parsing SIG doesn't make sense"), // valid panic, never should happen
            RecordType::DNSSEC(DNSSECRecordType::DNSKEY) => {
                panic!("DNSKEY should be dynamically generated")
            } // valid panic, never should happen
            RecordType::DNSSEC(DNSSECRecordType::KEY) => {
                panic!("KEY should be dynamically generated")
            } // valid panic, never should happen
            RecordType::DNSSEC(DNSSECRecordType::DS) => {
                panic!("DS should be dynamically generated")
            } // valid panic, never should happen
            RecordType::DNSSEC(DNSSECRecordType::NSEC) => {
                panic!("NSEC should be dynamically generated")
            } // valid panic, never should happen
            RecordType::DNSSEC(DNSSECRecordType::NSEC3) => {
                panic!("NSEC3 should be dynamically generated")
            } // valid panic, never should happen
            RecordType::DNSSEC(DNSSECRecordType::NSEC3PARAM) => {
                panic!("NSEC3PARAM should be dynamically generated")
            } // valid panic, never should happen
            RecordType::DNSSEC(DNSSECRecordType::RRSIG) => {
                panic!("RRSIG should be dynamically generated")
            } // valid panic, never should happen
        };

        Ok(rdata)
    }
}
<|endoftext|>