<commit_before>#![feature(rustc_private)]

#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]

#[macro_use]
extern crate log;

// From rustc.
#[macro_use]
extern crate rustc;
extern crate rustc_data_structures;
extern crate rustc_mir;
extern crate rustc_target;
extern crate syntax;

use std::collections::HashMap;
use std::borrow::Cow;

use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
use rustc::ty::layout::{TyLayout, LayoutOf, Size};
use rustc::hir::def_id::DefId;
use rustc::mir;

use syntax::ast::Mutability;
use syntax::attr;

pub use rustc::mir::interpret::*;
pub use rustc_mir::interpret::*;
pub use rustc_mir::interpret::{self, AllocMap}; // resolve ambiguity

mod fn_call;
mod operator;
mod intrinsic;
mod helpers;
mod tls;
mod locks;
mod range_map;
mod mono_hash_map;

use fn_call::EvalContextExt as MissingFnsEvalContextExt;
use operator::EvalContextExt as OperatorEvalContextExt;
use intrinsic::EvalContextExt as IntrinsicEvalContextExt;
use tls::{EvalContextExt as TlsEvalContextExt, TlsData};
use range_map::RangeMap;
use helpers::FalibleScalarExt;
use mono_hash_map::MonoHashMap;

pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    main_id: DefId,
    start_wrapper: Option<DefId>,
    validate: bool,
) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>> {
    let mut ecx = EvalContext::new(
        tcx.at(syntax::source_map::DUMMY_SP),
        ty::ParamEnv::reveal_all(),
        Evaluator::new(validate),
        Default::default(),
    );

    let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id);
    let main_mir = ecx.load_mir(main_instance.def)?;

    if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 {
        return err!(Unimplemented(
            "miri does not support main functions without `fn()` type signatures"
                .to_owned(),
        ));
    }

    if let Some(start_id) = start_wrapper {
        let main_ret_ty = ecx.tcx.fn_sig(main_id).output();
        let main_ret_ty = main_ret_ty.no_late_bound_regions().unwrap();
        let start_instance = ty::Instance::resolve(
            ecx.tcx.tcx,
            ty::ParamEnv::reveal_all(),
            start_id,
            ecx.tcx.mk_substs(
                ::std::iter::once(ty::subst::Kind::from(main_ret_ty)))
            ).unwrap();
        let start_mir = ecx.load_mir(start_instance.def)?;

        if start_mir.arg_count != 3 {
            return err!(AbiViolation(format!(
                "'start' lang item should have three arguments, but has {}",
                start_mir.arg_count
            )));
        }

        // Return value (in static memory so that it does not count as leak)
        let ret = ecx.layout_of(start_mir.return_ty())?;
        let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into())?;

        // Push our stack frame
        ecx.push_stack_frame(
            start_instance,
            start_mir.span,
            start_mir,
            Some(ret_ptr.into()),
            StackPopCleanup::None { cleanup: true },
        )?;

        let mut args = ecx.frame().mir.args_iter();

        // First argument: pointer to main()
        let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance);
        let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
        ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?;

        // Second argument (argc): 1
        let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
        ecx.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;

        // FIXME: extract main source file path
        // Third argument (argv): &[b"foo"]
        let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
        let foo = ecx.memory.allocate_static_bytes(b"foo\0");
        let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8);
        let foo_layout = ecx.layout_of(foo_ty)?;
        let foo_place = ecx.allocate(foo_layout, MemoryKind::Stack)?; // will be interned in just a second
        ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?;
        ecx.memory.intern_static(foo_place.to_ptr()?.alloc_id, Mutability::Immutable)?;
        ecx.write_scalar(foo_place.ptr, dest)?;

        assert!(args.next().is_none(), "start lang item has more arguments than expected");
    } else {
        let ret_place = MPlaceTy::dangling(ecx.layout_of(tcx.mk_unit())?, &ecx).into();
        ecx.push_stack_frame(
            main_instance,
            main_mir.span,
            main_mir,
            Some(ret_place),
            StackPopCleanup::None { cleanup: true },
        )?;

        // No arguments
        let mut args = ecx.frame().mir.args_iter();
        assert!(args.next().is_none(), "main function must not have arguments");
    }

    Ok(ecx)
}

pub fn eval_main<'a, 'tcx: 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    main_id: DefId,
    start_wrapper: Option<DefId>,
    validate: bool,
) {
    let mut ecx = create_ecx(tcx, main_id, start_wrapper, validate).expect("Couldn't create ecx");

    let res: EvalResult = (|| {
        ecx.run()?;
        ecx.run_tls_dtors()
    })();

    match res {
        Ok(()) => {
            let leaks = ecx.memory().leak_report();
            // Disable the leak test on some platforms where we likely do not
            // correctly implement TLS destructors.
            let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase();
            let ignore_leaks = target_os == "windows" || target_os == "macos";
            if !ignore_leaks && leaks != 0 {
                tcx.sess.err("the evaluated program leaked memory");
            }
        }
        Err(e) => {
            if let Some(frame) = ecx.stack().last() {
                let block = &frame.mir.basic_blocks()[frame.block];
                let span = if frame.stmt < block.statements.len() {
                    block.statements[frame.stmt].source_info.span
                } else {
                    block.terminator().source_info.span
                };

                let e = e.to_string();
                let msg = format!("constant evaluation error: {}", e);
                let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str());
                let (frames, span) = ecx.generate_stacktrace(None);
                err.span_label(span, e);
                for FrameInfo { span, location, .. } in frames {
                    err.span_note(span, &format!("inside call to `{}`", location));
                }
                err.emit();
            } else {
                ecx.tcx.sess.err(&e.to_string());
            }

            /* Nice try, but with MIRI_BACKTRACE this shows 100s of backtraces.
            for (i, frame) in ecx.stack().iter().enumerate() {
                trace!("-------------------");
                trace!("Frame {}", i);
                trace!("    return: {:#?}", frame.return_place);
                for (i, local) in frame.locals.iter().enumerate() {
                    if let Ok(local) = local.access() {
                        trace!("    local {}: {:?}", i, local);
                    }
                }
            }*/
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum MiriMemoryKind {
    /// `__rust_alloc` memory
    Rust,
    /// `malloc` memory
    C,
    /// Part of env var emulation
    Env,
    /// mutable statics
    MutStatic,
}

impl Into<MemoryKind<MiriMemoryKind>> for MiriMemoryKind {
    fn into(self) -> MemoryKind<MiriMemoryKind> {
        MemoryKind::Machine(self)
    }
}

#[derive(Clone, PartialEq, Eq)]
pub struct Evaluator<'tcx> {
    /// Environment variables set by `setenv`
    /// Miri does not expose env vars from the host to the emulated program
    pub(crate) env_vars: HashMap<Vec<u8>, Pointer>,

    /// TLS state
    pub(crate) tls: TlsData<'tcx>,

    /// Whether to enforce the validity invariant
    pub(crate) validate: bool,
}

impl<'tcx> Evaluator<'tcx> {
    fn new(validate: bool) -> Self {
        Evaluator {
            env_vars: HashMap::default(),
            tls: TlsData::default(),
            validate,
        }
    }
}

impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
    type MemoryData = ();
    type MemoryKinds = MiriMemoryKind;
    type PointerTag = (); // still WIP

    type MemoryMap = MonoHashMap<AllocId, (MemoryKind<MiriMemoryKind>, Allocation<()>)>;

    const STATIC_KIND: Option<MiriMemoryKind> = Some(MiriMemoryKind::MutStatic);

    fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool {
        if !ecx.machine.validate {
            return false;
        }

        // Some functions are whitelisted until we figure out how to fix them.
        // We walk up the stack a few frames to also cover their callees.
        const WHITELIST: &[&str] = &[
            // Uses mem::uninitialized
            "std::ptr::read",
        ];
        for frame in ecx.stack().iter()
            .rev().take(3)
        {
            let name = frame.instance.to_string();
            if WHITELIST.iter().any(|white| name.starts_with(white)) {
                return false;
            }
        }
        true
    }

    /// Returns Ok() when the function was handled, fail otherwise
    fn find_fn(
        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx>],
        dest: Option<PlaceTy<'tcx>>,
        ret: Option<mir::BasicBlock>,
    ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> {
        ecx.find_fn(instance, args, dest, ret)
    }

    fn call_intrinsic(
        ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx>],
        dest: PlaceTy<'tcx>,
    ) -> EvalResult<'tcx> {
        ecx.call_intrinsic(instance, args, dest)
    }

    fn ptr_op(
        ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>,
        bin_op: mir::BinOp,
        left: Scalar,
        left_layout: TyLayout<'tcx>,
        right: Scalar,
        right_layout: TyLayout<'tcx>,
    ) -> EvalResult<'tcx, (Scalar, bool)> {
        ecx.ptr_op(bin_op, left, left_layout, right, right_layout)
    }

    fn box_alloc(
        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        dest: PlaceTy<'tcx>,
    ) -> EvalResult<'tcx> {
        trace!("box_alloc for {:?}", dest.layout.ty);
        // Call the `exchange_malloc` lang item
        let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap();
        let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc);
        let malloc_mir = ecx.load_mir(malloc.def)?;
        ecx.push_stack_frame(
            malloc,
            malloc_mir.span,
            malloc_mir,
            Some(dest),
            // Don't do anything when we are done.  The statement() function will increment
            // the old stack frame's stmt counter to the next statement, which means that when
            // exchange_malloc returns, we go on evaluating exactly where we want to be.
            StackPopCleanup::None { cleanup: true },
        )?;

        let mut args = ecx.frame().mir.args_iter();
        let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?;

        // First argument: size
        // (0 is allowed here, this is expected to be handled by the lang item)
        let arg = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
        let size = layout.size.bytes();
        ecx.write_scalar(Scalar::from_uint(size, arg.layout.size), arg)?;

        // Second argument: align
        let arg = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
        let align = layout.align.abi();
        ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?;

        // No more arguments
        assert!(args.next().is_none(), "exchange_malloc lang item has more arguments than expected");
        Ok(())
    }

    fn find_foreign_static(
        tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
        def_id: DefId,
    ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> {
        let attrs = tcx.get_attrs(def_id);
        let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") {
            Some(name) => name.as_str(),
            None => tcx.item_name(def_id).as_str(),
        };

        let alloc = match &link_name[..] {
            "__cxa_thread_atexit_impl" => {
                // This should be all-zero, pointer-sized
                let data = vec![0; tcx.data_layout.pointer_size.bytes() as usize];
                Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align)
            }
            _ => return err!(Unimplemented(
                    format!("can't access foreign static: {}", link_name),
                )),
        };
        Ok(Cow::Owned(alloc))
    }

    fn validation_op(
        _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _op: ::rustc::mir::ValidationOp,
        _operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>,
    ) -> EvalResult<'tcx> {
        // FIXME: prevent this from ICEing
        //ecx.validation_op(op, operand)
        Ok(())
    }

    fn before_terminator(_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>
    {
        // We are not interested in detecting loops
        Ok(())
    }

    fn static_with_default_tag(
        alloc: &'_ Allocation
    ) -> Cow<'_, Allocation<Self::PointerTag>> {
        let alloc = alloc.clone();
        Cow::Owned(alloc)
    }
}
<commit_msg>whitelist Windows Mutex<commit_after>#![feature(rustc_private)]

