<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>,
) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>> {
    let mut ecx = EvalContext::new(
        tcx.at(syntax::source_map::DUMMY_SP),
        ty::ParamEnv::reveal_all(),
        Default::default(),
        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>,
) {
    let mut ecx = create_ecx(tcx, main_id, start_wrapper).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, Default, 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>,
}

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);
    const ENFORCE_VALIDITY: bool = false; // this is still WIP

    /// 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>enforce_validity became a function<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>,
) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>> {
    let mut ecx = EvalContext::new(
        tcx.at(syntax::source_map::DUMMY_SP),
        ty::ParamEnv::reveal_all(),
        Default::default(),
        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>,
) {
    let mut ecx = create_ecx(tcx, main_id, start_wrapper).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, Default, 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>,
}

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);

    #[inline(always)]
    fn enforce_validity(_ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool {
        false // this is still WIP
    }

    /// 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>extern crate num;

pub mod create;
pub use create::*;

pub mod set;
pub use set::*;

pub mod add;
pub use add::*;

pub mod sub;
pub use sub::*;

pub mod mul;
pub use mul::*;

pub mod div;
pub use div::*;

pub mod length;
pub use length::*;

pub mod misc;
pub use misc::*;

pub mod transform;
pub use transform::*;
<commit_msg>updates<commit_after>#![feature(no_std)]
#![no_std]

extern crate num;

pub mod create;
pub use create::*;

pub mod set;
pub use set::*;

pub mod add;
pub use add::*;

pub mod sub;
pub use sub::*;

pub mod mul;
pub use mul::*;

pub mod div;
pub use div::*;

pub mod length;
pub use length::*;

pub mod misc;
pub use misc::*;

pub mod transform;
pub use transform::*;
<|endoftext|>


<commit_before>#![feature(associated_consts)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(plugin)]

#![plugin(clippy)]

extern crate uuid;
extern crate jsrs_common;
extern crate js_types;

#[macro_use] extern crate matches;

pub mod alloc;
mod gc_error;
mod scope;
mod test_utils;

use std::cell::RefCell;
use std::mem;
use std::rc::Rc;

use jsrs_common::ast::{Exp, Stmt};
use js_types::js_var::{JsPtrEnum, JsVar};
use js_types::binding::Binding;

use alloc::AllocBox;
use gc_error::{GcError, Result};
use scope::{Scope, ScopeTag};

pub struct ScopeManager {
    globals: Scope,
    curr_scope: Scope,
    closures: Vec<Scope>,
    alloc_box: Rc<RefCell<AllocBox>>,
}

impl ScopeManager {
    fn new(alloc_box: Rc<RefCell<AllocBox>>) -> ScopeManager {
        ScopeManager {
            globals: Scope::new(ScopeTag::Call, &alloc_box),
            curr_scope: Scope::new(ScopeTag::Call, &alloc_box),
            closures: Vec::new(),
            alloc_box: alloc_box,
        }
    }

    pub fn push_scope(&mut self, stmt: &Stmt) {
        let tag = match *stmt {
            Stmt::BareExp(ref exp) => match *exp {
                Exp::Call(..) => ScopeTag::Call,
                _ => ScopeTag::Block,
            },
            _ => ScopeTag::Block,
        };
        let parent = mem::replace(&mut self.curr_scope, Scope::new(tag, &self.alloc_box));
        self.curr_scope.set_parent(parent);
    }

    pub fn pop_scope(&mut self, gc_yield: bool) -> Result<()> {
        let parent = try!(self.curr_scope.transfer_stack(&mut self.closures, gc_yield));
        if let Some(parent) = parent {
            mem::replace(&mut self.curr_scope, *parent);
            Ok(())
        } else {
            Err(GcError::Scope)
        }
    }

    pub fn alloc(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        self.curr_scope.push_var(var, ptr)
    }

    /// Try to load the variable behind a binding
    pub fn load(&self, bnd: &Binding) -> Result<(JsVar, Option<JsPtrEnum>)> {
        self.curr_scope.get_var_copy(bnd)
                       // Binding lookup failed locally, so check the root
                       // scope (globals)
                       .or(self.globals.get_var_copy(bnd))
                       .ok_or_else(|| GcError::Load(bnd.clone()))
    }

    pub fn store(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        let update = self.curr_scope.update_var(var, ptr);
        if let Err(GcError::Store(var, ptr)) = update{
            self.globals.update_var(var, ptr)
        } else {
            update
        }
    }
}

pub fn init_gc() -> ScopeManager {
    let alloc_box = Rc::new(RefCell::new(AllocBox::new()));
    ScopeManager::new(alloc_box)
}

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

    use jsrs_common::ast::Stmt;
    use js_types::js_var::JsType;
    use js_types::binding::Binding;

    use gc_error::GcError;
    use test_utils;

    #[test]
    fn test_pop_scope() {
        let alloc_box = test_utils::make_alloc_box();
        let mut mgr = ScopeManager::new(alloc_box);
        mgr.push_scope(&Stmt::Empty);
        assert!(mgr.curr_scope.parent.is_some());
        mgr.pop_scope(false).unwrap();
        assert!(mgr.curr_scope.parent.is_none());
    }

    #[test]
    fn test_pop_scope_fail() {
        let alloc_box = test_utils::make_alloc_box();
        let mut mgr = ScopeManager::new(alloc_box);
        let res = mgr.pop_scope(false);
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::Scope)));
    }

    #[test]
    fn test_alloc() {
        let alloc_box = test_utils::make_alloc_box();
        let mut mgr = ScopeManager::new(alloc_box);
        mgr.alloc(test_utils::make_num(1.), None).unwrap();
        mgr.push_scope(&Stmt::Empty);
        mgr.alloc(test_utils::make_num(2.), None).unwrap();
        assert!(mgr.alloc_box.borrow().is_empty());
    }

    #[test]
    fn test_load() {
        let alloc_box = test_utils::make_alloc_box();
        let mut mgr = ScopeManager::new(alloc_box);
        let x = test_utils::make_num(1.);
        let x_bnd = x.binding.clone();
        mgr.alloc(x, None).unwrap();
        let load = mgr.load(&x_bnd);
        assert!(load.is_ok());
        let load = load.unwrap();
        match load.0.t {
            JsType::JsNum(n) => assert!(f64::abs(n - 1.) < 0.0001),
            _ => unreachable!(),
        }
        assert!(load.1.is_none());
    }

    #[test]
    fn test_load_fail() {
        let alloc_box = test_utils::make_alloc_box();
        let mgr = ScopeManager::new(alloc_box);
        let bnd = Binding::anon();
        let res = mgr.load(&bnd);
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::Load(_))));
        if let Err(GcError::Load(res_bnd)) = res {
            assert_eq!(bnd, res_bnd);
        }
    }

    #[test]
    fn test_store() {
        let alloc_box = test_utils::make_alloc_box();
        let mut mgr = ScopeManager::new(alloc_box,);
        mgr.push_scope(&Stmt::Empty);
        let x = test_utils::make_num(1.);
        let x_bnd = x.binding.clone();
        mgr.alloc(x, None).unwrap();

        let mut test_num = test_utils::make_num(2.);
        test_num.binding = x_bnd;
        assert!(mgr.store(test_num, None).is_ok());
    }

}
<commit_msg>Change Stmt parameter in push_scope to an Exp<commit_after>#![feature(associated_consts)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(plugin)]

#![plugin(clippy)]

extern crate uuid;
extern crate jsrs_common;
extern crate js_types;

#[macro_use] extern crate matches;

pub mod alloc;
mod gc_error;
mod scope;
mod test_utils;

use std::cell::RefCell;
use std::mem;
use std::rc::Rc;

use jsrs_common::ast::Exp;
use js_types::js_var::{JsPtrEnum, JsVar};
use js_types::binding::Binding;

use alloc::AllocBox;
use gc_error::{GcError, Result};
use scope::{Scope, ScopeTag};

pub struct ScopeManager {
    globals: Scope,
    curr_scope: Scope,
    closures: Vec<Scope>,
    alloc_box: Rc<RefCell<AllocBox>>,
}

impl ScopeManager {
    fn new(alloc_box: Rc<RefCell<AllocBox>>) -> ScopeManager {
        ScopeManager {
            globals: Scope::new(ScopeTag::Call, &alloc_box),
            curr_scope: Scope::new(ScopeTag::Call, &alloc_box),
            closures: Vec::new(),
            alloc_box: alloc_box,
        }
    }

    pub fn push_scope(&mut self, exp: &Exp) {
        let tag = match *exp {
            Exp::Call(..) => ScopeTag::Call,
            _ => ScopeTag::Block,
        };
        let parent = mem::replace(&mut self.curr_scope, Scope::new(tag, &self.alloc_box));
        self.curr_scope.set_parent(parent);
    }

    pub fn pop_scope(&mut self, gc_yield: bool) -> Result<()> {
        let parent = try!(self.curr_scope.transfer_stack(&mut self.closures, gc_yield));
        if let Some(parent) = parent {
            mem::replace(&mut self.curr_scope, *parent);
            Ok(())
        } else {
            Err(GcError::Scope)
        }
    }

    pub fn alloc(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        self.curr_scope.push_var(var, ptr)
    }

    /// Try to load the variable behind a binding
    pub fn load(&self, bnd: &Binding) -> Result<(JsVar, Option<JsPtrEnum>)> {
        self.curr_scope.get_var_copy(bnd)
                       // Binding lookup failed locally, so check the root
                       // scope (globals)
                       .or(self.globals.get_var_copy(bnd))
                       .ok_or_else(|| GcError::Load(bnd.clone()))
    }

    pub fn store(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        let update = self.curr_scope.update_var(var, ptr);
        if let Err(GcError::Store(var, ptr)) = update{
            self.globals.update_var(var, ptr)
        } else {
            update
        }
    }
}