#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]

#[macro_use]
extern crate log;

// From rustc.
#[macro_use]
extern crate rustc;
extern crate rustc_data_structures;
extern crate rustc_mir;
extern crate rustc_target;
extern crate syntax;

use std::collections::HashMap;
use std::borrow::Cow;

use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
use rustc::ty::layout::{TyLayout, LayoutOf, Size};
use rustc::hir::def_id::DefId;
use rustc::mir;

use syntax::ast::Mutability;
use syntax::attr;

pub use rustc::mir::interpret::*;
pub use rustc_mir::interpret::*;
pub use rustc_mir::interpret::{self, AllocMap}; // resolve ambiguity

mod fn_call;
mod operator;
mod intrinsic;
mod helpers;
mod tls;
mod locks;
mod range_map;
mod mono_hash_map;

use fn_call::EvalContextExt as MissingFnsEvalContextExt;
use operator::EvalContextExt as OperatorEvalContextExt;
use intrinsic::EvalContextExt as IntrinsicEvalContextExt;
use tls::{EvalContextExt as TlsEvalContextExt, TlsData};
use range_map::RangeMap;
use helpers::FalibleScalarExt;
use mono_hash_map::MonoHashMap;

pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    main_id: DefId,
    start_wrapper: Option<DefId>,
    validate: bool,
) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>> {
    let mut ecx = EvalContext::new(
        tcx.at(syntax::source_map::DUMMY_SP),
        ty::ParamEnv::reveal_all(),
        Evaluator::new(validate),
        Default::default(),
    );

    let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id);
    let main_mir = ecx.load_mir(main_instance.def)?;

    if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 {
        return err!(Unimplemented(
            "miri does not support main functions without `fn()` type signatures"
                .to_owned(),
        ));
    }

    if let Some(start_id) = start_wrapper {
        let main_ret_ty = ecx.tcx.fn_sig(main_id).output();
        let main_ret_ty = main_ret_ty.no_late_bound_regions().unwrap();
        let start_instance = ty::Instance::resolve(
            ecx.tcx.tcx,
            ty::ParamEnv::reveal_all(),
            start_id,
            ecx.tcx.mk_substs(
                ::std::iter::once(ty::subst::Kind::from(main_ret_ty)))
            ).unwrap();
        let start_mir = ecx.load_mir(start_instance.def)?;

        if start_mir.arg_count != 3 {
            return err!(AbiViolation(format!(
                "'start' lang item should have three arguments, but has {}",
                start_mir.arg_count
            )));
        }

        // Return value (in static memory so that it does not count as leak)
        let ret = ecx.layout_of(start_mir.return_ty())?;
        let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into())?;

        // Push our stack frame
        ecx.push_stack_frame(
            start_instance,
            start_mir.span,
            start_mir,
            Some(ret_ptr.into()),
            StackPopCleanup::None { cleanup: true },
        )?;

        let mut args = ecx.frame().mir.args_iter();

        // First argument: pointer to main()
        let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance);
        let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
        ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?;

        // Second argument (argc): 1
        let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
        ecx.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;

        // FIXME: extract main source file path
        // Third argument (argv): &[b"foo"]
        let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
        let foo = ecx.memory.allocate_static_bytes(b"foo\0");
        let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8);
        let foo_layout = ecx.layout_of(foo_ty)?;
        let foo_place = ecx.allocate(foo_layout, MemoryKind::Stack)?; // will be interned in just a second
        ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?;
        ecx.memory.intern_static(foo_place.to_ptr()?.alloc_id, Mutability::Immutable)?;
        ecx.write_scalar(foo_place.ptr, dest)?;

        assert!(args.next().is_none(), "start lang item has more arguments than expected");
    } else {
        let ret_place = MPlaceTy::dangling(ecx.layout_of(tcx.mk_unit())?, &ecx).into();
        ecx.push_stack_frame(
            main_instance,
            main_mir.span,
            main_mir,
            Some(ret_place),
            StackPopCleanup::None { cleanup: true },
        )?;

        // No arguments
        let mut args = ecx.frame().mir.args_iter();
        assert!(args.next().is_none(), "main function must not have arguments");
    }

    Ok(ecx)
}

pub fn eval_main<'a, 'tcx: 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    main_id: DefId,
    start_wrapper: Option<DefId>,
    validate: bool,
) {
    let mut ecx = create_ecx(tcx, main_id, start_wrapper, validate).expect("Couldn't create ecx");

    let res: EvalResult = (|| {
        ecx.run()?;
        ecx.run_tls_dtors()
    })();

    match res {
        Ok(()) => {
            let leaks = ecx.memory().leak_report();
            // Disable the leak test on some platforms where we likely do not
            // correctly implement TLS destructors.
            let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase();
            let ignore_leaks = target_os == "windows" || target_os == "macos";
            if !ignore_leaks && leaks != 0 {
                tcx.sess.err("the evaluated program leaked memory");
            }
        }
        Err(e) => {
            if let Some(frame) = ecx.stack().last() {
                let block = &frame.mir.basic_blocks()[frame.block];
                let span = if frame.stmt < block.statements.len() {
                    block.statements[frame.stmt].source_info.span
                } else {
                    block.terminator().source_info.span
                };

                let e = e.to_string();
                let msg = format!("constant evaluation error: {}", e);
                let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str());
                let (frames, span) = ecx.generate_stacktrace(None);
                err.span_label(span, e);
                for FrameInfo { span, location, .. } in frames {
                    err.span_note(span, &format!("inside call to `{}`", location));
                }
                err.emit();
            } else {
                ecx.tcx.sess.err(&e.to_string());
            }

            /* Nice try, but with MIRI_BACKTRACE this shows 100s of backtraces.
            for (i, frame) in ecx.stack().iter().enumerate() {
                trace!("-------------------");
                trace!("Frame {}", i);
                trace!("    return: {:#?}", frame.return_place);
                for (i, local) in frame.locals.iter().enumerate() {
                    if let Ok(local) = local.access() {
                        trace!("    local {}: {:?}", i, local);
                    }
                }
            }*/
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum MiriMemoryKind {
    /// `__rust_alloc` memory
    Rust,
    /// `malloc` memory
    C,
    /// Part of env var emulation
    Env,
    /// mutable statics
    MutStatic,
}

impl Into<MemoryKind<MiriMemoryKind>> for MiriMemoryKind {
    fn into(self) -> MemoryKind<MiriMemoryKind> {
        MemoryKind::Machine(self)
    }
}

#[derive(Clone, PartialEq, Eq)]
pub struct Evaluator<'tcx> {
    /// Environment variables set by `setenv`
    /// Miri does not expose env vars from the host to the emulated program
    pub(crate) env_vars: HashMap<Vec<u8>, Pointer>,

    /// TLS state
    pub(crate) tls: TlsData<'tcx>,

    /// Whether to enforce the validity invariant
    pub(crate) validate: bool,
}

impl<'tcx> Evaluator<'tcx> {
    fn new(validate: bool) -> Self {
        Evaluator {
            env_vars: HashMap::default(),
            tls: TlsData::default(),
            validate,
        }
    }
}

impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
    type MemoryData = ();
    type MemoryKinds = MiriMemoryKind;
    type PointerTag = (); // still WIP

    type MemoryMap = MonoHashMap<AllocId, (MemoryKind<MiriMemoryKind>, Allocation<()>)>;

    const STATIC_KIND: Option<MiriMemoryKind> = Some(MiriMemoryKind::MutStatic);

    fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool {
        if !ecx.machine.validate {
            return false;
        }

        // Some functions are whitelisted until we figure out how to fix them.
        // We walk up the stack a few frames to also cover their callees.
        const WHITELIST: &[&str] = &[
            // Uses mem::uninitialized
            "std::ptr::read",
            "std::sys::windows::mutex::Mutex::",
        ];
        for frame in ecx.stack().iter()
            .rev().take(3)
        {
            let name = frame.instance.to_string();
            if WHITELIST.iter().any(|white| name.starts_with(white)) {
                return false;
            }
        }
        true
    }

    /// Returns Ok() when the function was handled, fail otherwise
    fn find_fn(
        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx>],
        dest: Option<PlaceTy<'tcx>>,
        ret: Option<mir::BasicBlock>,
    ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> {
        ecx.find_fn(instance, args, dest, ret)
    }

    fn call_intrinsic(
        ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx>],
        dest: PlaceTy<'tcx>,
    ) -> EvalResult<'tcx> {
        ecx.call_intrinsic(instance, args, dest)
    }

    fn ptr_op(
        ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>,
        bin_op: mir::BinOp,
        left: Scalar,
        left_layout: TyLayout<'tcx>,
        right: Scalar,
        right_layout: TyLayout<'tcx>,
    ) -> EvalResult<'tcx, (Scalar, bool)> {
        ecx.ptr_op(bin_op, left, left_layout, right, right_layout)
    }

    fn box_alloc(
        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        dest: PlaceTy<'tcx>,
    ) -> EvalResult<'tcx> {
        trace!("box_alloc for {:?}", dest.layout.ty);
        // Call the `exchange_malloc` lang item
        let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap();
        let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc);
        let malloc_mir = ecx.load_mir(malloc.def)?;
        ecx.push_stack_frame(
            malloc,
            malloc_mir.span,
            malloc_mir,
            Some(dest),
            // Don't do anything when we are done.  The statement() function will increment
            // the old stack frame's stmt counter to the next statement, which means that when
            // exchange_malloc returns, we go on evaluating exactly where we want to be.
            StackPopCleanup::None { cleanup: true },
        )?;

        let mut args = ecx.frame().mir.args_iter();
        let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?;

        // First argument: size
        // (0 is allowed here, this is expected to be handled by the lang item)
        let arg = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
        let size = layout.size.bytes();
        ecx.write_scalar(Scalar::from_uint(size, arg.layout.size), arg)?;

        // Second argument: align
        let arg = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
        let align = layout.align.abi();
        ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?;

        // No more arguments
        assert!(args.next().is_none(), "exchange_malloc lang item has more arguments than expected");
        Ok(())
    }

    fn find_foreign_static(
        tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
        def_id: DefId,
    ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> {
        let attrs = tcx.get_attrs(def_id);
        let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") {
            Some(name) => name.as_str(),
            None => tcx.item_name(def_id).as_str(),
        };

        let alloc = match &link_name[..] {
            "__cxa_thread_atexit_impl" => {
                // This should be all-zero, pointer-sized
                let data = vec![0; tcx.data_layout.pointer_size.bytes() as usize];
                Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align)
            }
            _ => return err!(Unimplemented(
                    format!("can't access foreign static: {}", link_name),
                )),
        };
        Ok(Cow::Owned(alloc))
    }

    fn validation_op(
        _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _op: ::rustc::mir::ValidationOp,
        _operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>,
    ) -> EvalResult<'tcx> {
        // FIXME: prevent this from ICEing
        //ecx.validation_op(op, operand)
        Ok(())
    }

    fn before_terminator(_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>
    {
        // We are not interested in detecting loops
        Ok(())
    }

    fn static_with_default_tag(
        alloc: &'_ Allocation
    ) -> Cow<'_, Allocation<Self::PointerTag>> {
        let alloc = alloc.clone();
        Cow::Owned(alloc)
    }
}
<|endoftext|>