pub fn init_gc() -> ScopeManager {
    let alloc_box = Rc::new(RefCell::new(AllocBox::new()));
    ScopeManager::new(alloc_box)
}

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

    use jsrs_common::ast::Exp;
    use js_types::js_var::JsType;
    use js_types::binding::Binding;

    use gc_error::GcError;
    use test_utils;

    #[test]
    fn test_pop_scope() {
        let alloc_box = test_utils::make_alloc_box();
        let mut mgr = ScopeManager::new(alloc_box);
        mgr.push_scope(&Exp::Undefined);
        assert!(mgr.curr_scope.parent.is_some());
        mgr.pop_scope(false).unwrap();
        assert!(mgr.curr_scope.parent.is_none());
    }

    #[test]
    fn test_pop_scope_fail() {
        let alloc_box = test_utils::make_alloc_box();
        let mut mgr = ScopeManager::new(alloc_box);
        let res = mgr.pop_scope(false);
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::Scope)));
    }

    #[test]
    fn test_alloc() {
        let alloc_box = test_utils::make_alloc_box();
        let mut mgr = ScopeManager::new(alloc_box);
        mgr.alloc(test_utils::make_num(1.), None).unwrap();
        mgr.push_scope(&Exp::Undefined);
        mgr.alloc(test_utils::make_num(2.), None).unwrap();
        assert!(mgr.alloc_box.borrow().is_empty());
    }

    #[test]
    fn test_load() {
        let alloc_box = test_utils::make_alloc_box();
        let mut mgr = ScopeManager::new(alloc_box);
        let x = test_utils::make_num(1.);
        let x_bnd = x.binding.clone();
        mgr.alloc(x, None).unwrap();
        let load = mgr.load(&x_bnd);
        assert!(load.is_ok());
        let load = load.unwrap();
        match load.0.t {
            JsType::JsNum(n) => assert!(f64::abs(n - 1.) < 0.0001),
            _ => unreachable!(),
        }
        assert!(load.1.is_none());
    }

    #[test]
    fn test_load_fail() {
        let alloc_box = test_utils::make_alloc_box();
        let mgr = ScopeManager::new(alloc_box);
        let bnd = Binding::anon();
        let res = mgr.load(&bnd);
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::Load(_))));
        if let Err(GcError::Load(res_bnd)) = res {
            assert_eq!(bnd, res_bnd);
        }
    }

    #[test]
    fn test_store() {
        let alloc_box = test_utils::make_alloc_box();
        let mut mgr = ScopeManager::new(alloc_box,);
        mgr.push_scope(&Exp::Undefined);
        let x = test_utils::make_num(1.);
        let x_bnd = x.binding.clone();
        mgr.alloc(x, None).unwrap();

        let mut test_num = test_utils::make_num(2.);
        test_num.binding = x_bnd;
        assert!(mgr.store(test_num, None).is_ok());
    }

}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

pub mod metadata;
mod utility;

use metadata::metadata;

pub struct Stream<'a> {
  pub meta_data: Vec<metadata::Block<'a>>,
  //frames: Vec<u32>
}

named!(stream <&[u8], Stream>,
  chain!(
    blocks: metadata,
    || {
      Stream {
        meta_data: blocks,
      }
    }
  )
);
<commit_msg>Change meta_data in Stream type to metadata<commit_after>#[macro_use]
extern crate nom;

pub mod metadata;
mod utility;

use metadata::metadata;

pub struct Stream<'a> {
  pub metadata: Vec<metadata::Block<'a>>,
  //frames: Vec<u32>
}

named!(stream <&[u8], Stream>,
  chain!(
    blocks: metadata,
    || {
      Stream {
        metadata: blocks,
      }
    }
  )
);
<|endoftext|>


<commit_before>/*!
linear algebra operations for [nalgebra][1] matrices using [LAPACK][2].

Functions to compute the singular value decomposition (SVD) and eigensystem are
implemented.

# Examples

```rust
extern crate nalgebra_lapack;
extern crate nalgebra as na;

use nalgebra_lapack::{HasSVD, HasEigensystem};

fn main() {
    // Create an input matrix
    let m = na::DMat::from_row_vec(3,5,&[
        -1.01,   0.86,  -4.60,   3.31,  -4.81,
         3.98,   0.53,  -7.04,   5.29,   3.55,
         3.30,   8.26,  -3.89,   8.20,  -1.51]);

    // Now perform SVD
    let (u,s,vt) = m.svd().unwrap();
    println!("u {:?}",u);
    println!("s {:?}",s);
    println!("vt {:?}",vt);

    // Create an input matrix
    let m = na::DMat::from_row_vec(2,2,&[
        2.0, 1.0,
        1.0, 2.0]);

    // Now get the eigensystem
    let (vals, vecs) = m.eigensystem().unwrap();
    println!("eigenvalues {:?}",vals);
    println!("eigenvectors {:?}",vecs);

}
```

[1]: https://crates.io/crates/nalgebra
[2]: https://crates.io/crates/lapack
*/

extern crate nalgebra as na;
extern crate lapack;
extern crate num;

use std::error::Error;
use std::fmt::{self, Display};
use num::complex::Complex;

use na::{DMat, DVec, Iterable};

#[derive(Debug)]
pub struct NalgebraLapackError {
  pub desc: String,
}

pub type NalgebraLapackResult<T> = Result<T, NalgebraLapackError>;

impl Error for NalgebraLapackError {
  fn description(&self) -> &str { &self.desc }
}

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

impl From<String> for NalgebraLapackError {
  fn from(err: String) -> NalgebraLapackError {
    NalgebraLapackError { desc: format!(
                  "String ({})",
                  err
                  ),
    }
  }
}

macro_rules! eigensystem_impl(
    ($t: ty, $lapack_func: path) => (
        impl HasEigensystem<Complex<$t>> for DMat<$t> {
            fn eigensystem(mut self) -> NalgebraLapackResult<(DVec<Complex<$t>>, DMat<Complex<$t>>)> {
                let jobvl = b'N';
                let jobvr = b'V';

                if self.ncols() != self.nrows() {
                    return Err(NalgebraLapackError { desc: "argument to eigen must be square.".to_owned() } );
                }
                let n = self.ncols();

                let lda = n;
                let ldvl = 1;
                let ldvr = n;

                let mut wr: DVec<$t> = DVec::from_elem( n, 0.0);
                let mut wi: DVec<$t> = DVec::from_elem( n, 0.0);

                let mut vl: DVec<$t> = DVec::from_elem( ldvl*ldvl, 0.0);
                let mut vr: DVec<$t> = DVec::from_elem( n*n, 0.0);

                let mut work = vec![0.0];
                let mut lwork = -1;
                let mut info = 0;

                $lapack_func(jobvl, jobvr, n, self.as_mut_vec(), lda, wr.as_mut_slice(),
                    wi.as_mut_slice(), vl.as_mut_slice(), ldvl, vr.as_mut_slice(), ldvr,
                    &mut work, lwork, &mut info);

                if info < 0 {
                  return Err(NalgebraLapackError { desc: "illegal argument in eigensystem.".to_owned() } );
                }

                lwork = work[0] as isize;
                let mut work = vec![0.0; lwork as usize];

                $lapack_func(jobvl, jobvr, n, self.as_mut_vec(), lda, wr.as_mut_slice(),
                    wi.as_mut_slice(), vl.as_mut_slice(), ldvl, vr.as_mut_slice(), ldvr,
                    &mut work, lwork, &mut info);

                if info < 0 {
                    return Err(NalgebraLapackError { desc: format!(
                                  "illegal argument {} to eigensystem()",
                                  -info
                                  ) } );
                }
                if info > 0 {
                    // TODO: should figure out how to return the correct eigenvalues.
                    return Err(NalgebraLapackError { desc: format!(
                                  "The QR algorithm failed to compute all the eigenvalues. {} were computed.",
                                  -info
                                  ) } );
                }

                let x: Vec<Complex<$t>> = wr.iter().zip(wi.iter()).map( |(r,i)| {Complex{re:*r,im:*i}} ).collect();
                let eigen_values = DVec{at:x};
                let mut result: Vec<Complex<$t>> = Vec::with_capacity(n*n);
                for i in (0..n) {
                    let mut j = 0;
                    while j < n {
                        if eigen_values[j].im == 0.0 {
                            result.push( Complex{ re: vr[i+j*ldvr], im: 0.0 });
                            j += 1;
                        } else {
                            result.push( Complex{ re: vr[i+j*ldvr], im: vr[i+(j+1)*ldvr] });
                            result.push( Complex{ re: vr[i+j*ldvr], im: -vr[i+(j+1)*ldvr] });
                            j += 2;
                        }
                    }
                }
                let right_eigen_vectors = DMat::from_row_vec(n,n,&result);
                Ok((eigen_values,right_eigen_vectors))
            }
        }
    );
);

pub trait HasEigensystem<T> {
    /// `eigensystem` computes eigenvalues and right eigenvectors
    ///
    /// Because the input matrix may be overwritten or destroyed, it is consumed.
    ///
    /// # Returns
    ///
    /// * `eigen_values` - The eigenvalues, normalized to have Euclidean norm equal to 1 and largest component real.
    /// * `right_eigen_vectors` - The right eigenvectors. They are contained as columns of this matrix.
    fn eigensystem(mut self) -> NalgebraLapackResult<(DVec<T>, DMat<T>)>;
}

macro_rules! eigensystem_complex_impl(
    ($t: ty, $lapack_func: path) => (
        impl HasEigensystem<Complex<$t>> for DMat<Complex<$t>> {
            fn eigensystem(mut self) -> NalgebraLapackResult<(DVec<Complex<$t>>, DMat<Complex<$t>>)> {
                let jobvl = b'N';
                let jobvr = b'V';

                if self.ncols() != self.nrows() {
                    return Err(NalgebraLapackError { desc: "argument to eigen must be square.".to_owned() } );
                }
                let n = self.ncols();

                let lda = n;
                let ldvl = 1;
                let ldvr = n;

                let mut w: DVec<Complex<$t>> = DVec::from_elem( n, Complex{re:0.0, im:0.0});

                let mut vl: DVec<Complex<$t>> = DVec::from_elem( ldvl*ldvl, Complex{re:0.0, im:0.0});
                let mut vr: DVec<Complex<$t>> = DVec::from_elem( n*n, Complex{re:0.0, im:0.0});

                let mut work = vec![Complex{re:0.0, im:0.0}];
                let mut lwork = -1;
                let mut rwork: Vec<$t> = vec![0.0; (2*n) as usize];

                let mut info = 0;

                $lapack_func(jobvl, jobvr, n, self.as_mut_vec(), lda, w.as_mut_slice(),
                    vl.as_mut_slice(), ldvl, vr.as_mut_slice(), ldvr,
                    & mut work, lwork, & mut rwork, &mut info);

                if info < 0 {
                  return Err(NalgebraLapackError { desc: "illegal argument in eigensystem.".to_owned() } );
                }

                lwork = work[0].re as isize;
                let mut work = vec![Complex{re:0.0, im:0.0}; lwork as usize];

                $lapack_func(jobvl, jobvr, n, self.as_mut_vec(), lda, w.as_mut_slice(),
                    vl.as_mut_slice(), ldvl, vr.as_mut_slice(), ldvr,
                    & mut work, lwork, & mut rwork, &mut info);

                if info < 0 {
                    return Err(NalgebraLapackError { desc: format!(
                                  "illegal argument {} to eigensystem()",
                                  -info
                                  ) } );
                }
                if info > 0 {
                    // TODO: should figure out how to return the correct eigenvalues.
                    return Err(NalgebraLapackError { desc: format!(
                                  "The QR algorithm failed to compute all the eigenvalues. {} were computed.",
                                  -info
                                  ) } );
                }

                let eigen_values = w;
                let right_eigen_vectors = DMat::from_row_vec(n,n,&vr.at);
                Ok((eigen_values,right_eigen_vectors))
            }
        }
    );
);

pub trait HasSVD<T,U> {
    /// `svd` computes the singular value decomposition (SVD). Returns full
    /// matrices.
    ///
    /// Because the input matrix may be overwritten or destroyed, it is consumed.
    ///
    /// # Returns
    ///
    /// * `u` - The left-singular vectors.
    /// * `s` - The singular values.
    /// * `vt` - The right-singular vectors.
    fn svd(mut self) -> NalgebraLapackResult<(DMat<T>, DVec<U>, DMat<T>)>;
}

macro_rules! svd_impl(
    ($t: ty, $lapack_func: path) => (
        impl HasSVD<$t,$t> for DMat<$t> {
            fn svd(mut self) -> NalgebraLapackResult<(DMat<$t>, DVec<$t>, DMat<$t>)> {
                let m = self.nrows();
                let n = self.ncols();

                let jobu = b'A';
                let jobvt = b'A';

                let lda = m;
                let min_mn = if m <= n { m } else {n};
                let mut s: DVec<$t> = DVec::from_elem( min_mn, 0.0);
                let ldu = m;
                let mut u: DMat<$t> = DMat::new_zeros(ldu, m);
                let ldvt = n;
                let mut vt: DMat<$t> = DMat::new_zeros(ldvt, n);
                let mut work = vec![0.0];
                let mut lwork = -1;
                let mut info = 0;

                $lapack_func(jobu, jobvt, m, n, self.as_mut_vec(), lda, &mut s.as_mut_slice(),
                               u.as_mut_vec(), ldu, vt.as_mut_vec(),
                               ldvt, &mut work, lwork, &mut info);
                if info < 0 {
                  return Err(NalgebraLapackError { desc: "illegal argument to svd.".to_owned() } );
                }

                lwork = work[0] as isize;
                work = vec![0.0; lwork as usize];

                $lapack_func(jobu, jobvt, m, n, self.as_mut_vec(), lda, &mut s.as_mut_slice(),
                               u.as_mut_vec(), ldu, vt.as_mut_vec(), ldvt, &mut work,
                               lwork, &mut info);

                if info < 0 {
                    return Err(NalgebraLapackError { desc: format!(
                                  "illegal argument {} in svd",
                                  -info
                                  ) } );
                }
                if info > 0 {
                    return Err(NalgebraLapackError { desc: format!(
                                  "{} superdiagonals did not converge.",
                                  info
                                  ) } );
                }

                Ok((u, s, vt))
            }
        }
    );
);

macro_rules! svd_complex_impl(
    ($t: ty, $lapack_func: path) => (
        impl HasSVD<Complex<$t>,$t> for DMat<Complex<$t>> {
            fn svd(mut self) -> NalgebraLapackResult<(DMat<Complex<$t>>, DVec<$t>, DMat<Complex<$t>>)> {
                let m = self.nrows();
                let n = self.ncols();

                let jobu = b'A';
                let jobvt = b'A';

                let lda = m;
                let min_mn = if m <= n { m } else {n};
                let mut s: DVec<$t> = DVec::from_elem( min_mn, 0.0);
                let ldu = m;
                let mut u: DMat<Complex<$t>> = DMat::new_zeros(ldu, m);
                let ldvt = n;
                let mut vt: DMat<Complex<$t>> = DMat::new_zeros(ldvt, n);
                let mut work: Vec<Complex<$t>> = vec![Complex{re:0.0, im:0.0}];
                let mut lwork = -1;
                let mut rwork: Vec<$t> = vec![0.0; (5*min_mn as usize)];
                let mut info = 0;

                $lapack_func(jobu, jobvt, m, n, self.as_mut_vec(), lda, &mut s.as_mut_slice(),
                             u.as_mut_vec(), ldu, vt.as_mut_vec(), ldvt, &mut work,
                             lwork, &mut rwork, &mut info);

                if info < 0 {
                  return Err(NalgebraLapackError { desc: "illegal argument to svd.".to_owned() } );
                }

                lwork = work[0].re as isize;
                let mut work: Vec<Complex<$t>> = vec![Complex{re:0.0, im:0.0}; lwork as usize];

                $lapack_func(jobu, jobvt, m, n, self.as_mut_vec(), lda, &mut s.as_mut_slice(),
                             u.as_mut_vec(), ldu, vt.as_mut_vec(), ldvt, &mut work,
                             lwork, &mut rwork, &mut info);

                if info < 0 {
                    return Err(NalgebraLapackError { desc: format!(
                                  "illegal argument {} in svd",
                                  -info
                                  ) } );
                }
                if info > 0 {
                    return Err(NalgebraLapackError { desc: format!(
                                  "{} superdiagonals did not converge.",
                                  info
                                  ) } );
                }

                Ok((u, s, vt))
            }
        }
    );
);

eigensystem_impl!(f32, lapack::sgeev);
eigensystem_impl!(f64, lapack::dgeev);
eigensystem_complex_impl!(f32, lapack::cgeev);
eigensystem_complex_impl!(f64, lapack::zgeev);

svd_impl!(f32, lapack::sgesvd);
svd_impl!(f64, lapack::dgesvd);
svd_complex_impl!(f32, lapack::cgesvd);
svd_complex_impl!(f64, lapack::zgesvd);
<commit_msg>fix compiler warning<commit_after>/*!
linear algebra operations for [nalgebra][1] matrices using [LAPACK][2].

Functions to compute the singular value decomposition (SVD) and eigensystem are
implemented.

# Examples

```rust
extern crate nalgebra_lapack;
extern crate nalgebra as na;

use nalgebra_lapack::{HasSVD, HasEigensystem};

fn main() {
    // Create an input matrix
    let m = na::DMat::from_row_vec(3,5,&[
        -1.01,   0.86,  -4.60,   3.31,  -4.81,
         3.98,   0.53,  -7.04,   5.29,   3.55,
         3.30,   8.26,  -3.89,   8.20,  -1.51]);

    // Now perform SVD
    let (u,s,vt) = m.svd().unwrap();
    println!("u {:?}",u);
    println!("s {:?}",s);
    println!("vt {:?}",vt);

    // Create an input matrix
    let m = na::DMat::from_row_vec(2,2,&[
        2.0, 1.0,
        1.0, 2.0]);

    // Now get the eigensystem
    let (vals, vecs) = m.eigensystem().unwrap();
    println!("eigenvalues {:?}",vals);
    println!("eigenvectors {:?}",vecs);

}
```

[1]: https://crates.io/crates/nalgebra
[2]: https://crates.io/crates/lapack
*/

extern crate nalgebra as na;
extern crate lapack;
extern crate num;

use std::error::Error;
use std::fmt::{self, Display};
use num::complex::Complex;

use na::{DMat, DVec, Iterable};

#[derive(Debug)]
pub struct NalgebraLapackError {
  pub desc: String,
}

pub type NalgebraLapackResult<T> = Result<T, NalgebraLapackError>;

impl Error for NalgebraLapackError {
  fn description(&self) -> &str { &self.desc }
}

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

impl From<String> for NalgebraLapackError {
  fn from(err: String) -> NalgebraLapackError {
    NalgebraLapackError { desc: format!(
                  "String ({})",
                  err
                  ),
    }
  }
}