<commit_before>#![feature(io, core)]
#![cfg_attr(test, feature(collections))]
#![cfg_attr(test, deny(warnings))]

extern crate time;
extern crate conduit;
extern crate "conduit-middleware" as middleware;

use conduit::{Request, Method};
use middleware::Middleware;
use std::borrow::Cow;
use std::error::Error;
use std::old_io::util::NullReader;
use std::string::CowString;
use time::{Tm, strptime, ParseError};

type Response = Result<conduit::Response, Box<Error+Send>>;

#[allow(missing_copy_implementations)]
pub struct ConditionalGet;

impl Middleware for ConditionalGet {
    fn after(&self, req: &mut Request, res: Response) -> Response {
        let mut res = try!(res);

        match req.method() {
            Method::Get | Method::Head => {
                if is_ok(&res) && is_fresh(req, &res) {
                    res.status = (304, "Not Modified");
                    res.headers.remove("Content-Type");
                    res.headers.remove("Content-Length");
                    res.body = Box::new(NullReader);
                }
            },
            _ => ()
        }

        Ok(res)
    }
}

fn is_ok(response: &conduit::Response) -> bool {
    match *response {
        conduit::Response { status: (200, _), .. } => true,
        _ => false
    }
}

fn is_fresh(req: &Request, res: &conduit::Response) -> bool {
    let modified_since = req.headers().find("If-Modified-Since").map(header_val);
    let none_match     = req.headers().find("If-None-Match").map(header_val);

    if modified_since.as_ref().or_else(|| none_match.as_ref()).is_none() {
        return false;
    }

    let mut success = true;

    modified_since.and_then(|modified_since| {
        parse_http_date(modified_since).map_err(|_| { success = false; }).ok()
    }).map(|parsed| {
        success = success && is_modified_since(parsed, res);
    });

    none_match.map(|none_match| {
        success = success && etag_matches(none_match, res);
    });

    success
}

fn etag_matches<S: Str>(none_match: S, res: &conduit::Response) -> bool {
    res.headers.get("ETag").map(|etag| {
        res_header_val(etag).as_slice() == none_match.as_slice()
    }).unwrap_or(false)
}

fn is_modified_since(modified_since: Tm, res: &conduit::Response) -> bool {
    res.headers.get("Last-Modified").and_then(|last_modified| {
        parse_http_date(res_header_val(last_modified).as_slice()).ok()
    }).map(|last_modified| {
        modified_since.to_timespec() >= last_modified.to_timespec()
    }).unwrap_or(false)
}

fn header_val<'a>(header: Vec<&'a str>) -> CowString<'a> {
    if header.len() == 1 {
        Cow::Borrowed(header[0])
    } else {
        Cow::Owned(header.concat())
    }
}

fn res_header_val<'a>(header: &'a Vec<String>) -> CowString<'a> {
    if header.len() == 1 {
        Cow::Borrowed(header[0].as_slice())
    } else {
        Cow::Owned(header.concat())
    }
}

fn parse_http_date<S: Str>(string: S) -> Result<Tm, ()> {
    let string = string.as_slice();

    parse_rfc1123(string)
        .or_else(|_| parse_rfc850(string))
        .or_else(|_| parse_asctime(string))
        .map_err(|_| ())
}

fn parse_rfc1123(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d %b %Y %T GMT")
}

fn parse_rfc850(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d-%m-%y %T GMT")
}

fn parse_asctime(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a %m%t%d %T %Y")
}

#[cfg(test)]
mod tests {
    extern crate "conduit-test" as test;

    use std::collections::HashMap;
    use std::error::Error;
    use std::old_io::MemReader;
    use time;
    use time::Tm;
    use conduit;
    use conduit::{Request, Response, Handler, Method};
    use middleware::MiddlewareBuilder;

    use super::ConditionalGet;

    macro_rules! returning {
        ($code:expr, $($header:expr => $value:expr),+) => ({
            let mut headers = HashMap::new();
            $(headers.insert($header.to_string(), vec!($value.to_string()));)+
            let handler = SimpleHandler::new(headers, $code, "hello");
            let mut stack = MiddlewareBuilder::new(handler);
            stack.add(ConditionalGet);
            stack
        });
        ($($header:expr => $value:expr),+) => ({
            returning!((200, "OK"), $($header => $value),+)
        })
    }

    macro_rules! request {
        ($($header:expr => $value:expr),+) => ({
            let mut req = test::MockRequest::new(Method::Get, "/");
            $(req.header($header, $value.to_string().as_slice());)+
            req
        })
    }