macro_rules! eigensystem_impl(
    ($t: ty, $lapack_func: path) => (
        impl HasEigensystem<Complex<$t>> for DMat<$t> {
            fn eigensystem(mut self) -> NalgebraLapackResult<(DVec<Complex<$t>>, DMat<Complex<$t>>)> {
                let jobvl = b'N';
                let jobvr = b'V';

                if self.ncols() != self.nrows() {
                    return Err(NalgebraLapackError { desc: "argument to eigen must be square.".to_owned() } );
                }
                let n = self.ncols();

                let lda = n;
                let ldvl = 1;
                let ldvr = n;

                let mut wr: DVec<$t> = DVec::from_elem( n, 0.0);
                let mut wi: DVec<$t> = DVec::from_elem( n, 0.0);

                let mut vl: DVec<$t> = DVec::from_elem( ldvl*ldvl, 0.0);
                let mut vr: DVec<$t> = DVec::from_elem( n*n, 0.0);

                let mut work = vec![0.0];
                let mut lwork = -1;
                let mut info = 0;

                $lapack_func(jobvl, jobvr, n, self.as_mut_vec(), lda, wr.as_mut_slice(),
                    wi.as_mut_slice(), vl.as_mut_slice(), ldvl, vr.as_mut_slice(), ldvr,
                    &mut work, lwork, &mut info);

                if info < 0 {
                  return Err(NalgebraLapackError { desc: "illegal argument in eigensystem.".to_owned() } );
                }

                lwork = work[0] as isize;
                let mut work = vec![0.0; lwork as usize];

                $lapack_func(jobvl, jobvr, n, self.as_mut_vec(), lda, wr.as_mut_slice(),
                    wi.as_mut_slice(), vl.as_mut_slice(), ldvl, vr.as_mut_slice(), ldvr,
                    &mut work, lwork, &mut info);

                if info < 0 {
                    return Err(NalgebraLapackError { desc: format!(
                                  "illegal argument {} to eigensystem()",
                                  -info
                                  ) } );
                }
                if info > 0 {
                    // TODO: should figure out how to return the correct eigenvalues.
                    return Err(NalgebraLapackError { desc: format!(
                                  "The QR algorithm failed to compute all the eigenvalues. {} were computed.",
                                  -info
                                  ) } );
                }

                let x: Vec<Complex<$t>> = wr.iter().zip(wi.iter()).map( |(r,i)| {Complex{re:*r,im:*i}} ).collect();
                let eigen_values = DVec{at:x};
                let mut result: Vec<Complex<$t>> = Vec::with_capacity(n*n);
                for i in 0..n {
                    let mut j = 0;
                    while j < n {
                        if eigen_values[j].im == 0.0 {
                            result.push( Complex{ re: vr[i+j*ldvr], im: 0.0 });
                            j += 1;
                        } else {
                            result.push( Complex{ re: vr[i+j*ldvr], im: vr[i+(j+1)*ldvr] });
                            result.push( Complex{ re: vr[i+j*ldvr], im: -vr[i+(j+1)*ldvr] });
                            j += 2;
                        }
                    }
                }
                let right_eigen_vectors = DMat::from_row_vec(n,n,&result);
                Ok((eigen_values,right_eigen_vectors))
            }
        }
    );
);

pub trait HasEigensystem<T> {
    /// `eigensystem` computes eigenvalues and right eigenvectors
    ///
    /// Because the input matrix may be overwritten or destroyed, it is consumed.
    ///
    /// # Returns
    ///
    /// * `eigen_values` - The eigenvalues, normalized to have Euclidean norm equal to 1 and largest component real.
    /// * `right_eigen_vectors` - The right eigenvectors. They are contained as columns of this matrix.
    fn eigensystem(mut self) -> NalgebraLapackResult<(DVec<T>, DMat<T>)>;
}

macro_rules! eigensystem_complex_impl(
    ($t: ty, $lapack_func: path) => (
        impl HasEigensystem<Complex<$t>> for DMat<Complex<$t>> {
            fn eigensystem(mut self) -> NalgebraLapackResult<(DVec<Complex<$t>>, DMat<Complex<$t>>)> {
                let jobvl = b'N';
                let jobvr = b'V';

                if self.ncols() != self.nrows() {
                    return Err(NalgebraLapackError { desc: "argument to eigen must be square.".to_owned() } );
                }
                let n = self.ncols();

                let lda = n;
                let ldvl = 1;
                let ldvr = n;

                let mut w: DVec<Complex<$t>> = DVec::from_elem( n, Complex{re:0.0, im:0.0});

                let mut vl: DVec<Complex<$t>> = DVec::from_elem( ldvl*ldvl, Complex{re:0.0, im:0.0});
                let mut vr: DVec<Complex<$t>> = DVec::from_elem( n*n, Complex{re:0.0, im:0.0});

                let mut work = vec![Complex{re:0.0, im:0.0}];
                let mut lwork = -1;
                let mut rwork: Vec<$t> = vec![0.0; (2*n) as usize];

                let mut info = 0;

                $lapack_func(jobvl, jobvr, n, self.as_mut_vec(), lda, w.as_mut_slice(),
                    vl.as_mut_slice(), ldvl, vr.as_mut_slice(), ldvr,
                    & mut work, lwork, & mut rwork, &mut info);

                if info < 0 {
                  return Err(NalgebraLapackError { desc: "illegal argument in eigensystem.".to_owned() } );
                }

                lwork = work[0].re as isize;
                let mut work = vec![Complex{re:0.0, im:0.0}; lwork as usize];

                $lapack_func(jobvl, jobvr, n, self.as_mut_vec(), lda, w.as_mut_slice(),
                    vl.as_mut_slice(), ldvl, vr.as_mut_slice(), ldvr,
                    & mut work, lwork, & mut rwork, &mut info);

                if info < 0 {
                    return Err(NalgebraLapackError { desc: format!(
                                  "illegal argument {} to eigensystem()",
                                  -info
                                  ) } );
                }
                if info > 0 {
                    // TODO: should figure out how to return the correct eigenvalues.
                    return Err(NalgebraLapackError { desc: format!(
                                  "The QR algorithm failed to compute all the eigenvalues. {} were computed.",
                                  -info
                                  ) } );
                }

                let eigen_values = w;
                let right_eigen_vectors = DMat::from_row_vec(n,n,&vr.at);
                Ok((eigen_values,right_eigen_vectors))
            }
        }
    );
);

pub trait HasSVD<T,U> {
    /// `svd` computes the singular value decomposition (SVD). Returns full
    /// matrices.
    ///
    /// Because the input matrix may be overwritten or destroyed, it is consumed.
    ///
    /// # Returns
    ///
    /// * `u` - The left-singular vectors.
    /// * `s` - The singular values.
    /// * `vt` - The right-singular vectors.
    fn svd(mut self) -> NalgebraLapackResult<(DMat<T>, DVec<U>, DMat<T>)>;
}

macro_rules! svd_impl(
    ($t: ty, $lapack_func: path) => (
        impl HasSVD<$t,$t> for DMat<$t> {
            fn svd(mut self) -> NalgebraLapackResult<(DMat<$t>, DVec<$t>, DMat<$t>)> {
                let m = self.nrows();
                let n = self.ncols();

                let jobu = b'A';
                let jobvt = b'A';

                let lda = m;
                let min_mn = if m <= n { m } else {n};
                let mut s: DVec<$t> = DVec::from_elem( min_mn, 0.0);
                let ldu = m;
                let mut u: DMat<$t> = DMat::new_zeros(ldu, m);
                let ldvt = n;
                let mut vt: DMat<$t> = DMat::new_zeros(ldvt, n);
                let mut work = vec![0.0];
                let mut lwork = -1;
                let mut info = 0;

                $lapack_func(jobu, jobvt, m, n, self.as_mut_vec(), lda, &mut s.as_mut_slice(),
                               u.as_mut_vec(), ldu, vt.as_mut_vec(),
                               ldvt, &mut work, lwork, &mut info);
                if info < 0 {
                  return Err(NalgebraLapackError { desc: "illegal argument to svd.".to_owned() } );
                }

                lwork = work[0] as isize;
                work = vec![0.0; lwork as usize];

                $lapack_func(jobu, jobvt, m, n, self.as_mut_vec(), lda, &mut s.as_mut_slice(),
                               u.as_mut_vec(), ldu, vt.as_mut_vec(), ldvt, &mut work,
                               lwork, &mut info);

                if info < 0 {
                    return Err(NalgebraLapackError { desc: format!(
                                  "illegal argument {} in svd",
                                  -info
                                  ) } );
                }
                if info > 0 {
                    return Err(NalgebraLapackError { desc: format!(
                                  "{} superdiagonals did not converge.",
                                  info
                                  ) } );
                }

                Ok((u, s, vt))
            }
        }
    );
);

macro_rules! svd_complex_impl(
    ($t: ty, $lapack_func: path) => (
        impl HasSVD<Complex<$t>,$t> for DMat<Complex<$t>> {
            fn svd(mut self) -> NalgebraLapackResult<(DMat<Complex<$t>>, DVec<$t>, DMat<Complex<$t>>)> {
                let m = self.nrows();
                let n = self.ncols();

                let jobu = b'A';
                let jobvt = b'A';

                let lda = m;
                let min_mn = if m <= n { m } else {n};
                let mut s: DVec<$t> = DVec::from_elem( min_mn, 0.0);
                let ldu = m;
                let mut u: DMat<Complex<$t>> = DMat::new_zeros(ldu, m);
                let ldvt = n;
                let mut vt: DMat<Complex<$t>> = DMat::new_zeros(ldvt, n);
                let mut work: Vec<Complex<$t>> = vec![Complex{re:0.0, im:0.0}];
                let mut lwork = -1;
                let mut rwork: Vec<$t> = vec![0.0; (5*min_mn as usize)];
                let mut info = 0;

                $lapack_func(jobu, jobvt, m, n, self.as_mut_vec(), lda, &mut s.as_mut_slice(),
                             u.as_mut_vec(), ldu, vt.as_mut_vec(), ldvt, &mut work,
                             lwork, &mut rwork, &mut info);

                if info < 0 {
                  return Err(NalgebraLapackError { desc: "illegal argument to svd.".to_owned() } );
                }

                lwork = work[0].re as isize;
                let mut work: Vec<Complex<$t>> = vec![Complex{re:0.0, im:0.0}; lwork as usize];

                $lapack_func(jobu, jobvt, m, n, self.as_mut_vec(), lda, &mut s.as_mut_slice(),
                             u.as_mut_vec(), ldu, vt.as_mut_vec(), ldvt, &mut work,
                             lwork, &mut rwork, &mut info);

                if info < 0 {
                    return Err(NalgebraLapackError { desc: format!(
                                  "illegal argument {} in svd",
                                  -info
                                  ) } );
                }
                if info > 0 {
                    return Err(NalgebraLapackError { desc: format!(
                                  "{} superdiagonals did not converge.",
                                  info
                                  ) } );
                }

                Ok((u, s, vt))
            }
        }
    );
);

eigensystem_impl!(f32, lapack::sgeev);
eigensystem_impl!(f64, lapack::dgeev);
eigensystem_complex_impl!(f32, lapack::cgeev);
eigensystem_complex_impl!(f64, lapack::zgeev);

svd_impl!(f32, lapack::sgesvd);
svd_impl!(f64, lapack::dgesvd);
svd_complex_impl!(f32, lapack::cgesvd);
svd_complex_impl!(f64, lapack::zgesvd);
<|endoftext|>


<commit_before>#![feature(zero_one)]
#![feature(const_fn)]
#![no_std]

#[cfg(test)]
mod tests;

use core::mem::size_of;

#[derive(Debug, Clone, Copy)]
pub struct BitField<T: Number>(T);

impl<T> BitField<T>
    where T: Number
{
    pub const fn new(value: T) -> BitField<T> {
        BitField(value)
    }

    pub fn get_bit(&self, bit: usize) -> bool {
        assert!(bit < self.length());
        self.get_range(bit..(bit + 1)) == T::one()
    }

    pub fn get_range(&self, range: Range<usize>) -> T {
        assert!(range.start < self.length());
        assert!(range.end <= self.length());
        assert!(range.start < range.end);

        // shift away high bits
        let bits = self.0 << (self.length() - range.end) >> (self.length() - range.end);

        // shift away low bits
        bits >> range.start
    }

    pub fn set_bit(&mut self, bit: usize) {
        assert!(bit < self.length());
        self.0 |= T::one() << bit;
    }

    pub fn reset_bit(&mut self, bit: usize) {
        assert!(bit < self.length());
        self.0 &= !(T::one() << bit);
    }

    pub fn set_range(&mut self, range: Range<usize>, value: T) {
        assert!(range.start < self.length());
        assert!(range.end <= self.length());
        assert!(range.start < range.end);
        assert!(value << (self.length() - (range.end - range.start)) >> (self.length() - (range.end - range.start)) ==
                value,
                "value too big");

        let bitmask: T = !(!T::zero() << (self.length() - range.end) >> (self.length() - range.end) >> range.start <<
                           range.start);

        let bits = self.0 & bitmask;
        // set bits
        self.0 = bits | (value << range.start);
    }

    fn length(&self) -> usize {
        size_of::<T>() * 8
    }
}

use core::ops::{Range, Shl, Shr, BitAnd, BitOr, BitOrAssign, BitAndAssign, Not};
use core::num::{Zero, One};
use core::fmt::Debug;

pub trait Number: Debug + Copy + Eq + Zero + One +
    Not<Output=Self> + Shl<usize, Output=Self> + Shr<usize, Output=Self> +
    BitAnd<Self, Output=Self> + BitOr<Self, Output=Self>  + BitAndAssign + BitOrAssign {}

impl Number for u8 {}
impl Number for u16 {}
impl Number for u32 {}
impl Number for u64 {}
impl Number for usize {}
<commit_msg>Use u8 instead of usize for indexes<commit_after>#![feature(zero_one)]
#![feature(const_fn)]
#![no_std]

#[cfg(test)]
mod tests;

use core::mem::size_of;

#[derive(Debug, Clone, Copy)]
pub struct BitField<T: Number>(T);

impl<T> BitField<T>
    where T: Number
{
    pub const fn new(value: T) -> BitField<T> {
        BitField(value)
    }

    pub fn get_bit(&self, bit: u8) -> bool {
        assert!(bit < self.length());
        self.get_range(bit..(bit + 1)) == T::one()
    }

    pub fn get_range(&self, range: Range<u8>) -> T {
        assert!(range.start < self.length());
        assert!(range.end <= self.length());
        assert!(range.start < range.end);

        // shift away high bits
        let bits = self.0 << (self.length() - range.end) >> (self.length() - range.end);

        // shift away low bits
        bits >> range.start
    }

    pub fn set_bit(&mut self, bit: u8) {
        assert!(bit < self.length());
        self.0 |= T::one() << bit;
    }

    pub fn reset_bit(&mut self, bit: u8) {
        assert!(bit < self.length());
        self.0 &= !(T::one() << bit);
    }

    pub fn set_range(&mut self, range: Range<u8>, value: T) {
        assert!(range.start < self.length());
        assert!(range.end <= self.length());
        assert!(range.start < range.end);
        assert!(value << (self.length() - (range.end - range.start)) >> (self.length() - (range.end - range.start)) ==
                value,
                "value too big");

        let bitmask: T = !(!T::zero() << (self.length() - range.end) >> (self.length() - range.end) >> range.start <<
                           range.start);

        let bits = self.0 & bitmask;
        // set bits
        self.0 = bits | (value << range.start);
    }

    fn length(&self) -> u8 {
        size_of::<T>() * 8
    }
}

use core::ops::{Range, Shl, Shr, BitAnd, BitOr, BitOrAssign, BitAndAssign, Not};
use core::num::{Zero, One};
use core::fmt::Debug;

pub trait Number: Debug + Copy + Eq + Zero + One +
    Not<Output=Self> + Shl<u8, Output=Self> + Shr<u8, Output=Self> +
    BitAnd<Self, Output=Self> + BitOr<Self, Output=Self>  + BitAndAssign + BitOrAssign {}

impl Number for u8 {}
impl Number for u16 {}
impl Number for u32 {}
impl Number for u64 {}
impl Number for usize {}
<|endoftext|>


<commit_before>#![feature(drop_types_in_const)]

#![allow(unknown_lints)]

#[cfg(feature = "toml")]
extern crate toml;

#[cfg(feature = "json")]
extern crate serde_json;

mod value;
mod source;
mod file;
mod env;
mod config;

use std::error::Error;
use std::sync::{Once, ONCE_INIT};
use std::borrow::Cow;

pub use source::{Source, SourceBuilder};
pub use file::{File, FileFormat};
pub use env::Environment;

pub use value::Value;

pub use config::Config;

// Global configuration
static mut CONFIG: Option<Config<'static>> = None;
static CONFIG_INIT: Once = ONCE_INIT;

// Get the global configuration instance
pub fn global() -> &'static mut Config<'static> {
    unsafe {
        CONFIG_INIT.call_once(|| {
            CONFIG = Some(Default::default());
        });

        CONFIG.as_mut().unwrap()
    }
}

pub fn merge<T>(source: T) -> Result<(), Box<Error>>
    where T: SourceBuilder
{
    global().merge(source)
}

pub fn set_default<T>(key: &str, value: T) -> Result<(), Box<Error>>
    where T: Into<Value<'static>>
{
    global().set_default(key, value)
}

pub fn set<T>(key: &str, value: T) -> Result<(), Box<Error>>
    where T: Into<Value<'static>>
{
    global().set(key, value)
}

pub fn get<'a>(key: &str) -> Option<Cow<'a, Value>> {
    global().get(key)
}

pub fn get_str<'a>(key: &str) -> Option<Cow<'a, str>> {
    global().get_str(key)
}

pub fn get_int(key: &str) -> Option<i64> {
    global().get_int(key)
}

pub fn get_float(key: &str) -> Option<f64> {
    global().get_float(key)
}

pub fn get_bool(key: &str) -> Option<bool> {
    global().get_bool(key)
}
<commit_msg>Add back RwLock<commit_after>#![feature(drop_types_in_const)]

#![allow(unknown_lints)]

#[cfg(feature = "toml")]
extern crate toml;

#[cfg(feature = "json")]
extern crate serde_json;

mod value;
mod source;
mod file;
mod env;
mod config;

use std::error::Error;
use std::sync::{Once, ONCE_INIT, RwLock};
use std::borrow::Cow;

pub use source::{Source, SourceBuilder};
pub use file::{File, FileFormat};
pub use env::Environment;

pub use value::Value;

pub use config::Config;

// Global configuration
static mut CONFIG: Option<RwLock<Config<'static>>> = None;
static CONFIG_INIT: Once = ONCE_INIT;

// Get the global configuration instance
pub fn global() -> &'static mut RwLock<Config<'static>> {
    unsafe {
        CONFIG_INIT.call_once(|| {
            CONFIG = Some(Default::default());
        });

        CONFIG.as_mut().unwrap()
    }
}

pub fn merge<T>(source: T) -> Result<(), Box<Error>>
    where T: SourceBuilder
{
    global().write().unwrap().merge(source)
}

pub fn set_default<T>(key: &str, value: T) -> Result<(), Box<Error>>
    where T: Into<Value<'static>>
{
    global().write().unwrap().set_default(key, value)
}

pub fn set<T>(key: &str, value: T) -> Result<(), Box<Error>>
    where T: Into<Value<'static>>
{
    global().write().unwrap().set(key, value)
}