    #[test]
    fn test_sends_304() {
        let handler = returning!("Last-Modified" => httpdate(time::now()));
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_if_older_than_now() {
        let handler = returning!("Last-Modified" => before_now());
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_with_etag() {
        let handler = returning!("ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_time_but_not_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "4321"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_etag_but_not_time() {
        let handler = returning!("Last-Modified" => now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_etag() {
        let handler = returning!("ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-None-Match" => "4321"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_time() {
        let handler = returning!("Last-Modified" => now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now()
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_with_fresh_time_and_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_does_not_affect_non_200() {
        let code = (302, "Found");
        let handler = returning!(code, "Last-Modified" => before_now(), "ETag" => "1234");
        expect(code, handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_does_not_affect_malformed_timestamp() {
        let bad_stamp = time::now().strftime("%Y-%m-%d %H:%M:%S %z").unwrap().to_string();
        let handler = returning!("Last-Modified" => before_now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => bad_stamp
        ) as &mut conduit::Request));
    }

    fn expect_304(response: Result<Response, Box<Error+Send>>) {
        let mut response = response.ok().expect("No response");
        let body = response.body.read_to_string().ok().expect("No body");

        assert_eq!(response.status, (304, "Not Modified"));
        assert_eq!(body.as_slice(), "");
    }

    fn expect_200(response: Result<Response, Box<Error+Send>>) {
        expect((200, "OK"), response);
    }

    fn expect(status: (u32, &'static str), response: Result<Response, Box<Error+Send>>) {
        let mut response = response.ok().expect("No response");
        let body = response.body.read_to_string().ok().expect("No body");

        assert_eq!(response.status, status);
        assert_eq!(body.as_slice(), "hello");
    }

    struct SimpleHandler {
        map: HashMap<String, Vec<String>>,
        status: Status,
        body: &'static str
    }

    type Status = (u32, &'static str);

    impl SimpleHandler {
        fn new(map: HashMap<String, Vec<String>>, status: Status, body: &'static str) -> SimpleHandler {
            SimpleHandler { map: map, status: status, body: body }
        }
    }

    impl Handler for SimpleHandler {
        fn call(&self, _: &mut Request) -> Result<Response, Box<Error+Send>> {
            Ok(Response {
                status: self.status,
                headers: self.map.clone(),
                body: Box::new(MemReader::new(self.body.to_string().into_bytes())),
            })
        }
    }

    fn before_now() -> String {
        let mut now = time::now();
        now.tm_year -= 1;
        httpdate(now)
    }

    fn now() -> String {
        httpdate(time::now())
    }

    fn httpdate(time: Tm) -> String {
        time.strftime("%a, %d-%m-%y %T GMT").unwrap().to_string()
    }
}
<commit_msg>Update to rust master<commit_after>#![feature(io, core)]
#![cfg_attr(test, deny(warnings))]

extern crate time;
extern crate conduit;
extern crate "conduit-middleware" as middleware;

use conduit::{Request, Method};
use middleware::Middleware;
use std::borrow::Cow;
use std::error::Error;
use std::old_io::util::NullReader;
use std::string::CowString;
use time::{Tm, strptime, ParseError};

type Response = Result<conduit::Response, Box<Error+Send>>;

#[allow(missing_copy_implementations)]
pub struct ConditionalGet;

impl Middleware for ConditionalGet {
    fn after(&self, req: &mut Request, res: Response) -> Response {
        let mut res = try!(res);

        match req.method() {
            Method::Get | Method::Head => {
                if is_ok(&res) && is_fresh(req, &res) {
                    res.status = (304, "Not Modified");
                    res.headers.remove("Content-Type");
                    res.headers.remove("Content-Length");
                    res.body = Box::new(NullReader);
                }
            },
            _ => ()
        }

        Ok(res)
    }
}

fn is_ok(response: &conduit::Response) -> bool {
    match *response {
        conduit::Response { status: (200, _), .. } => true,
        _ => false
    }
}

fn is_fresh(req: &Request, res: &conduit::Response) -> bool {
    let modified_since = req.headers().find("If-Modified-Since").map(header_val);
    let none_match     = req.headers().find("If-None-Match").map(header_val);

    if modified_since.as_ref().or_else(|| none_match.as_ref()).is_none() {
        return false;
    }

    let mut success = true;

    modified_since.and_then(|modified_since| {
        parse_http_date(modified_since).map_err(|_| { success = false; }).ok()
    }).map(|parsed| {
        success = success && is_modified_since(parsed, res);
    });

    none_match.map(|none_match| {
        success = success && etag_matches(none_match, res);
    });

    success
}

fn etag_matches<S: Str>(none_match: S, res: &conduit::Response) -> bool {
    res.headers.get("ETag").map(|etag| {
        res_header_val(etag).as_slice() == none_match.as_slice()
    }).unwrap_or(false)
}

fn is_modified_since(modified_since: Tm, res: &conduit::Response) -> bool {
    res.headers.get("Last-Modified").and_then(|last_modified| {
        parse_http_date(res_header_val(last_modified).as_slice()).ok()
    }).map(|last_modified| {
        modified_since.to_timespec() >= last_modified.to_timespec()
    }).unwrap_or(false)
}

fn header_val<'a>(header: Vec<&'a str>) -> CowString<'a> {
    if header.len() == 1 {
        Cow::Borrowed(header[0])
    } else {
        Cow::Owned(header.concat())
    }
}

fn res_header_val<'a>(header: &'a Vec<String>) -> CowString<'a> {
    if header.len() == 1 {
        Cow::Borrowed(header[0].as_slice())
    } else {
        Cow::Owned(header.concat())
    }
}

fn parse_http_date<S: Str>(string: S) -> Result<Tm, ()> {
    let string = string.as_slice();

    parse_rfc1123(string)
        .or_else(|_| parse_rfc850(string))
        .or_else(|_| parse_asctime(string))
        .map_err(|_| ())
}

fn parse_rfc1123(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d %b %Y %T GMT")
}

fn parse_rfc850(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d-%m-%y %T GMT")
}

fn parse_asctime(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a %m%t%d %T %Y")
}

#[cfg(test)]
mod tests {
    extern crate "conduit-test" as test;

    use std::collections::HashMap;
    use std::error::Error;
    use std::old_io::MemReader;
    use time;
    use time::Tm;
    use conduit;
    use conduit::{Request, Response, Handler, Method};
    use middleware::MiddlewareBuilder;

    use super::ConditionalGet;

    macro_rules! returning {
        ($code:expr, $($header:expr => $value:expr),+) => ({
            let mut headers = HashMap::new();
            $(headers.insert($header.to_string(), vec!($value.to_string()));)+
            let handler = SimpleHandler::new(headers, $code, "hello");
            let mut stack = MiddlewareBuilder::new(handler);
            stack.add(ConditionalGet);
            stack
        });
        ($($header:expr => $value:expr),+) => ({
            returning!((200, "OK"), $($header => $value),+)
        })
    }

    macro_rules! request {
        ($($header:expr => $value:expr),+) => ({
            let mut req = test::MockRequest::new(Method::Get, "/");
            $(req.header($header, $value.to_string().as_slice());)+
            req
        })
    }

    #[test]
    fn test_sends_304() {
        let handler = returning!("Last-Modified" => httpdate(time::now()));
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_if_older_than_now() {
        let handler = returning!("Last-Modified" => before_now());
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_with_etag() {
        let handler = returning!("ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_time_but_not_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "4321"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_etag_but_not_time() {
        let handler = returning!("Last-Modified" => now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_etag() {
        let handler = returning!("ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-None-Match" => "4321"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_time() {
        let handler = returning!("Last-Modified" => now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now()
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_with_fresh_time_and_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_does_not_affect_non_200() {
        let code = (302, "Found");
        let handler = returning!(code, "Last-Modified" => before_now(), "ETag" => "1234");
        expect(code, handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_does_not_affect_malformed_timestamp() {
        let bad_stamp = time::now().strftime("%Y-%m-%d %H:%M:%S %z").unwrap().to_string();
        let handler = returning!("Last-Modified" => before_now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => bad_stamp
        ) as &mut conduit::Request));
    }

    fn expect_304(response: Result<Response, Box<Error+Send>>) {
        let mut response = response.ok().expect("No response");
        let body = response.body.read_to_string().ok().expect("No body");

        assert_eq!(response.status, (304, "Not Modified"));
        assert_eq!(body.as_slice(), "");
    }

    fn expect_200(response: Result<Response, Box<Error+Send>>) {
        expect((200, "OK"), response);
    }

    fn expect(status: (u32, &'static str), response: Result<Response, Box<Error+Send>>) {
        let mut response = response.ok().expect("No response");
        let body = response.body.read_to_string().ok().expect("No body");

        assert_eq!(response.status, status);
        assert_eq!(body.as_slice(), "hello");
    }

    struct SimpleHandler {
        map: HashMap<String, Vec<String>>,
        status: Status,
        body: &'static str
    }

    type Status = (u32, &'static str);

    impl SimpleHandler {
        fn new(map: HashMap<String, Vec<String>>, status: Status, body: &'static str) -> SimpleHandler {
            SimpleHandler { map: map, status: status, body: body }
        }
    }

    impl Handler for SimpleHandler {
        fn call(&self, _: &mut Request) -> Result<Response, Box<Error+Send>> {
            Ok(Response {
                status: self.status,
                headers: self.map.clone(),
                body: Box::new(MemReader::new(self.body.to_string().into_bytes())),
            })
        }
    }

    fn before_now() -> String {
        let mut now = time::now();
        now.tm_year -= 1;
        httpdate(now)
    }

    fn now() -> String {
        httpdate(time::now())
    }

    fn httpdate(time: Tm) -> String {
        time.strftime("%a, %d-%m-%y %T GMT").unwrap().to_string()
    }
}
<|endoftext|>


<commit_before>//! An element-tree style XML library
//!
//! # Examples
//!
//! ## Reading
//!
//! ```
//! use treexml::Document;
//!
//! let doc_raw = r#"
//! <?xml version="1.1" encoding="UTF-8"?>
//! <table>
//!     <fruit type="apple">worm</fruit>
//!     <vegetable />
//! </table>
//! "#;
//!
//! let doc = Document::parse(doc_raw.as_bytes()).unwrap();
//! let root = doc.root.unwrap();
//!
//! let fruit = root.find_child(|tag| tag.name == "fruit").unwrap().clone();
//! println!("{} [{:?}] = {}", fruit.name, fruit.attributes, fruit.text.unwrap());
//! ```
//!
//! ## Writing
//!
//! ```
//! use treexml::{Document, Element};
//!
//! let mut root = Element::new("root");
//! let mut child = Element::new("child");
//! child.text = Some("contents".to_owned());
//! root.children.push(child);
//!
//! let doc = Document{
//!     root: Some(root),
//!     .. Document::default()
//! };
//!
//! println!("{}", doc);
//! ```

extern crate xml;

use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt;
use std::io::{Read, Write};
use std::iter::Filter;
use std::slice::{Iter, IterMut};

use xml::common::XmlVersion as BaseXmlVersion;

/// The common error type for all XML tree operations
#[derive(Debug)]
pub enum Error {
    /// Error parsing input data into an XML tree
    ParseError(xml::reader::Error),
    WriteError(xml::writer::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::ParseError(ref e) => e.fmt(f),
            Error::WriteError(ref e) => e.fmt(f),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::ParseError(ref e) => e.description(),
            Error::WriteError(_) => "Error writing XML element",
        }
    }
}

impl From<xml::reader::Error> for Error {
    fn from(err: xml::reader::Error) -> Error {
        Error::ParseError(err)
    }
}

impl From<xml::writer::Error> for Error {
    fn from(err: xml::writer::Error) -> Error {
        Error::WriteError(err)
    }
}

/// Enumeration of XML versions
///
/// This exists solely because `xml-rs`'s `XmlVersion` doesn't implement Debug
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum XmlVersion {
    /// XML Version 1.0
    Version10,
    /// XML Version 1.1
    Version11,
}

impl From<BaseXmlVersion> for XmlVersion {
    fn from(v: BaseXmlVersion) -> XmlVersion {
        match v {
            BaseXmlVersion::Version10 => XmlVersion::Version10,
            BaseXmlVersion::Version11 => XmlVersion::Version11,
        }
    }
}

impl Into<BaseXmlVersion> for XmlVersion {
    fn into(self) -> BaseXmlVersion {
        match self {
            XmlVersion::Version10 => BaseXmlVersion::Version10,
            XmlVersion::Version11 => BaseXmlVersion::Version11,
        }
    }
}

/// An XML element
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Element {
    /// Tag prefix, used for namespacing: `xsl` in `xsl:for-each`
    pub prefix: Option<String>,
    /// Tag name: `for-each` in `xsl:for-each`
    pub name: String,
    /// Tag attributes
    pub attributes: HashMap<String, String>,
    /// A vector of child elements
    pub children: Vec<Element>,
    /// Contents of the element
    pub text: Option<String>,
    /// CDATA contents of the element
    pub cdata: Option<String>,
}

impl Default for Element {
    fn default() -> Self {
        Element {
            prefix: None,
            name: "tag".to_owned(),
            attributes: HashMap::new(),
            children: Vec::new(),
            text: None,
            cdata: None,
        }
    }
}

impl Element {
    /// Create a new `Element` with the tag name `name`
    pub fn new<S>(name: S) -> Element
    where
        S: Into<String>,
    {
        Element {
            name: name.into(),
            ..Element::default()
        }
    }

    /// Parse the contents of an element
    fn parse<R: Read>(
        &mut self,
        mut reader: &mut xml::reader::EventReader<R>,
    ) -> Result<(), Error> {

        use xml::reader::XmlEvent;

        loop {
            let ev = reader.next()?;
            match ev {
                XmlEvent::StartElement { name, attributes, .. } => {

                    let mut attr_map = HashMap::new();
                    for attr in attributes {
                        let attr_name = match attr.name.prefix {
                            Some(prefix) => format!("{}:{}", prefix, attr.name.local_name),
                            None => attr.name.local_name,
                        };
                        attr_map.insert(attr_name, attr.value);
                    }

                    let mut child = Element {
                        prefix: name.prefix,
                        name: name.local_name,
                        attributes: attr_map,
                        ..Element::default()
                    };
                    child.parse(&mut reader)?;
                    self.children.push(child);

                },
                XmlEvent::EndElement { name } => {

                    if name.prefix == self.prefix && name.local_name == self.name {
                        return Ok(());
                    } else {
                        // This should never happen, since the base xml library will panic first
                        panic!("Unexpected closing tag: {}, expected {}", name, self.name);
                    }

                },
                XmlEvent::Characters(s) => {

                    let text = match self.text {
                        Some(ref v) => v.clone(),
                        None => String::new(),
                    };
                    self.text = Some(text + &s);

                },
                XmlEvent::CData(s) => {

                    let cdata = match self.cdata {
                        Some(ref v) => v.clone(),
                        None => String::new(),
                    };
                    self.cdata = Some(cdata + &s);

                },
                XmlEvent::StartDocument { .. } |
                XmlEvent::EndDocument |
                XmlEvent::ProcessingInstruction { .. } |
                XmlEvent::Whitespace(_) |
                XmlEvent::Comment(_) => {},
            }
        }
    }

    /// Write an element and its contents to `writer`
    fn write<W: Write>(&self, writer: &mut xml::writer::EventWriter<W>) -> Result<(), Error> {

        use xml::writer::XmlEvent;
        use xml::name::Name;
        use xml::attribute::Attribute;
        use xml::namespace::Namespace;

        let name = Name::local(&self.name);
        let mut attributes = Vec::with_capacity(self.attributes.len());
        for (k, v) in &self.attributes {
            attributes.push(Attribute {
                name: Name::local(k),
                value: v,
            });
        }

        let namespace = Namespace::empty();

        writer.write(XmlEvent::StartElement {
            name: name,
            attributes: Cow::Owned(attributes),
            namespace: Cow::Owned(namespace),
        })?;

        if let Some(ref text) = self.text {
            writer.write(XmlEvent::Characters(&text[..]))?;
        }
        if let Some(ref cdata) = self.cdata {
            writer.write(XmlEvent::CData(&cdata[..]))?;
        }

        for e in &self.children {
            e.write(writer)?;
        }

        writer.write(XmlEvent::EndElement { name: Some(name) })?;

        Ok(())

    }

    /// Find a single child of the current `Element`, given a predicate
    pub fn find_child<P>(&self, predicate: P) -> Option<&Element>
    where
        P: for<'r> Fn(&'r &Element) -> bool,
    {
        self.children.iter().find(predicate)
    }

    /// Find a single child of the current `Element`, given a predicate; returns a mutable borrow
    pub fn find_child_mut<P>(&mut self, predicate: P) -> Option<&mut Element>
    where
        P: for<'r> FnMut(&'r &mut Element) -> bool,
    {
        self.children.iter_mut().find(predicate)
    }

    /// Filters the children of the current `Element`, given a predicate
    pub fn filter_children<P>(&self, predicate: P) -> Filter<Iter<Element>, P>
    where
        P: for<'r> Fn(&'r &Element) -> bool,
    {
        self.children.iter().filter(predicate)
    }

    /// Filters the children of the current `Element`, given a predicate; returns a mutable iterator
    pub fn filter_children_mut<P>(&mut self, predicate: P) -> Filter<IterMut<Element>, P>
    where
        P: for<'r> FnMut(&'r &mut Element) -> bool,
    {
        self.children.iter_mut().filter(predicate)
    }
}

impl fmt::Display for Element {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let doc = Document {
            root: Some(self.clone()),
            ..Document::default()
        };
        let mut v = Vec::<u8>::new();
        doc._write(&mut v, false, "  ").unwrap();
        let s = String::from_utf8(v).unwrap();
        f.write_str(&s[..])
    }
}

/// An XML document
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Document {
    /// Version of the XML document
    pub version: XmlVersion,
    /// Encoding of the XML document
    pub encoding: String,
    /// Root tag of the XML document
    pub root: Option<Element>,
}

impl Default for Document {
    fn default() -> Self {
        Document {
            version: XmlVersion::Version10,
            encoding: "UTF-8".to_owned(),
            root: None,
        }
    }
}

impl Document {
    /// Create a new `Document` with default values
    pub fn new() -> Document {
        Document { ..Document::default() }
    }

    /// Parse data from a reader to construct an XML document
    ///
    /// # Failures
    ///
    /// Passes any errors that the `xml-rs` library returns up the stack
    pub fn parse<R: Read>(r: R) -> Result<Document, Error> {

        use xml::reader::{EventReader, XmlEvent};

        let mut reader = EventReader::new(r);
        let mut doc = Document::new();

        loop {
            let ev = reader.next()?;
            match ev {
                XmlEvent::StartDocument { version, encoding, .. } => {
                    doc.version = XmlVersion::from(version);
                    doc.encoding = encoding;
                },
                XmlEvent::StartElement { name, attributes, .. } => {

                    // Start of the root element

                    let mut attr_map = HashMap::new();
                    for attr in attributes {
                        let attr_name = match attr.name.prefix {
                            Some(prefix) => format!("{}:{}", prefix, attr.name.local_name),
                            None => attr.name.local_name,
                        };
                        attr_map.insert(attr_name, attr.value);
                    }

                    let mut root = Element {
                        prefix: name.prefix,
                        name: name.local_name,
                        attributes: attr_map,
                        ..Element::default()
                    };
                    root.parse(&mut reader)?;
                    doc.root = Some(root);

                },
                XmlEvent::EndDocument => break,
                _ => {},
            }
        }

        Ok(doc)

    }

    pub fn write<W: Write>(&self, mut w: &mut W) -> Result<(), Error> {
        self._write(&mut w, true, "  ")
    }

    /// Writes a document to `w`
    fn _write<W: Write>(
        &self,
        w: &mut W,
        document_decl: bool,
        indent_str: &'static str,
    ) -> Result<(), Error> {

        use xml::writer::{EmitterConfig, XmlEvent};

        let mut writer = EmitterConfig::new()
            .perform_indent(true)
            .write_document_declaration(document_decl)
            .indent_string(indent_str)
            .create_writer(w);

        if document_decl {
            writer.write(XmlEvent::StartDocument {
                version: self.version.into(),
                encoding: Some(&self.encoding),
                standalone: None,
            })?;
        }

        if let Some(ref e) = self.root {
            e.write(&mut writer)?;
        }

        Ok(())

    }
}

impl fmt::Display for Document {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut v = Vec::<u8>::new();
        self.write(&mut v).unwrap();
        let s = String::from_utf8(v).unwrap();
        f.write_str(&s[..])
    }
}
<commit_msg>implement From instead of Into<commit_after>//! An element-tree style XML library
//!
//! # Examples
//!
//! ## Reading
//!
//! ```
//! use treexml::Document;
//!
//! let doc_raw = r#"
//! <?xml version="1.1" encoding="UTF-8"?>
//! <table>
//!     <fruit type="apple">worm</fruit>
//!     <vegetable />
//! </table>
//! "#;
//!
//! let doc = Document::parse(doc_raw.as_bytes()).unwrap();
//! let root = doc.root.unwrap();
//!
//! let fruit = root.find_child(|tag| tag.name == "fruit").unwrap().clone();
//! println!("{} [{:?}] = {}", fruit.name, fruit.attributes, fruit.text.unwrap());
//! ```
//!
//! ## Writing
//!
//! ```
//! use treexml::{Document, Element};
//!
//! let mut root = Element::new("root");
//! let mut child = Element::new("child");
//! child.text = Some("contents".to_owned());
//! root.children.push(child);
//!
//! let doc = Document{
//!     root: Some(root),
//!     .. Document::default()
//! };
//!
//! println!("{}", doc);
//! ```

extern crate xml;

use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt;
use std::io::{Read, Write};
use std::iter::Filter;
use std::slice::{Iter, IterMut};

use xml::common::XmlVersion as BaseXmlVersion;

/// The common error type for all XML tree operations
#[derive(Debug)]
pub enum Error {
    /// Error parsing input data into an XML tree
    ParseError(xml::reader::Error),
    WriteError(xml::writer::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::ParseError(ref e) => e.fmt(f),
            Error::WriteError(ref e) => e.fmt(f),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::ParseError(ref e) => e.description(),
            Error::WriteError(_) => "Error writing XML element",
        }
    }
}

impl From<xml::reader::Error> for Error {
    fn from(err: xml::reader::Error) -> Error {
        Error::ParseError(err)
    }
}

impl From<xml::writer::Error> for Error {
    fn from(err: xml::writer::Error) -> Error {
        Error::WriteError(err)
    }
}

/// Enumeration of XML versions
///
/// This exists solely because `xml-rs`'s `XmlVersion` doesn't implement Debug
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum XmlVersion {
    /// XML Version 1.0
    Version10,
    /// XML Version 1.1
    Version11,
}

impl From<BaseXmlVersion> for XmlVersion {
    fn from(value: BaseXmlVersion) -> XmlVersion {
        match value {
            BaseXmlVersion::Version10 => XmlVersion::Version10,
            BaseXmlVersion::Version11 => XmlVersion::Version11,
        }
    }
}

impl From<XmlVersion> for BaseXmlVersion {
    fn from(value: XmlVersion) -> BaseXmlVersion {
        match value {
            XmlVersion::Version10 => BaseXmlVersion::Version10,
            XmlVersion::Version11 => BaseXmlVersion::Version11,
        }
    }
}

/// An XML element
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Element {
    /// Tag prefix, used for namespacing: `xsl` in `xsl:for-each`
    pub prefix: Option<String>,
    /// Tag name: `for-each` in `xsl:for-each`
    pub name: String,
    /// Tag attributes
    pub attributes: HashMap<String, String>,
    /// A vector of child elements
    pub children: Vec<Element>,
    /// Contents of the element
    pub text: Option<String>,
    /// CDATA contents of the element
    pub cdata: Option<String>,
}

impl Default for Element {
    fn default() -> Self {
        Element {
            prefix: None,
            name: "tag".to_owned(),
            attributes: HashMap::new(),
            children: Vec::new(),
            text: None,
            cdata: None,
        }
    }
}

impl Element {
    /// Create a new `Element` with the tag name `name`
    pub fn new<S>(name: S) -> Element
    where
        S: Into<String>,
    {
        Element {
            name: name.into(),
            ..Element::default()
        }
    }

    /// Parse the contents of an element
    fn parse<R: Read>(
        &mut self,
        mut reader: &mut xml::reader::EventReader<R>,
    ) -> Result<(), Error> {

        use xml::reader::XmlEvent;

        loop {
            let ev = reader.next()?;
            match ev {
                XmlEvent::StartElement { name, attributes, .. } => {

                    let mut attr_map = HashMap::new();
                    for attr in attributes {
                        let attr_name = match attr.name.prefix {
                            Some(prefix) => format!("{}:{}", prefix, attr.name.local_name),
                            None => attr.name.local_name,
                        };
                        attr_map.insert(attr_name, attr.value);
                    }

                    let mut child = Element {
                        prefix: name.prefix,
                        name: name.local_name,
                        attributes: attr_map,
                        ..Element::default()
                    };
                    child.parse(&mut reader)?;
                    self.children.push(child);

                },
                XmlEvent::EndElement { name } => {

                    if name.prefix == self.prefix && name.local_name == self.name {
                        return Ok(());
                    } else {
                        // This should never happen, since the base xml library will panic first
                        panic!("Unexpected closing tag: {}, expected {}", name, self.name);
                    }

                },
                XmlEvent::Characters(s) => {

                    let text = match self.text {
                        Some(ref v) => v.clone(),
                        None => String::new(),
                    };
                    self.text = Some(text + &s);

                },
                XmlEvent::CData(s) => {

                    let cdata = match self.cdata {
                        Some(ref v) => v.clone(),
                        None => String::new(),
                    };
                    self.cdata = Some(cdata + &s);

                },
                XmlEvent::StartDocument { .. } |
                XmlEvent::EndDocument |
                XmlEvent::ProcessingInstruction { .. } |
                XmlEvent::Whitespace(_) |
                XmlEvent::Comment(_) => {},
            }
        }
    }

    /// Write an element and its contents to `writer`
    fn write<W: Write>(&self, writer: &mut xml::writer::EventWriter<W>) -> Result<(), Error> {

        use xml::writer::XmlEvent;
        use xml::name::Name;
        use xml::attribute::Attribute;
        use xml::namespace::Namespace;

        let name = Name::local(&self.name);
        let mut attributes = Vec::with_capacity(self.attributes.len());
        for (k, v) in &self.attributes {
            attributes.push(Attribute {
                name: Name::local(k),
                value: v,
            });
        }

        let namespace = Namespace::empty();

        writer.write(XmlEvent::StartElement {
            name: name,
            attributes: Cow::Owned(attributes),
            namespace: Cow::Owned(namespace),
        })?;

        if let Some(ref text) = self.text {
            writer.write(XmlEvent::Characters(&text[..]))?;
        }
        if let Some(ref cdata) = self.cdata {
            writer.write(XmlEvent::CData(&cdata[..]))?;
        }

        for e in &self.children {
            e.write(writer)?;
        }

        writer.write(XmlEvent::EndElement { name: Some(name) })?;

        Ok(())

    }

    /// Find a single child of the current `Element`, given a predicate
    pub fn find_child<P>(&self, predicate: P) -> Option<&Element>
    where
        P: for<'r> Fn(&'r &Element) -> bool,
    {
        self.children.iter().find(predicate)
    }

    /// Find a single child of the current `Element`, given a predicate; returns a mutable borrow
    pub fn find_child_mut<P>(&mut self, predicate: P) -> Option<&mut Element>
    where
        P: for<'r> FnMut(&'r &mut Element) -> bool,
    {
        self.children.iter_mut().find(predicate)
    }

    /// Filters the children of the current `Element`, given a predicate
    pub fn filter_children<P>(&self, predicate: P) -> Filter<Iter<Element>, P>
    where
        P: for<'r> Fn(&'r &Element) -> bool,
    {
        self.children.iter().filter(predicate)
    }

    /// Filters the children of the current `Element`, given a predicate; returns a mutable iterator
    pub fn filter_children_mut<P>(&mut self, predicate: P) -> Filter<IterMut<Element>, P>
    where
        P: for<'r> FnMut(&'r &mut Element) -> bool,
    {
        self.children.iter_mut().filter(predicate)
    }
}

impl fmt::Display for Element {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let doc = Document {
            root: Some(self.clone()),
            ..Document::default()
        };
        let mut v = Vec::<u8>::new();
        doc._write(&mut v, false, "  ").unwrap();
        let s = String::from_utf8(v).unwrap();
        f.write_str(&s[..])
    }
}

/// An XML document
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Document {
    /// Version of the XML document
    pub version: XmlVersion,
    /// Encoding of the XML document
    pub encoding: String,
    /// Root tag of the XML document
    pub root: Option<Element>,
}

impl Default for Document {
    fn default() -> Self {
        Document {
            version: XmlVersion::Version10,
            encoding: "UTF-8".to_owned(),
            root: None,
        }
    }
}

impl Document {
    /// Create a new `Document` with default values
    pub fn new() -> Document {
        Document { ..Document::default() }
    }

    /// Parse data from a reader to construct an XML document
    ///
    /// # Failures
    ///
    /// Passes any errors that the `xml-rs` library returns up the stack
    pub fn parse<R: Read>(r: R) -> Result<Document, Error> {

        use xml::reader::{EventReader, XmlEvent};

        let mut reader = EventReader::new(r);
        let mut doc = Document::new();

        loop {
            let ev = reader.next()?;
            match ev {
                XmlEvent::StartDocument { version, encoding, .. } => {
                    doc.version = XmlVersion::from(version);
                    doc.encoding = encoding;
                },
                XmlEvent::StartElement { name, attributes, .. } => {

                    // Start of the root element

                    let mut attr_map = HashMap::new();
                    for attr in attributes {
                        let attr_name = match attr.name.prefix {
                            Some(prefix) => format!("{}:{}", prefix, attr.name.local_name),
                            None => attr.name.local_name,
                        };
                        attr_map.insert(attr_name, attr.value);
                    }

                    let mut root = Element {
                        prefix: name.prefix,
                        name: name.local_name,
                        attributes: attr_map,
                        ..Element::default()
                    };
                    root.parse(&mut reader)?;
                    doc.root = Some(root);

                },
                XmlEvent::EndDocument => break,
                _ => {},
            }
        }

        Ok(doc)

    }

    pub fn write<W: Write>(&self, mut w: &mut W) -> Result<(), Error> {
        self._write(&mut w, true, "  ")
    }

    /// Writes a document to `w`
    fn _write<W: Write>(
        &self,
        w: &mut W,
        document_decl: bool,
        indent_str: &'static str,
    ) -> Result<(), Error> {

        use xml::writer::{EmitterConfig, XmlEvent};

        let mut writer = EmitterConfig::new()
            .perform_indent(true)
            .write_document_declaration(document_decl)
            .indent_string(indent_str)
            .create_writer(w);

        if document_decl {
            writer.write(XmlEvent::StartDocument {
                version: self.version.into(),
                encoding: Some(&self.encoding),
                standalone: None,
            })?;
        }

        if let Some(ref e) = self.root {
            e.write(&mut writer)?;
        }

        Ok(())

    }
}

impl fmt::Display for Document {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut v = Vec::<u8>::new();
        self.write(&mut v).unwrap();
        let s = String::from_utf8(v).unwrap();
        f.write_str(&s[..])
    }
}
<|endoftext|>


<commit_before>//! # derive_more
//! Rust has lots of builtin traits that are implemented for its basic types, such as [`Add`],
//! [`Not`] or [`From`].
//! However, when wrapping these types inside your own structs or enums you lose the
//! implementations of these traits and are required to recreate them.
//! This is especially annoying when your own structures are very simple, such as when using the
//! commonly advised newtype pattern (e.g. `MyInt(i32)`).
//!
//! This library tries to remove these annoyances and the corresponding boilerplate code.
//! It does this by allowing you to derive lots of commonly used traits for both structs and enums.
//!
//! ## Example code
//!
//! By using this library the following code just works:
//!
//!
//! ```rust
//! # #[macro_use] extern crate derive_more;
//!
//! #[derive(Debug, Eq, PartialEq, From, Add)]
//! struct MyInt(i32);
//!
//! #[derive(Debug, Eq, PartialEq, From, Into, Constructor, Mul)]
//! struct Point2D {
//!     x: i32,
//!     y: i32,
//! }
//!
//! #[derive(Debug, Eq, PartialEq, From, Add)]
//! enum MyEnum {
//!     Int(i32),
//!     UnsignedInt(u32),
//!     Nothing,
//! }
//!
//! fn main() {
//!     let my_11 = MyInt(5) + 6.into();
//!     assert_eq!(MyInt(11), MyInt(5) + 6.into());
//!     assert_eq!(Point2D { x: 5, y: 6 } * 10, (50, 60).into());
//!     assert_eq!((5, 6), Point2D { x: 5, y: 6 }.into());
//!     assert_eq!(Point2D { x: 5, y: 6 }, Point2D::new(5, 6));
//!     assert_eq!(MyEnum::Int(15), (MyEnum::Int(8) + 7.into()).unwrap())
//! }
//! ```
//!
//! ## The newly derivable traits
//!
//! Obviously not all traits should be derived to the same code, because they are different
//! traits after all.
//! However, some of the semantics of the traits overlap a lot, so they have been grouped in the
//! following way:
//!
//! 1. `From`, only contains [`From`].
//! 2. `Into`, only contains [`Into`].
//! 3. `Constructor`, this doesn't derive a trait, but it derives a `new` method that can be
//!    used as a constructor.
//! 4. Newtype derives (and structs with one field), contains [`FromStr`].
//! 5. `Not`-like, contains [`Not`] and [`Neg`].
//! 6. `Add`-like, contains [`Add`], [`Sub`], [`BitAnd`], [`BitOr`] and [`BitXor`].
//! 7. `AddAssign`-like, contains [`AddAssign`], [`SubAssign`], [`BitAndAssign`], [`BitOrAssign`]
//!    and [`BitXorAssign`].
//! 8. `Mul`-like, contains [`Mul`], [`Div`], [`Rem`], [`Shr`] and [`Shl`].
//! 9. `MulAssign`-like, contains [`MulAssign`], [`DivAssign`], [`RemAssign`], [`ShrAssign`] and [`ShlAssign`].
//!
//!
//! ## Generated code
//!
//! It is important to understand what code gets generated when using one of the derives from this
//! crate.
//! That is why the links below explain what code gets generated for a trait for each group from
//! before.
//!
//! 1. [`#[derive(From)]`](from.html)
//! 2. [`#[derive(Into)]`](into.html)
//! 3. [`#[derive(Constructor)]`](constructor.html)
//! 4. [`#[derive(FromStr)]`](fromstr.html)
//! 5. [`#[derive(Not)]`](not.html)
//! 6. [`#[derive(Add)]`](add.html)
//! 7. [`#[derive(AddAssign)]`](add_assign.html)
//! 8. [`#[derive(Mul)]`](mul.html)
//! 9. [`#[derive(MulAssign)]`](mul_assign.html)
//!
//! If you want to be sure what code is generated for your specific type I recommend using the
//! [`cargo-expand`] utility.
//! This will show you your code with all macros and derives expanded.
//!
//! ## Installation
//!
//! This library requires Rust 1.15 or higher, so this needs to be installed.
//! Then add the following to `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! derive_more = "0.6.0"
//! ```
//!
//! And this to the top of your Rust file:
//!
//! ```rust
//! #[macro_use]
//! extern crate derive_more;
//! # fn main () {}
//! ```
//!
//! [`cargo-expand`]: https://github.com/dtolnay/cargo-expand
//! [`From`]: https://doc.rust-lang.org/core/convert/trait.From.html
//! [`Into`]: https://doc.rust-lang.org/core/convert/trait.Into.html
//! [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html
//! [`Not`]: https://doc.rust-lang.org/std/ops/trait.Not.html
//! [`Neg`]: https://doc.rust-lang.org/std/ops/trait.Neg.html
//! [`Add`]: https://doc.rust-lang.org/std/ops/trait.Add.html
//! [`Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html
//! [`BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html
//! [`BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html
//! [`BitXor`]: https://doc.rust-lang.org/std/ops/trait.BitXor.html
//! [`AddAssign`]: https://doc.rust-lang.org/std/ops/trait.AddAssign.html
//! [`SubAssign`]: https://doc.rust-lang.org/std/ops/trait.SubAssign.html
//! [`BitAndAssign`]: https://doc.rust-lang.org/std/ops/trait.BitAndAssign.html
//! [`BitOrAssign`]: https://doc.rust-lang.org/std/ops/trait.BitOrAssign.html
//! [`BitXorAssign`]: https://doc.rust-lang.org/std/ops/trait.BitXorAssign.html
//! [`Mul`]: https://doc.rust-lang.org/std/ops/trait.Mul.html
//! [`Div`]: https://doc.rust-lang.org/std/ops/trait.Div.html
//! [`Rem`]: https://doc.rust-lang.org/std/ops/trait.Rem.html
//! [`Shr`]: https://doc.rust-lang.org/std/ops/trait.Shr.html
//! [`Shl`]: https://doc.rust-lang.org/std/ops/trait.Shl.html
//! [`MulAssign`]: https://doc.rust-lang.org/std/ops/trait.MulAssign.html
//! [`DivAssign`]: https://doc.rust-lang.org/std/ops/trait.DivAssign.html
//! [`RemAssign`]: https://doc.rust-lang.org/std/ops/trait.RemAssign.html
//! [`ShrAssign`]: https://doc.rust-lang.org/std/ops/trait.ShrAssign.html
//! [`ShlAssign`]: https://doc.rust-lang.org/std/ops/trait.ShlAssign.html

extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate syn;

use proc_macro::TokenStream;

mod utils;

mod from;
mod into;
mod constructor;
mod not_like;
mod add_like;
mod add_assign_like;
mod mul_like;
mod mul_assign_like;
mod from_str;

macro_rules! create_derive(
    ($mod_:ident, $trait_:ident, $fn_name: ident) => {
        #[proc_macro_derive($trait_)]
        #[doc(hidden)]
        pub fn $fn_name(input: TokenStream) -> TokenStream {
            let ast = syn::parse(input).unwrap();
            $mod_::expand(&ast, stringify!($trait_)).into()
        }
    }
);

create_derive!(from, From, from_derive);

create_derive!(into, Into, into_derive);

create_derive!(constructor, Constructor, constructor_derive);

create_derive!(not_like, Not, not_derive);
create_derive!(not_like, Neg, neg_derive);

create_derive!(add_like, Add, add_derive);
create_derive!(add_like, Sub, sub_derive);
create_derive!(add_like, BitAnd, bit_and_derive);
create_derive!(add_like, BitOr, bit_or_derive);
create_derive!(add_like, BitXor, bit_xor_derive);

create_derive!(mul_like, Mul, mul_derive);
create_derive!(mul_like, Div, div_derive);
create_derive!(mul_like, Rem, rem_derive);
create_derive!(mul_like, Shr, shr_derive);
create_derive!(mul_like, Shl, shl_derive);

create_derive!(add_assign_like, AddAssign, add_assign_derive);
create_derive!(add_assign_like, SubAssign, sub_assign_derive);
create_derive!(add_assign_like, BitAndAssign, bit_and_assign_derive);
create_derive!(add_assign_like, BitOrAssign, bit_or_assign_derive);
create_derive!(add_assign_like, BitXorAssign, bit_xor_assign_derive);

create_derive!(mul_assign_like, MulAssign, mul_assign_derive);
create_derive!(mul_assign_like, DivAssign, div_assign_derive);
create_derive!(mul_assign_like, RemAssign, rem_assign_derive);
create_derive!(mul_assign_like, ShrAssign, shr_assign_derive);
create_derive!(mul_assign_like, ShlAssign, shl_assign_derive);

create_derive!(from_str, FromStr, from_str_derive);
<commit_msg>Docs: Correct link<commit_after>//! # derive_more
//! Rust has lots of builtin traits that are implemented for its basic types, such as [`Add`],
//! [`Not`] or [`From`].
//! However, when wrapping these types inside your own structs or enums you lose the
//! implementations of these traits and are required to recreate them.
//! This is especially annoying when your own structures are very simple, such as when using the
//! commonly advised newtype pattern (e.g. `MyInt(i32)`).
//!
//! This library tries to remove these annoyances and the corresponding boilerplate code.
//! It does this by allowing you to derive lots of commonly used traits for both structs and enums.
//!
//! ## Example code
//!
//! By using this library the following code just works:
//!
//!
//! ```rust
//! # #[macro_use] extern crate derive_more;
//!
//! #[derive(Debug, Eq, PartialEq, From, Add)]
//! struct MyInt(i32);
//!
//! #[derive(Debug, Eq, PartialEq, From, Into, Constructor, Mul)]
//! struct Point2D {
//!     x: i32,
//!     y: i32,
//! }
//!
//! #[derive(Debug, Eq, PartialEq, From, Add)]
//! enum MyEnum {
//!     Int(i32),
//!     UnsignedInt(u32),
//!     Nothing,
//! }
//!
//! fn main() {
//!     let my_11 = MyInt(5) + 6.into();
//!     assert_eq!(MyInt(11), MyInt(5) + 6.into());
//!     assert_eq!(Point2D { x: 5, y: 6 } * 10, (50, 60).into());
//!     assert_eq!((5, 6), Point2D { x: 5, y: 6 }.into());
//!     assert_eq!(Point2D { x: 5, y: 6 }, Point2D::new(5, 6));
//!     assert_eq!(MyEnum::Int(15), (MyEnum::Int(8) + 7.into()).unwrap())
//! }
//! ```
//!
//! ## The newly derivable traits
//!
//! Obviously not all traits should be derived to the same code, because they are different
//! traits after all.
//! However, some of the semantics of the traits overlap a lot, so they have been grouped in the
//! following way:
//!
//! 1. `From`, only contains [`From`].
//! 2. `Into`, only contains [`Into`].
//! 3. `Constructor`, this doesn't derive a trait, but it derives a `new` method that can be
//!    used as a constructor.
//! 4. Newtype derives (and structs with one field), contains [`FromStr`].
//! 5. `Not`-like, contains [`Not`] and [`Neg`].
//! 6. `Add`-like, contains [`Add`], [`Sub`], [`BitAnd`], [`BitOr`] and [`BitXor`].
//! 7. `AddAssign`-like, contains [`AddAssign`], [`SubAssign`], [`BitAndAssign`], [`BitOrAssign`]
//!    and [`BitXorAssign`].
//! 8. `Mul`-like, contains [`Mul`], [`Div`], [`Rem`], [`Shr`] and [`Shl`].
//! 9. `MulAssign`-like, contains [`MulAssign`], [`DivAssign`], [`RemAssign`], [`ShrAssign`] and [`ShlAssign`].
//!
//!
//! ## Generated code
//!
//! It is important to understand what code gets generated when using one of the derives from this
//! crate.
//! That is why the links below explain what code gets generated for a trait for each group from
//! before.
//!
//! 1. [`#[derive(From)]`](from.html)
//! 2. [`#[derive(Into)]`](into.html)
//! 3. [`#[derive(Constructor)]`](constructor.html)
//! 4. [`#[derive(FromStr)]`](from_str.html)
//! 5. [`#[derive(Not)]`](not.html)
//! 6. [`#[derive(Add)]`](add.html)
//! 7. [`#[derive(AddAssign)]`](add_assign.html)
//! 8. [`#[derive(Mul)]`](mul.html)
//! 9. [`#[derive(MulAssign)]`](mul_assign.html)
//!
//! If you want to be sure what code is generated for your specific type I recommend using the
//! [`cargo-expand`] utility.
//! This will show you your code with all macros and derives expanded.
//!
//! ## Installation
//!
//! This library requires Rust 1.15 or higher, so this needs to be installed.
//! Then add the following to `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! derive_more = "0.6.0"
//! ```
//!
//! And this to the top of your Rust file:
//!
//! ```rust
//! #[macro_use]
//! extern crate derive_more;
//! # fn main () {}
//! ```
//!
//! [`cargo-expand`]: https://github.com/dtolnay/cargo-expand
//! [`From`]: https://doc.rust-lang.org/core/convert/trait.From.html
//! [`Into`]: https://doc.rust-lang.org/core/convert/trait.Into.html
//! [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html
//! [`Not`]: https://doc.rust-lang.org/std/ops/trait.Not.html
//! [`Neg`]: https://doc.rust-lang.org/std/ops/trait.Neg.html
//! [`Add`]: https://doc.rust-lang.org/std/ops/trait.Add.html
//! [`Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html
//! [`BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html
//! [`BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html
//! [`BitXor`]: https://doc.rust-lang.org/std/ops/trait.BitXor.html
//! [`AddAssign`]: https://doc.rust-lang.org/std/ops/trait.AddAssign.html
//! [`SubAssign`]: https://doc.rust-lang.org/std/ops/trait.SubAssign.html
//! [`BitAndAssign`]: https://doc.rust-lang.org/std/ops/trait.BitAndAssign.html
//! [`BitOrAssign`]: https://doc.rust-lang.org/std/ops/trait.BitOrAssign.html
//! [`BitXorAssign`]: https://doc.rust-lang.org/std/ops/trait.BitXorAssign.html
//! [`Mul`]: https://doc.rust-lang.org/std/ops/trait.Mul.html
//! [`Div`]: https://doc.rust-lang.org/std/ops/trait.Div.html
//! [`Rem`]: https://doc.rust-lang.org/std/ops/trait.Rem.html
//! [`Shr`]: https://doc.rust-lang.org/std/ops/trait.Shr.html
//! [`Shl`]: https://doc.rust-lang.org/std/ops/trait.Shl.html
//! [`MulAssign`]: https://doc.rust-lang.org/std/ops/trait.MulAssign.html
//! [`DivAssign`]: https://doc.rust-lang.org/std/ops/trait.DivAssign.html
//! [`RemAssign`]: https://doc.rust-lang.org/std/ops/trait.RemAssign.html
//! [`ShrAssign`]: https://doc.rust-lang.org/std/ops/trait.ShrAssign.html
//! [`ShlAssign`]: https://doc.rust-lang.org/std/ops/trait.ShlAssign.html

extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate syn;

use proc_macro::TokenStream;

mod utils;

mod from;
mod into;
mod constructor;
mod not_like;
mod add_like;
mod add_assign_like;
mod mul_like;
mod mul_assign_like;
mod from_str;

macro_rules! create_derive(
    ($mod_:ident, $trait_:ident, $fn_name: ident) => {
        #[proc_macro_derive($trait_)]
        #[doc(hidden)]
        pub fn $fn_name(input: TokenStream) -> TokenStream {
            let ast = syn::parse(input).unwrap();
            $mod_::expand(&ast, stringify!($trait_)).into()
        }
    }
);

create_derive!(from, From, from_derive);

create_derive!(into, Into, into_derive);

create_derive!(constructor, Constructor, constructor_derive);

create_derive!(not_like, Not, not_derive);
create_derive!(not_like, Neg, neg_derive);

create_derive!(add_like, Add, add_derive);
create_derive!(add_like, Sub, sub_derive);
create_derive!(add_like, BitAnd, bit_and_derive);
create_derive!(add_like, BitOr, bit_or_derive);
create_derive!(add_like, BitXor, bit_xor_derive);

create_derive!(mul_like, Mul, mul_derive);
create_derive!(mul_like, Div, div_derive);
create_derive!(mul_like, Rem, rem_derive);
create_derive!(mul_like, Shr, shr_derive);
create_derive!(mul_like, Shl, shl_derive);

create_derive!(add_assign_like, AddAssign, add_assign_derive);
create_derive!(add_assign_like, SubAssign, sub_assign_derive);
create_derive!(add_assign_like, BitAndAssign, bit_and_assign_derive);
create_derive!(add_assign_like, BitOrAssign, bit_or_assign_derive);
create_derive!(add_assign_like, BitXorAssign, bit_xor_assign_derive);

create_derive!(mul_assign_like, MulAssign, mul_assign_derive);
create_derive!(mul_assign_like, DivAssign, div_assign_derive);
create_derive!(mul_assign_like, RemAssign, rem_assign_derive);
create_derive!(mul_assign_like, ShrAssign, shr_assign_derive);
create_derive!(mul_assign_like, ShlAssign, shl_assign_derive);

create_derive!(from_str, FromStr, from_str_derive);
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

/*!
Bindings and wrappers for __GLib__
*/

extern crate libc;
extern crate glib_sys as glib_ffi;

pub use glib_ffi as ffi;

use libc::c_char;

pub use self::list::{List, Elem, RevElem};
pub use self::slist::{SList, SElem};
pub use self::glib_container::GlibContainer;
pub use self::error::{Error};
pub use self::permission::Permission;
pub use self::timeout_func::timeout;
pub use self::traits::{FFIGObject, Connect};
pub use self::value::{Value, ValuePublic};
pub use type_::Type;
pub use self::date::{Time, Date, Year, Month, Weekday, Day};

mod list;
mod slist;
pub mod glib_container;
mod error;
mod permission;
pub mod signal;
pub mod timeout_func;
pub mod traits;
pub mod translate;
mod value;
pub mod type_;
pub mod date;

pub fn to_gboolean(b: bool) -> ffi::Gboolean {
    match b {
        true => ffi::GTRUE,
        false => ffi::GFALSE
    }
}

pub fn to_bool(b: ffi::Gboolean) -> bool {
    b != ffi::GFALSE
}

// An opaque structure used as the base of all interface types.
pub struct TypeInterface;

// An opaque structure used as the base of all type instances.
pub struct TypeInstance;

// An opaque structure used as the base of all classes.
pub struct TypeClass;

//FIXME: Check if this is actually correct (maybe not since ParamFlags is deprecated)
#[derive(Clone, Copy)]
pub enum ParamFlags{
    Readable,
    Writable,
    ReadWrite,
    Construct,
    ConstructOnly,
    LaxValidation,
    StaticName,
    Private,
    StaticNick,
    StaticBlurb,
    Deprecated
}

#[repr(C)]
pub struct ParamSpec {
    g_type_instance: TypeInstance,
    name: *mut c_char,
    flags: ParamFlags,
    value_type: ffi::GType,
    owner_type: ffi::GType,
}<commit_msg>Add forgotten struct export<commit_after>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

/*!
Bindings and wrappers for __GLib__
*/

extern crate libc;
extern crate glib_sys as glib_ffi;

pub use glib_ffi as ffi;

use libc::c_char;

pub use self::list::{List, Elem, RevElem};
pub use self::slist::{SList, SElem};
pub use self::glib_container::GlibContainer;
pub use self::error::{Error};
pub use self::permission::Permission;
pub use self::timeout_func::timeout;
pub use self::traits::{FFIGObject, Connect};
pub use self::value::{Value, ValuePublic};
pub use type_::Type;
pub use self::date::{TimeVal, Time, Date, Year, Month, Weekday, Day};

mod list;
mod slist;
pub mod glib_container;
mod error;
mod permission;
pub mod signal;
pub mod timeout_func;
pub mod traits;
pub mod translate;
mod value;
pub mod type_;
pub mod date;

pub fn to_gboolean(b: bool) -> ffi::Gboolean {
    match b {
        true => ffi::GTRUE,
        false => ffi::GFALSE
    }
}

pub fn to_bool(b: ffi::Gboolean) -> bool {
    b != ffi::GFALSE
}

// An opaque structure used as the base of all interface types.
pub struct TypeInterface;

// An opaque structure used as the base of all type instances.
pub struct TypeInstance;

// An opaque structure used as the base of all classes.
pub struct TypeClass;

//FIXME: Check if this is actually correct (maybe not since ParamFlags is deprecated)
#[derive(Clone, Copy)]
pub enum ParamFlags{
    Readable,
    Writable,
    ReadWrite,
    Construct,
    ConstructOnly,
    LaxValidation,
    StaticName,
    Private,
    StaticNick,
    StaticBlurb,
    Deprecated
}

#[repr(C)]
pub struct ParamSpec {
    g_type_instance: TypeInstance,
    name: *mut c_char,
    flags: ParamFlags,
    value_type: ffi::GType,
    owner_type: ffi::GType,
}<|endoftext|>


<commit_before>extern crate hyper;
extern crate url;
extern crate serde;
extern crate serde_json;

use hyper::client::{Client};
use hyper::header::{ContentType};
use hyper::client::response::{Response};
use hyper::error::Error as HyperError;
use url::form_urlencoded::{serialize};
use std::io::Read;
use std::io::Error;
use std::collections::BTreeMap;
use serde_json::error::Error as JsonError;

#[derive(Debug)]
pub enum CleverbotError {
    IncorrectCredentials,
    DuplicatedReferenceNames,
    Io(HyperError),
    Api(String),
    Std(Error),
    Json(JsonError),
    MissingValue(String)
}

impl From<HyperError> for CleverbotError {
    fn from(err: HyperError) -> CleverbotError {
        CleverbotError::Io(err)
    }
}

impl From<Error> for CleverbotError {
    fn from(err: Error) -> CleverbotError {
        CleverbotError::Std(err)
    }
}

impl From<JsonError> for CleverbotError {
    fn from(err: JsonError) -> CleverbotError {
        CleverbotError::Json(err)
    }
}

pub struct Cleverbot {
    user: String,
    key: String,
    pub nick: String,
}

impl Cleverbot {
    /// Creates a new Cleverbot instance.
    /// * `user` - The API User.
    /// * `key` - The API Key.
    pub fn new(user: String, key: String, nick: Option<String>) -> Result<Cleverbot, CleverbotError> {
        let mut response = {
            let mut args = vec![
                ("user", &*user),
                ("key", &*key),
            ];
            if let Some(ref nick) = nick { args.push(("nick", &*nick)) };
            try!(request("https://cleverbot.io/1.0/create", &*args))
        };
        let mut body = String::new();
        try!(response.read_to_string(&mut body));
        let json: BTreeMap<String, String> = try!(serde_json::from_str(&body));
        let opt_result = json.get("status");
        let result = match opt_result {
            Some(result) => result,
            None => return Err(CleverbotError::MissingValue(String::from("status"))),
        };
        match result.as_ref() {
            "success" => {
                let json_nick = json.get("nick");
                let nick = match json_nick {
                    Some(nick) => nick,
                    None => return Err(CleverbotError::MissingValue(String::from("nick")))
                };
                Ok(Cleverbot {
                    user: user,
                    key: key,
                    nick: nick.to_string(),
                })
            },
            "Error: API credentials incorrect" => Err(CleverbotError::IncorrectCredentials),
            "Error: reference name already exists" => Err(CleverbotError::DuplicatedReferenceNames),
            _ => Err(CleverbotError::Api(result.to_owned()))
        }
    }

    /// Sends the bot a message and returns its response. If the nick is not set, it will
    /// set it randomly through set_nick_randomly. Returns its response or error string.
    /// * `message` - The message to send to the bot.
    pub fn say(&mut self, message: &str) -> Result<String, CleverbotError> {
        let args = vec![
            ("user", &*self.user),
            ("key", &*self.key),
            ("nick", &*self.nick),
            ("text", message),
        ];
        let mut response = {
            try!(request("https://cleverbot.io/1.0/ask", &*args))
        };
        let mut body = String::new();
        try!(response.read_to_string(&mut body));
        let json: BTreeMap<String, String> = try!(serde_json::from_str(&body));
        let opt_result = json.get("status");
        let result = match opt_result {
            Some(result) => result,
            None => return Err(CleverbotError::MissingValue(String::from("status"))),
        };
        match result.as_ref() {
            "success" => {
                let json_response = json.get("response");
                let response = match json_response {
                    Some(response) => response,
                    None => return Err(CleverbotError::MissingValue(String::from("nick"))),
                };
                Ok(response.to_string())
            },
            "Error: API credentials incorrect" => Err(CleverbotError::IncorrectCredentials),
            "Error: reference name already exists" => Err(CleverbotError::DuplicatedReferenceNames),
            _ => Err(CleverbotError::Api(result.to_owned()))
        }
    }
}

/// Submits a POST request to the URL with the given vec body.
/// * `base` - The URL
/// * `args` - A vector representing the request body.
fn request(base: &str, args: &[(&str, &str)]) -> Result<Response, HyperError> {
    let client = Client::new();
    let body = serialize(args.into_iter());
    client.post(base)
        .body(&body)
        .header(ContentType::form_url_encoded())
        .send()
}
<commit_msg>:fu: Clean up style a bit more<commit_after>extern crate hyper;
extern crate url;
extern crate serde;
extern crate serde_json;

use hyper::client::{Client};
use hyper::header::{ContentType};
use hyper::client::response::{Response};
use hyper::error::Error as HyperError;
use url::form_urlencoded::{serialize};
use std::io::Read;
use std::io::Error;
use std::collections::BTreeMap;
use serde_json::error::Error as JsonError;

#[derive(Debug)]
pub enum CleverbotError {
    IncorrectCredentials,
    DuplicatedReferenceNames,
    Io(HyperError),
    Api(String),
    Std(Error),
    Json(JsonError),
    MissingValue(String)
}

impl From<HyperError> for CleverbotError {
    fn from(err: HyperError) -> CleverbotError {
        CleverbotError::Io(err)
    }
}

impl From<Error> for CleverbotError {
    fn from(err: Error) -> CleverbotError {
        CleverbotError::Std(err)
    }
}

impl From<JsonError> for CleverbotError {
    fn from(err: JsonError) -> CleverbotError {
        CleverbotError::Json(err)
    }
}

pub struct Cleverbot {
    user: String,
    key: String,
    pub nick: String,
}

impl Cleverbot {
    /// Creates a new Cleverbot instance.
    /// * `user` - The API User.
    /// * `key` - The API Key.
    pub fn new(user: String, key: String, nick: Option<String>) -> Result<Cleverbot, CleverbotError> {
        let mut response = {
            let mut args = vec![
                ("user", &*user),
                ("key", &*key),
            ];
            if let Some(ref nick) = nick { args.push(("nick", &*nick)) };
            try!(request("https://cleverbot.io/1.0/create", &*args))
        };
        let mut body = String::new();
        try!(response.read_to_string(&mut body));
        let json: BTreeMap<String, String> = try!(serde_json::from_str(&body));
        let opt_result = json.get("status");
        let result = match opt_result {
            Some(result) => result,
            None => return Err(CleverbotError::MissingValue(String::from("status"))),
        };
        match result.as_ref() {
            "success" => {
                let json_nick = json.get("nick");
                match json_nick {
                    Some(nick) => Ok(Cleverbot {
                        user: user,
                        key: key,
                        nick: nick.to_string()
                    }),
                    None => Err(CleverbotError::MissingValue(String::from("nick"))),
                }
            },
            "Error: API credentials incorrect" => Err(CleverbotError::IncorrectCredentials),
            "Error: reference name already exists" => Err(CleverbotError::DuplicatedReferenceNames),
            _ => Err(CleverbotError::Api(result.to_owned()))
        }
    }

    /// Sends the bot a message and returns its response. If the nick is not set, it will
    /// set it randomly through set_nick_randomly. Returns its response or error string.
    /// * `message` - The message to send to the bot.
    pub fn say(&mut self, message: &str) -> Result<String, CleverbotError> {
        let args = vec![
            ("user", &*self.user),
            ("key", &*self.key),
            ("nick", &*self.nick),
            ("text", message),
        ];
        let mut response = try!(request("https://cleverbot.io/1.0/ask", &*args));
        let mut body = String::new();
        try!(response.read_to_string(&mut body));
        let json: BTreeMap<String, String> = try!(serde_json::from_str(&body));
        let opt_result = json.get("status");
        let result = match opt_result {
            Some(result) => result,
            None => return Err(CleverbotError::MissingValue(String::from("status"))),
        };
        match result.as_ref() {
            "success" => {
                let json_response = json.get("response");
                match json_response {
                    Some(response) => Ok(response.to_string()),
                    None => Err(CleverbotError::MissingValue(String::from("nick"))),
                }
            },
            "Error: API credentials incorrect" => Err(CleverbotError::IncorrectCredentials),
            "Error: reference name already exists" => Err(CleverbotError::DuplicatedReferenceNames),
            _ => Err(CleverbotError::Api(result.to_owned()))
        }
    }
}

/// Submits a POST request to the URL with the given vec body.
/// * `base` - The URL
/// * `args` - A vector representing the request body.
fn request(base: &str, args: &[(&str, &str)]) -> Result<Response, HyperError> {
    let client = Client::new();
    let body = serialize(args.into_iter());
    client.post(base)
        .body(&body)
        .header(ContentType::form_url_encoded())
        .send()
}
<|endoftext|>