pub fn get<'a>(key: &str) -> Option<Cow<'a, Value>> {
    // TODO(~): Should this panic! or return None with an error message?
    //          Make an issue if you think it should be an error message.
    let r = global().read().unwrap();

    let c = &*r;

    // TODO(@rust): Figure out how to not to use unsafe here
    unsafe {
        let c: &'static Config = std::mem::transmute(c);
        c.get(key)
    }
}

pub fn get_str<'a>(key: &str) -> Option<Cow<'a, str>> {
    let r = global().read().unwrap();

    unsafe {
        let c: &'static Config = std::mem::transmute(&*r);
        c.get_str(key)
    }
}

pub fn get_int(key: &str) -> Option<i64> {
    let r = global().read().unwrap();

    unsafe {
        let c: &'static Config = std::mem::transmute(&*r);
        c.get_int(key)
    }
}

pub fn get_float(key: &str) -> Option<f64> {
    let r = global().read().unwrap();

    unsafe {
        let c: &'static Config = std::mem::transmute(&*r);
        c.get_float(key)
    }
}

pub fn get_bool(key: &str) -> Option<bool> {
    let r = global().read().unwrap();

    unsafe {
        let c: &'static Config = std::mem::transmute(&*r);
        c.get_bool(key)
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::cell::RefCell;

thread_local!(static EVENT_LOOP: Option<RefCell<EventLoop>> = None);

fn with_current_event_loop<F, R>(f: F) -> R
    where F: FnOnce(&RefCell<EventLoop>) -> R {
        EVENT_LOOP.with(|maybe_event_loop| {
            match maybe_event_loop {
                &None => panic!("current thread has no event loop"),
                &Some(ref event_loop) => f(event_loop),
            }
        })
    }

pub type Error = Box<::std::error::Error>;
pub type Result<T> = ::std::result::Result<T, Error>;

pub struct Promise<T> {
    pub node : Box<PromiseNode<T>>,
}

impl <T> Promise <T> where T: 'static {
    pub fn then<F, G, R>(self, func: F, error_handler: G) -> Promise<R>
        where F: 'static + FnOnce(T) -> Result<R>,
              G: 'static + FnOnce(Error) -> Result<R>,
              R: 'static {
            let node : Box<PromiseNode<R>> = Box::new(TransformPromiseNode::new(self.node, func, error_handler));
            Promise { node: node }
        }

    pub fn wait(self) -> Result<T> {
        unimplemented!()
    }
}

pub trait Event {
    fn fire(&mut self);
}

pub trait PromiseNode<T> {
    /// Arms the given event when the promised value is ready.
    fn on_ready(&mut self, event : Box<Event>);

    fn set_self_pointer(&mut self) {}
    fn get(self: Box<Self>) -> Result<T>;
}

/// A PromiseNode that transforms the result of another PromiseNode through an application-provided
/// function (implements `then()`).
pub struct TransformPromiseNode<T, DepT, Func, ErrorFunc>
where Func: FnOnce(DepT) -> Result<T>, ErrorFunc: FnOnce(Error) -> Result<T> {
    dependency: Box<PromiseNode<DepT>>,
    func: Func,
    error_handler: ErrorFunc,
}

impl <T, DepT, Func, ErrorFunc> TransformPromiseNode<T, DepT, Func, ErrorFunc>
where Func: FnOnce(DepT) -> Result<T>, ErrorFunc: FnOnce(Error) -> Result<T> {
    fn new(dependency: Box<PromiseNode<DepT>>, func: Func, error_handler: ErrorFunc)
           -> TransformPromiseNode<T, DepT, Func, ErrorFunc> {
        TransformPromiseNode { dependency : dependency,
                               func: func, error_handler: error_handler }
    }
}

impl <T, DepT, Func, ErrorFunc> PromiseNode<T> for TransformPromiseNode<T, DepT, Func, ErrorFunc>
where Func: FnOnce(DepT) -> Result<T>, ErrorFunc: FnOnce(Error) -> Result<T> {
    fn on_ready(&mut self, event: Box<Event>) {
        self.dependency.on_ready(event);
    }
    fn get(self: Box<Self>) -> Result<T> {
        let tmp = *self;
        let TransformPromiseNode {dependency, func, error_handler} = tmp;
        match dependency.get() {
            Ok(value) => {
                func(value)
            }
            Err(e) => {
                error_handler(e)
            }
        }
    }
}

/// A promise that has already been resolved to an immediate value or error.
pub struct ImmediatePromiseNode<T> {
    result: Result<T>,
}

impl <T> PromiseNode<T> for ImmediatePromiseNode<T> {

    fn on_ready(&mut self, event: Box<Event>) {
        with_current_event_loop(|event_loop| {
            event_loop.borrow_mut().arm_breadth_first(event);
        });
    }
    fn get(self: Box<Self>) -> Result<T> {
        self.result
    }
}

trait ErrorHandler {
    fn task_failed(error: Error);
}

struct TaskSetImpl {
    error_handler: Box<ErrorHandler>,
}

/// A Deque with an insertion point in the middle.
struct InsertDeque<T> {
    front: ::std::collections::VecDeque<T>,
    back: ::std::collections::VecDeque<T>,
}

/// A queue of events being executed in a loop.
pub struct EventLoop {
    daemons: TaskSetImpl,
    running: bool,
    last_runnable_state: bool,
    events: ::std::collections::VecDeque<Box<Event>>,
    depth_first_events: ::std::collections::VecDeque<Box<Event>>,
}

impl EventLoop {

    fn arm_depth_first(&mut self, event: Box<Event>) {
        self.depth_first_events.push_front(event);
    }

    fn arm_breadth_first(&mut self, event: Box<Event>) {
        self.events.push_back(event);
    }

    /// Run the even loop for `max_turn_count` turns or until there is nothing left to be done,
    /// whichever comes first. This never calls the `EventPort`'s `sleep()` or `poll()`. It will
    /// call the `EventPort`'s `set_runnable(false)` if the queue becomes empty.
    pub fn run(&mut self, max_turn_count : u32) {
        self.running = true;

        for _ in 0..max_turn_count {
            if !self.turn() {
                break;
            }
        }
    }

    fn turn(&mut self) -> bool {
        assert!(self.depth_first_events.is_empty());
        match self.events.pop_front() {
            None => return false,
            Some(mut event) => {
                // event->firing = true ?
                event.fire();
            }
        }
        while !self.depth_first_events.is_empty() {
            self.events.push_front(self.depth_first_events.pop_back().unwrap());
        }
        return true;
    }
}
<commit_msg>tiny example nearly working<commit_after>#![allow(dead_code)]

use std::cell::RefCell;

thread_local!(static EVENT_LOOP: Option<RefCell<EventLoop>> = None);

fn with_current_event_loop<F, R>(f: F) -> R
    where F: FnOnce(&RefCell<EventLoop>) -> R {
        EVENT_LOOP.with(|maybe_event_loop| {
            match maybe_event_loop {
                &None => panic!("current thread has no event loop"),
                &Some(ref event_loop) => f(event_loop),
            }
        })
    }

pub type Error = Box<::std::error::Error>;
pub type Result<T> = ::std::result::Result<T, Error>;

pub struct Promise<T> where T: 'static {
    pub node : Box<PromiseNode<T>>,
}

impl <T> Promise <T> where T: 'static {
    pub fn then<F, G, R>(self, func: F, error_handler: G) -> Promise<R>
        where F: 'static + FnOnce(T) -> Result<R>,
              G: 'static + FnOnce(Error) -> Result<R>,
              R: 'static {
            let node : Box<PromiseNode<R>> = Box::new(TransformPromiseNode::new(self.node, func, error_handler));
            Promise { node: node }
        }

    pub fn wait(mut self) -> Result<T> {
        with_current_event_loop(move |event_loop| {
            let fired = ::std::rc::Rc::new(::std::cell::Cell::new(false));
            let done_event = BoolEvent { fired: fired.clone()};
            self.node.on_ready(Box::new(done_event));

            event_loop.borrow_mut().running = true;

            while !fired.get() {
                if !event_loop.borrow_mut().turn() {
                    // No events in the queue.
                    panic!("need to implement EventPort");
                }
            }

            self.node.get()
        })
    }
}

pub trait Event {
    fn fire(&mut self);

    /* TODO why doesn't this worked? Something about Sized?
    fn arm_breadth_first(self: Box<Self>) {
        with_current_event_loop(|event_loop| {
     //       event_loop.borrow_mut().arm_breadth_first(self);
        });
    } */
}

struct BoolEvent {
    fired: ::std::rc::Rc<::std::cell::Cell<bool>>,
}

impl Event for BoolEvent {
    fn fire(&mut self) {
        self.fired.set(true);
    }
}

pub trait PromiseNode<T> {
    /// Arms the given event when the promised value is ready.
    fn on_ready(&mut self, event : Box<Event>);

    fn set_self_pointer(&mut self) {}
    fn get(self: Box<Self>) -> Result<T>;
}

/// A PromiseNode that transforms the result of another PromiseNode through an application-provided
/// function (implements `then()`).
pub struct TransformPromiseNode<T, DepT, Func, ErrorFunc>
where Func: FnOnce(DepT) -> Result<T>, ErrorFunc: FnOnce(Error) -> Result<T> {
    dependency: Box<PromiseNode<DepT>>,
    func: Func,
    error_handler: ErrorFunc,
}

impl <T, DepT, Func, ErrorFunc> TransformPromiseNode<T, DepT, Func, ErrorFunc>
where Func: FnOnce(DepT) -> Result<T>, ErrorFunc: FnOnce(Error) -> Result<T> {
    fn new(dependency: Box<PromiseNode<DepT>>, func: Func, error_handler: ErrorFunc)
           -> TransformPromiseNode<T, DepT, Func, ErrorFunc> {
        TransformPromiseNode { dependency : dependency,
                               func: func, error_handler: error_handler }
    }
}

impl <T, DepT, Func, ErrorFunc> PromiseNode<T> for TransformPromiseNode<T, DepT, Func, ErrorFunc>
where Func: FnOnce(DepT) -> Result<T>, ErrorFunc: FnOnce(Error) -> Result<T> {
    fn on_ready(&mut self, event: Box<Event>) {
        self.dependency.on_ready(event);
    }
    fn get(self: Box<Self>) -> Result<T> {
        let tmp = *self;
        let TransformPromiseNode {dependency, func, error_handler} = tmp;
        match dependency.get() {
            Ok(value) => {
                func(value)
            }
            Err(e) => {
                error_handler(e)
            }
        }
    }
}

/// A promise that has already been resolved to an immediate value or error.
pub struct ImmediatePromiseNode<T> {
    result: Result<T>,
}

impl <T> PromiseNode<T> for ImmediatePromiseNode<T> {

    fn on_ready(&mut self, event: Box<Event>) {
        with_current_event_loop(|event_loop| {
            event_loop.borrow_mut().arm_breadth_first(event);
        });
    }
    fn get(self: Box<Self>) -> Result<T> {
        self.result
    }
}

trait ErrorHandler {
    fn task_failed(error: Error);
}

struct TaskSetImpl {
    error_handler: Box<ErrorHandler>,
}

/// A queue of events being executed in a loop.
pub struct EventLoop {
    daemons: TaskSetImpl,
    running: bool,
    last_runnable_state: bool,
    events: ::std::collections::VecDeque<Box<Event>>,
    depth_first_events: ::std::collections::VecDeque<Box<Event>>,
}

impl EventLoop {

    fn arm_depth_first(&mut self, event: Box<Event>) {
        self.depth_first_events.push_front(event);
    }

    fn arm_breadth_first(&mut self, event: Box<Event>) {
        self.events.push_back(event);
    }

    /// Run the event loop for `max_turn_count` turns or until there is nothing left to be done,
    /// whichever comes first. This never calls the `EventPort`'s `sleep()` or `poll()`. It will
    /// call the `EventPort`'s `set_runnable(false)` if the queue becomes empty.
    pub fn run(&mut self, max_turn_count : u32) {
        self.running = true;

        for _ in 0..max_turn_count {
            if !self.turn() {
                break;
            }
        }
    }

    fn turn(&mut self) -> bool {
        assert!(self.depth_first_events.is_empty());
        match self.events.pop_front() {
            None => return false,
            Some(mut event) => {
                // event->firing = true ?
                event.fire();
            }
        }
        while !self.depth_first_events.is_empty() {
            self.events.push_front(self.depth_first_events.pop_back().unwrap());
        }
        return true;
    }
}

/// A callback which can be used to fulfill a promise.
pub trait PromiseFulfiller<T> where T: 'static {
    fn fulfill(&mut self, value: T);
    fn reject(&mut self, error: Error);
}

pub enum OnReadyEvent {
    Empty,
    AlreadyReady,
    Full(Box<Event>),
}

impl OnReadyEvent {
    fn is_already_ready(&self) -> bool {
        match self {
            &OnReadyEvent::AlreadyReady => return true,
            _ => return false,
        }
    }

    fn is_empty(&self) -> bool {
        match self {
            &OnReadyEvent::Empty => return true,
            _ => return false,
        }
    }

    fn init(&mut self, new_event: Box<Event>) {
        if self.is_already_ready() {
            with_current_event_loop(|event_loop| {
                event_loop.borrow_mut().arm_breadth_first(new_event);
            });
        } else {
            *self = OnReadyEvent::Empty;
        }
    }

    fn arm(&mut self) {
        if self.is_empty() {
            *self = OnReadyEvent::AlreadyReady;
        } else {
            let old_self = ::std::mem::replace(self, OnReadyEvent::Empty);
            match old_self {
                OnReadyEvent::Full(event) => {
                    with_current_event_loop(|event_loop| {
                        event_loop.borrow_mut().arm_depth_first(event);
                    });
                }
                _ => {
                    panic!("armed an event twice?");
                }
            }
        }
    }
}

pub struct PromiseAndFulfillerHub<T> where T: 'static {
    result: Option<Result<T>>,
    on_ready_event: OnReadyEvent,
}

impl <T> PromiseFulfiller<T> for PromiseAndFulfillerHub<T> where T: 'static {
    fn fulfill(&mut self, value: T) {
        if self.result.is_none() {
            self.result = Some(Ok(value));
        }
    }

    fn reject(&mut self, error: Error) {
        if self.result.is_none() {
            self.result = Some(Err(error));
        }
    }
}

/*
pub struct WrapperPromiseNode<T> where T: 'static {
    hub: ::std::rc::Rc<::std::cell::RefCell<PromiseAndFulfillerHub<T>>>,
}
*/

impl <T> PromiseNode<T> for ::std::rc::Rc<::std::cell::RefCell<PromiseAndFulfillerHub<T>>> where T: 'static {
    fn on_ready(&mut self, event: Box<Event>) {
        self.borrow_mut().on_ready_event.init(event);
    }
    fn get(self: Box<Self>) -> Result<T> {
        match ::std::mem::replace(&mut self.borrow_mut().result, None) {
            None => panic!("no result!"),
            Some(r) => r
        }
    }
}

impl <T> PromiseFulfiller<T> for ::std::rc::Rc<::std::cell::RefCell<PromiseAndFulfillerHub<T>>> where T: 'static {
    fn fulfill(&mut self, value: T) {
        self.borrow_mut().fulfill(value);
    }

    fn reject(&mut self, error: Error) {
        self.borrow_mut().reject(error);
    }
}

pub fn new_promise_and_fulfiller<T>() -> (Promise<T>, Box<PromiseFulfiller<T>>) where T: 'static {
    let result = ::std::rc::Rc::new(::std::cell::RefCell::new(
        PromiseAndFulfillerHub { result: None::<Result<T>>, on_ready_event: OnReadyEvent::Empty }));
    let result_promise : Promise<T> = Promise { node: Box::new(result.clone())};
    (result_promise, Box::new(result))
}

#[cfg(test)]
mod tests {

    #[test]
    fn hello() {
        let (mut promise, mut fulfiller) = ::new_promise_and_fulfiller::<u32>();
        let p1 = promise.then(|x| {
            println!("x = {}", x);
            return Ok(x + 1);
        }, |e| {
            return Ok(1);
        });

        fulfiller.fulfill(10);
        p1.wait();

    }
}
<|endoftext|>


<commit_before>#![feature(no_std)]
#![no_std]

extern crate num;

pub mod create;
pub use create::*;

pub mod set;
pub use set::*;

pub mod mul;
pub use mul::*;

pub mod sdiv;
pub use sdiv::*;

pub mod misc;
pub use misc::*;

pub mod transform;
pub use transform::*;
<commit_msg>updated to lastest rust nightly<commit_after>#![no_std]

extern crate num;

pub mod create;
pub use create::*;

pub mod set;
pub use set::*;

pub mod mul;
pub use mul::*;

pub mod sdiv;
pub use sdiv::*;

pub mod misc;
pub use misc::*;

pub mod transform;
pub use transform::*;
<|endoftext|>


<commit_before>//! Task queue
//! The implementation of the thread pool for Rust.
//!
//! # Example
//! ``` rust
//! extern crate task_queue;
//!
//! use std::sync::{ Arc, Mutex };
//!
//! let data = Arc::new(Mutex::new(0));
//! let mut queue = task_queue::TaskQueue::new();
//!
//! for _ in 0..1000 {
//!    let clone = data.clone();
//!
//!    queue.enqueue(move || {
//!        let mut guard = clone.lock().unwrap();
//!        *guard += 1;
//!    }).unwrap();
//! }
//!
//! let not_executed_tasks = queue.stop().unwrap();
//! for t in &not_executed_tasks {
//!     t.run();
//! }
//! ```
//!
//! Library supports dynamic control over the number of threads.
//! For implement it you should use SpawnPolicy trait.
//!
//! For example StaticSpawnPolicy implementation:
//! # Example
//! ``` rust
//! pub struct StaticSpawnPolicy;
//!
//! impl SpawnPolicy for StaticSpawnPolicy {
//!     fn get_count(&self, queue: &TaskQueue) -> usize {
//!         queue.max_threads
//!     }
//! }
//! ```

pub mod error;
pub mod spawn_policy;
mod pipe;

use std::thread::{ JoinHandle, Builder };

use error::TaskQueueError;
use pipe::Sender;
use pipe::Reciver;
use pipe::ReciverHandle;
use spawn_policy::SpawnPolicy;
use spawn_policy::StaticSpawnPolicy;

pub struct TaskQueue {
    sender: Sender<Message>,

    policy: Box<SpawnPolicy>,
    min_threads: usize,
    max_threads: usize,

    threads: Vec<ThreadInfo>,
    last_thread_id: i64
}

impl TaskQueue {
    /// Create new task queue with 10 threads
    pub fn new() -> TaskQueue {
        TaskQueue::with_threads(10, 10)
    }

    /// Create new task quque with selected threads count
    pub fn with_threads(min: usize, max: usize) -> TaskQueue {
        TaskQueue {
            sender: Sender::<Message>::new(),
            policy: Box::new(StaticSpawnPolicy::new()),
            min_threads: min,
            max_threads: max,
            threads: Vec::new(),
            last_thread_id: 0
        }
    }

    /// Schedule task in queue
    pub fn enqueue<F>(&mut self, f: F) -> Result<(), TaskQueueError> where F: Fn() + Send + 'static, {
        let task = Task { value: Box::new(f) };
        self.sender.put(Message::Task(task));

        let count = self.policy.get_count(self);
        let mut runned = self.threads.len();

        if count > runned {
            for _ in runned..count {
                let info = try!(self.build_and_run());
                self.threads.push(info);
            }
        } else {
            loop {
                if runned == count {
                    break;
                }

                let info = self.threads.remove(0);
                self.sender.put_for(info.reciver, Message::CloseThread);
                runned -= 1;
            }
        }

        Ok(())
    }

    fn build_and_run(&mut self) -> Result<ThreadInfo, TaskQueueError> {
        self.last_thread_id += 1;

        let name = format!("TaskQueue::thread {}", self.last_thread_id);
        let reciver = self.sender.create_reciver();
        let reciver_handle = reciver.handle();

        let handle = try!(Builder::new()
            .name(name)
            .spawn(move || TaskQueue::thread_update(reciver)));

        Ok(ThreadInfo::new(reciver_handle, handle))
    }

    fn thread_update(reciver: Reciver<Message>) {
        loop {
            let message = reciver.get();
            match message {
                Message::Task(t) => t.run(),
                Message::CloseThread => return,
            }
        }
    }

    /// Stops tasks queue work and return are not completed tasks
    pub fn stop(self) -> Result<Vec<Task>, TaskQueueError> {
        for info in &self.threads {
            self.sender.put_for(info.reciver.clone(), Message::CloseThread);
        }

        for info in self.threads {
            if let Err(_) = info.handle.join() {
                return Err(TaskQueueError::Join);
            }
        }

        let not_executed = self.sender.cancel_all();
        let mut result = Vec::<Task>::new();
        for m in not_executed {
            let task = match m {
                Message::Task(t) => t,
                Message::CloseThread => panic!("This should never happen")
            };

            result.push(task);
        }

        Ok(result)
    }

    /// Returns current threads count
    pub fn get_threads_count(&self) -> usize {
        self.threads.len()
    }

    /// Return max threads count
    pub fn get_max_threads(&self) -> usize {
        self.max_threads
    }

    /// Return min threads count
    pub fn get_min_threads(&self) -> usize {
        self.min_threads
    }

    /// Sets a policy for controlling the amount of threads
    pub fn set_spawn_policy(&mut self, policy: Box<SpawnPolicy>) {
        self.policy = policy;
    }

    /// Gets tasks count in queue
    pub fn tasks_count(&self) -> usize {
        self.sender.size()
    }
}

struct ThreadInfo {
    reciver: ReciverHandle,
    handle: JoinHandle<()>,
}

impl ThreadInfo {
    fn new(reciver: ReciverHandle, handle: JoinHandle<()>) -> ThreadInfo {
        ThreadInfo {
            reciver: reciver,
            handle: handle
        }
    }
}

enum Message {
    Task(Task),
    CloseThread,
}

pub struct Task {
    value: Box<Fn() + Send + 'static>,
}

impl Task {
    pub fn run(&self) {
        (self.value)();
    }
}
<commit_msg>Doc fix<commit_after>//! Task queue
//! The implementation of the thread pool for Rust.
//!
//! # Example
//! ``` rust
//! extern crate task_queue;
//!
//! use std::sync::{ Arc, Mutex };
//!
//! let data = Arc::new(Mutex::new(0));
//! let mut queue = task_queue::TaskQueue::new();
//!
//! for _ in 0..1000 {
//!    let clone = data.clone();
//!
//!    queue.enqueue(move || {
//!        let mut guard = clone.lock().unwrap();
//!        *guard += 1;
//!    }).unwrap();
//! }
//!
//! let not_executed_tasks = queue.stop().unwrap();
//! for t in &not_executed_tasks {
//!     t.run();
//! }
//! ```
//!
//! Library supports dynamic control over the number of threads.
//! For implement it you should use SpawnPolicy trait.
//!
//! For example StaticSpawnPolicy implementation:
//! # Example
//! ```
//! use task_queue::TaskQueue;
//! use task_queue::spawn_policy::SpawnPolicy;
//!
//! pub struct StaticSpawnPolicy;
//!
//! impl SpawnPolicy for StaticSpawnPolicy {
//!     fn get_count(&self, queue: &TaskQueue) -> usize {
//!         queue.get_max_threads()
//!     }
//! }
//! #
//! # fn main() {
//! # }
//! ```

pub mod error;
pub mod spawn_policy;
mod pipe;

use std::thread::{ JoinHandle, Builder };

use error::TaskQueueError;
use pipe::Sender;
use pipe::Reciver;
use pipe::ReciverHandle;
use spawn_policy::SpawnPolicy;
use spawn_policy::StaticSpawnPolicy;

pub struct TaskQueue {
    sender: Sender<Message>,

    policy: Box<SpawnPolicy>,
    min_threads: usize,
    max_threads: usize,

    threads: Vec<ThreadInfo>,
    last_thread_id: i64
}

impl TaskQueue {
    /// Create new task queue with 10 threads
    pub fn new() -> TaskQueue {
        TaskQueue::with_threads(10, 10)
    }

    /// Create new task quque with selected threads count
    pub fn with_threads(min: usize, max: usize) -> TaskQueue {
        TaskQueue {
            sender: Sender::<Message>::new(),
            policy: Box::new(StaticSpawnPolicy::new()),
            min_threads: min,
            max_threads: max,
            threads: Vec::new(),
            last_thread_id: 0
        }
    }

    /// Schedule task in queue
    pub fn enqueue<F>(&mut self, f: F) -> Result<(), TaskQueueError> where F: Fn() + Send + 'static, {
        let task = Task { value: Box::new(f) };
        self.sender.put(Message::Task(task));

        let count = self.policy.get_count(self);
        let mut runned = self.threads.len();

        if count > runned {
            for _ in runned..count {
                let info = try!(self.build_and_run());
                self.threads.push(info);
            }
        } else {
            loop {
                if runned == count {
                    break;
                }

                let info = self.threads.remove(0);
                self.sender.put_for(info.reciver, Message::CloseThread);
                runned -= 1;
            }
        }

        Ok(())
    }

    fn build_and_run(&mut self) -> Result<ThreadInfo, TaskQueueError> {
        self.last_thread_id += 1;

        let name = format!("TaskQueue::thread {}", self.last_thread_id);
        let reciver = self.sender.create_reciver();
        let reciver_handle = reciver.handle();

        let handle = try!(Builder::new()
            .name(name)
            .spawn(move || TaskQueue::thread_update(reciver)));

        Ok(ThreadInfo::new(reciver_handle, handle))
    }

    fn thread_update(reciver: Reciver<Message>) {
        loop {
            let message = reciver.get();
            match message {
                Message::Task(t) => t.run(),
                Message::CloseThread => return,
            }
        }
    }

    /// Stops tasks queue work and return are not completed tasks
    pub fn stop(self) -> Result<Vec<Task>, TaskQueueError> {
        for info in &self.threads {
            self.sender.put_for(info.reciver.clone(), Message::CloseThread);
        }

        for info in self.threads {
            if let Err(_) = info.handle.join() {
                return Err(TaskQueueError::Join);
            }
        }

        let not_executed = self.sender.cancel_all();
        let mut result = Vec::<Task>::new();
        for m in not_executed {
            let task = match m {
                Message::Task(t) => t,
                Message::CloseThread => panic!("This should never happen")
            };

            result.push(task);
        }

        Ok(result)
    }

    /// Returns current threads count
    pub fn get_threads_count(&self) -> usize {
        self.threads.len()
    }

    /// Return max threads count
    pub fn get_max_threads(&self) -> usize {
        self.max_threads
    }

    /// Return min threads count
    pub fn get_min_threads(&self) -> usize {
        self.min_threads
    }

    /// Sets a policy for controlling the amount of threads
    pub fn set_spawn_policy(&mut self, policy: Box<SpawnPolicy>) {
        self.policy = policy;
    }

    /// Gets tasks count in queue
    pub fn tasks_count(&self) -> usize {
        self.sender.size()
    }
}

struct ThreadInfo {
    reciver: ReciverHandle,
    handle: JoinHandle<()>,
}

impl ThreadInfo {
    fn new(reciver: ReciverHandle, handle: JoinHandle<()>) -> ThreadInfo {
        ThreadInfo {
            reciver: reciver,
            handle: handle
        }
    }
}

enum Message {
    Task(Task),
    CloseThread,
}

pub struct Task {
    value: Box<Fn() + Send + 'static>,
}

impl Task {
    pub fn run(&self) {
        (self.value)();
    }
}
<|endoftext|>


<commit_before>// #![feature(plugin)]
// #![plugin(clippy)]

//!  Several libraries used in solving Project Euler problems (https://projecteuler.net)
//!
//! # Using this library
//!
//! Just add the following to your [`Cargo.toml`](http://crates.io/):
//!
//! ```toml
//! [dependencies]
//! euler_library = { git = "https://github.com/roycrippen/euler_library" }
//! ```
//! And add this to your root crate.
//!
//! ```
//! extern crate euler_library;
//! ```
//!
pub mod big;
pub mod cards;
pub mod common;
pub mod primes;
<commit_msg>doc fix<commit_after>// #![feature(plugin)]
// #![plugin(clippy)]

//!  Several libraries used in solving Project Euler problems (https://projecteuler.net)
//!
//! # Using this library
//!
//! Just add the following to your [`Cargo.toml`](http://crates.io/):
//!
//! ```toml
//! [dependencies.euler_library]
//! git = "https://github.com/roycrippen/euler_library"
//! ```
//! And add this to your root crate.
//!
//! ```
//! extern crate euler_library;
//! ```
//!
pub mod big;
pub mod cards;
pub mod common;
pub mod primes;
<|endoftext|>