<commit_before>//! Main evaluator loop and setting up the initial stack frame.

use std::convert::TryFrom;
use std::ffi::OsStr;

use log::info;

use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt};
use rustc_target::abi::LayoutOf;
use rustc_target::spec::abi::Abi;

use crate::*;

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AlignmentCheck {
    /// Do not check alignment.
    None,
    /// Check alignment "symbolically", i.e., using only the requested alignment for an allocation and not its real base address.
    Symbolic,
    /// Check alignment on the actual physical integer address.
    Int,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum RejectOpWith {
    /// Isolated op is rejected with an abort of the machine.
    Abort,

    /// If not Abort, miri returns an error for an isolated op.
    /// Following options determine if user should be warned about such error.
    /// Do not print warning about rejected isolated op.
    NoWarning,

    /// Print a warning about rejected isolated op, with backtrace.
    Warning,

    /// Print a warning about rejected isolated op, without backtrace.
    WarningWithoutBacktrace,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum IsolatedOp {
    /// Reject an op requiring communication with the host. By
    /// default, miri rejects the op with an abort. If not, it returns
    /// an error code, and prints a warning about it. Warning levels
    /// are controlled by `RejectOpWith` enum.
    Reject(RejectOpWith),

    /// Execute op requiring communication with the host, i.e. disable isolation.
    Allow,
}

/// Configuration needed to spawn a Miri instance.
#[derive(Clone)]
pub struct MiriConfig {
    /// Determine if validity checking is enabled.
    pub validate: bool,
    /// Determines if Stacked Borrows is enabled.
    pub stacked_borrows: bool,
    /// Controls alignment checking.
    pub check_alignment: AlignmentCheck,
    /// Controls function [ABI](Abi) checking.
    pub check_abi: bool,
    /// Action for an op requiring communication with the host.
    pub isolated_op: IsolatedOp,
    /// Determines if memory leaks should be ignored.
    pub ignore_leaks: bool,
    /// Environment variables that should always be isolated from the host.
    pub excluded_env_vars: Vec<String>,
    /// Command-line arguments passed to the interpreted program.
    pub args: Vec<String>,
    /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
    pub seed: Option<u64>,
    /// The stacked borrows pointer id to report about
    pub tracked_pointer_tag: Option<PtrId>,
    /// The stacked borrows call ID to report about
    pub tracked_call_id: Option<CallId>,
    /// The allocation id to report about.
    pub tracked_alloc_id: Option<AllocId>,
    /// Whether to track raw pointers in stacked borrows.
    pub track_raw: bool,
    /// Determine if data race detection should be enabled
    pub data_race_detector: bool,
    /// Rate of spurious failures for compare_exchange_weak atomic operations,
    /// between 0.0 and 1.0, defaulting to 0.8 (80% chance of failure).
    pub cmpxchg_weak_failure_rate: f64,
    /// If `Some`, enable the `measureme` profiler, writing results to a file
    /// with the specified prefix.
    pub measureme_out: Option<String>,
    /// Panic when unsupported functionality is encountered
    pub panic_on_unsupported: bool,
}

impl Default for MiriConfig {
    fn default() -> MiriConfig {
        MiriConfig {
            validate: true,
            stacked_borrows: true,
            check_alignment: AlignmentCheck::Int,
            check_abi: true,
            isolated_op: IsolatedOp::Reject(RejectOpWith::Abort),
            ignore_leaks: false,
            excluded_env_vars: vec![],
            args: vec![],
            seed: None,
            tracked_pointer_tag: None,
            tracked_call_id: None,
            tracked_alloc_id: None,
            track_raw: false,
            data_race_detector: true,
            cmpxchg_weak_failure_rate: 0.8,
            measureme_out: None,
            panic_on_unsupported: false,
        }
    }
}

/// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing
/// the location where the return value of the `start` lang item will be
/// written to.
/// Public because this is also used by `priroda`.
pub fn create_ecx<'mir, 'tcx: 'mir>(
    tcx: TyCtxt<'tcx>,
    main_id: DefId,
    config: MiriConfig,
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Tag>)> {
    let param_env = ty::ParamEnv::reveal_all();
    let layout_cx = LayoutCx { tcx, param_env };
    let mut ecx = InterpCx::new(
        tcx,
        rustc_span::source_map::DUMMY_SP,
        param_env,
        Evaluator::new(&config, layout_cx),
        MemoryExtra::new(&config),
    );
    // Complete initialization.
    EnvVars::init(&mut ecx, config.excluded_env_vars)?;
    MemoryExtra::init_extern_statics(&mut ecx)?;

    // Setup first stack-frame
    let main_instance = ty::Instance::mono(tcx, main_id);
    let main_mir = ecx.load_mir(main_instance.def, None)?;
    if main_mir.arg_count != 0 {
        bug!("main function must not take any arguments");
    }

    let start_id = tcx.lang_items().start_fn().unwrap();
    let main_ret_ty = tcx.fn_sig(main_id).output();
    let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
    let start_instance = ty::Instance::resolve(
        tcx,
        ty::ParamEnv::reveal_all(),
        start_id,
        tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))),
    )
    .unwrap()
    .unwrap();

    // First argument: pointer to `main()`.
    let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance));
    // Second argument (argc): length of `config.args`.
    let argc = Scalar::from_machine_usize(u64::try_from(config.args.len()).unwrap(), &ecx);
    // Third argument (`argv`): created from `config.args`.
    let argv = {
        // Put each argument in memory, collect pointers.
        let mut argvs = Vec::<Immediate<Tag>>::new();
        for arg in config.args.iter() {
            // Make space for `0` terminator.
            let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap();
            let arg_type = tcx.mk_array(tcx.types.u8, size);
            let arg_place =
                ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into())?;
            ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?;
            ecx.mark_immutable(&*arg_place);
            argvs.push(arg_place.to_ref(&ecx));
        }
        // Make an array with all these pointers, in the Miri memory.
        let argvs_layout = ecx.layout_of(
            tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), u64::try_from(argvs.len()).unwrap()),
        )?;
        let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?;
        for (idx, arg) in argvs.into_iter().enumerate() {
            let place = ecx.mplace_field(&argvs_place, idx)?;
            ecx.write_immediate(arg, &place.into())?;
        }
        ecx.mark_immutable(&*argvs_place);
        // A pointer to that place is the 3rd argument for main.
        let argv = argvs_place.to_ref(&ecx);
        // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`.
        {
            let argc_place =
                ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?;
            ecx.write_scalar(argc, &argc_place.into())?;
            ecx.mark_immutable(&*argc_place);
            ecx.machine.argc = Some(*argc_place);

            let argv_place = ecx.allocate(
                ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?,
                MiriMemoryKind::Machine.into(),
            )?;
            ecx.write_immediate(argv, &argv_place.into())?;
            ecx.mark_immutable(&*argv_place);
            ecx.machine.argv = Some(*argv_place);
        }
        // Store command line as UTF-16 for Windows `GetCommandLineW`.
        {
            // Construct a command string with all the aguments.
            let mut cmd = String::new();
            for arg in config.args.iter() {
                if !cmd.is_empty() {
                    cmd.push(' ');
                }
                cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into()));
            }
            // Don't forget `0` terminator.
            cmd.push(std::char::from_u32(0).unwrap());

            let cmd_utf16: Vec<u16> = cmd.encode_utf16().collect();
            let cmd_type = tcx.mk_array(tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap());
            let cmd_place =
                ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?;
            ecx.machine.cmd_line = Some(*cmd_place);
            // Store the UTF-16 string. We just allocated so we know the bounds are fine.
            for (idx, &c) in cmd_utf16.iter().enumerate() {
                let place = ecx.mplace_field(&cmd_place, idx)?;
                ecx.write_scalar(Scalar::from_u16(c), &place.into())?;
            }
            ecx.mark_immutable(&*cmd_place);
        }
        argv
    };

    // Return place (in static memory so that it does not count as leak).
    let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?;
    // Call start function.
    ecx.call_function(
        start_instance,
        Abi::Rust,
        &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv],
        Some(&ret_place.into()),
        StackPopCleanup::None { cleanup: true },
    )?;

    Ok((ecx, ret_place))
}

/// Evaluates the main function specified by `main_id`.
/// Returns `Some(return_code)` if program executed completed.
/// Returns `None` if an evaluation error occured.
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
    // Copy setting before we move `config`.
    let ignore_leaks = config.ignore_leaks;

    let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) {
        Ok(v) => v,
        Err(err) => {
            err.print_backtrace();
            panic!("Miri initialization error: {}", err.kind())
        }
    };

    // Perform the main execution.
    let res: InterpResult<'_, i64> = (|| {
        // Main loop.
        loop {
            let info = ecx.preprocess_diagnostics();
            match ecx.schedule()? {
                SchedulingAction::ExecuteStep => {
                    assert!(ecx.step()?, "a terminated thread was scheduled for execution");
                }
                SchedulingAction::ExecuteTimeoutCallback => {
                    assert!(
                        ecx.machine.communicate(),
                        "scheduler callbacks require disabled isolation, but the code \
                        that created the callback did not check it"
                    );
                    ecx.run_timeout_callback()?;
                }
                SchedulingAction::ExecuteDtors => {
                    // This will either enable the thread again (so we go back
                    // to `ExecuteStep`), or determine that this thread is done
                    // for good.
                    ecx.schedule_next_tls_dtor_for_active_thread()?;
                }
                SchedulingAction::Stop => {
                    break;
                }
            }
            ecx.process_diagnostics(info);
        }
        let return_code = ecx.read_scalar(&ret_place.into())?.to_machine_isize(&ecx)?;
        Ok(return_code)
    })();

    // Machine cleanup.
    EnvVars::cleanup(&mut ecx).unwrap();

    // Process the result.
    match res {
        Ok(return_code) => {
            if !ignore_leaks {
                // Check for thread leaks.
                if !ecx.have_all_terminated() {
                    tcx.sess.err("the main thread terminated without waiting for all remaining threads");
                    return None;
                }
                // Check for memory leaks.
                info!("Additonal static roots: {:?}", ecx.machine.static_roots);
                let leaks = ecx.memory.leak_report(&ecx.machine.static_roots);
                if leaks != 0 {
                    tcx.sess.err("the evaluated program leaked memory");
                    // Ignore the provided return code - let the reported error
                    // determine the return code.
                    return None;
                }
            }
            Some(return_code)
        }
        Err(e) => report_error(&ecx, e),
    }
}
<commit_msg>tell users how to disable the leak check<commit_after>//! Main evaluator loop and setting up the initial stack frame.

use std::convert::TryFrom;
use std::ffi::OsStr;

use log::info;

use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt};
use rustc_target::abi::LayoutOf;
use rustc_target::spec::abi::Abi;

use crate::*;

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AlignmentCheck {
    /// Do not check alignment.
    None,
    /// Check alignment "symbolically", i.e., using only the requested alignment for an allocation and not its real base address.
    Symbolic,
    /// Check alignment on the actual physical integer address.
    Int,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum RejectOpWith {
    /// Isolated op is rejected with an abort of the machine.
    Abort,

    /// If not Abort, miri returns an error for an isolated op.
    /// Following options determine if user should be warned about such error.
    /// Do not print warning about rejected isolated op.
    NoWarning,

    /// Print a warning about rejected isolated op, with backtrace.
    Warning,

    /// Print a warning about rejected isolated op, without backtrace.
    WarningWithoutBacktrace,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum IsolatedOp {
    /// Reject an op requiring communication with the host. By
    /// default, miri rejects the op with an abort. If not, it returns
    /// an error code, and prints a warning about it. Warning levels
    /// are controlled by `RejectOpWith` enum.
    Reject(RejectOpWith),

    /// Execute op requiring communication with the host, i.e. disable isolation.
    Allow,
}

/// Configuration needed to spawn a Miri instance.
#[derive(Clone)]
pub struct MiriConfig {
    /// Determine if validity checking is enabled.
    pub validate: bool,
    /// Determines if Stacked Borrows is enabled.
    pub stacked_borrows: bool,
    /// Controls alignment checking.
    pub check_alignment: AlignmentCheck,
    /// Controls function [ABI](Abi) checking.
    pub check_abi: bool,
    /// Action for an op requiring communication with the host.
    pub isolated_op: IsolatedOp,
    /// Determines if memory leaks should be ignored.
    pub ignore_leaks: bool,
    /// Environment variables that should always be isolated from the host.
    pub excluded_env_vars: Vec<String>,
    /// Command-line arguments passed to the interpreted program.
    pub args: Vec<String>,
    /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
    pub seed: Option<u64>,
    /// The stacked borrows pointer id to report about
    pub tracked_pointer_tag: Option<PtrId>,
    /// The stacked borrows call ID to report about
    pub tracked_call_id: Option<CallId>,
    /// The allocation id to report about.
    pub tracked_alloc_id: Option<AllocId>,
    /// Whether to track raw pointers in stacked borrows.
    pub track_raw: bool,
    /// Determine if data race detection should be enabled
    pub data_race_detector: bool,
    /// Rate of spurious failures for compare_exchange_weak atomic operations,
    /// between 0.0 and 1.0, defaulting to 0.8 (80% chance of failure).
    pub cmpxchg_weak_failure_rate: f64,
    /// If `Some`, enable the `measureme` profiler, writing results to a file
    /// with the specified prefix.
    pub measureme_out: Option<String>,
    /// Panic when unsupported functionality is encountered
    pub panic_on_unsupported: bool,
}

impl Default for MiriConfig {
    fn default() -> MiriConfig {
        MiriConfig {
            validate: true,
            stacked_borrows: true,
            check_alignment: AlignmentCheck::Int,
            check_abi: true,
            isolated_op: IsolatedOp::Reject(RejectOpWith::Abort),
            ignore_leaks: false,
            excluded_env_vars: vec![],
            args: vec![],
            seed: None,
            tracked_pointer_tag: None,
            tracked_call_id: None,
            tracked_alloc_id: None,
            track_raw: false,
            data_race_detector: true,
            cmpxchg_weak_failure_rate: 0.8,
            measureme_out: None,
            panic_on_unsupported: false,
        }
    }
}

/// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing
/// the location where the return value of the `start` lang item will be
/// written to.
/// Public because this is also used by `priroda`.
pub fn create_ecx<'mir, 'tcx: 'mir>(
    tcx: TyCtxt<'tcx>,
    main_id: DefId,
    config: MiriConfig,
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Tag>)> {
    let param_env = ty::ParamEnv::reveal_all();
    let layout_cx = LayoutCx { tcx, param_env };
    let mut ecx = InterpCx::new(
        tcx,
        rustc_span::source_map::DUMMY_SP,
        param_env,
        Evaluator::new(&config, layout_cx),
        MemoryExtra::new(&config),
    );
    // Complete initialization.
    EnvVars::init(&mut ecx, config.excluded_env_vars)?;
    MemoryExtra::init_extern_statics(&mut ecx)?;

    // Setup first stack-frame
    let main_instance = ty::Instance::mono(tcx, main_id);
    let main_mir = ecx.load_mir(main_instance.def, None)?;
    if main_mir.arg_count != 0 {
        bug!("main function must not take any arguments");
    }

    let start_id = tcx.lang_items().start_fn().unwrap();
    let main_ret_ty = tcx.fn_sig(main_id).output();
    let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
    let start_instance = ty::Instance::resolve(
        tcx,
        ty::ParamEnv::reveal_all(),
        start_id,
        tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))),
    )
    .unwrap()
    .unwrap();

    // First argument: pointer to `main()`.
    let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance));
    // Second argument (argc): length of `config.args`.
    let argc = Scalar::from_machine_usize(u64::try_from(config.args.len()).unwrap(), &ecx);
    // Third argument (`argv`): created from `config.args`.
    let argv = {
        // Put each argument in memory, collect pointers.
        let mut argvs = Vec::<Immediate<Tag>>::new();
        for arg in config.args.iter() {
            // Make space for `0` terminator.
            let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap();
            let arg_type = tcx.mk_array(tcx.types.u8, size);
            let arg_place =
                ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into())?;
            ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?;
            ecx.mark_immutable(&*arg_place);
            argvs.push(arg_place.to_ref(&ecx));
        }
        // Make an array with all these pointers, in the Miri memory.
        let argvs_layout = ecx.layout_of(
            tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), u64::try_from(argvs.len()).unwrap()),
        )?;
        let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?;
        for (idx, arg) in argvs.into_iter().enumerate() {
            let place = ecx.mplace_field(&argvs_place, idx)?;
            ecx.write_immediate(arg, &place.into())?;
        }
        ecx.mark_immutable(&*argvs_place);
        // A pointer to that place is the 3rd argument for main.
        let argv = argvs_place.to_ref(&ecx);
        // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`.
        {
            let argc_place =
                ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?;
            ecx.write_scalar(argc, &argc_place.into())?;
            ecx.mark_immutable(&*argc_place);
            ecx.machine.argc = Some(*argc_place);

            let argv_place = ecx.allocate(
                ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?,
                MiriMemoryKind::Machine.into(),
            )?;
            ecx.write_immediate(argv, &argv_place.into())?;
            ecx.mark_immutable(&*argv_place);
            ecx.machine.argv = Some(*argv_place);
        }
        // Store command line as UTF-16 for Windows `GetCommandLineW`.
        {
            // Construct a command string with all the aguments.
            let mut cmd = String::new();
            for arg in config.args.iter() {
                if !cmd.is_empty() {
                    cmd.push(' ');
                }
                cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into()));
            }
            // Don't forget `0` terminator.
            cmd.push(std::char::from_u32(0).unwrap());

            let cmd_utf16: Vec<u16> = cmd.encode_utf16().collect();
            let cmd_type = tcx.mk_array(tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap());
            let cmd_place =
                ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?;
            ecx.machine.cmd_line = Some(*cmd_place);
            // Store the UTF-16 string. We just allocated so we know the bounds are fine.
            for (idx, &c) in cmd_utf16.iter().enumerate() {
                let place = ecx.mplace_field(&cmd_place, idx)?;
                ecx.write_scalar(Scalar::from_u16(c), &place.into())?;
            }
            ecx.mark_immutable(&*cmd_place);
        }
        argv
    };

    // Return place (in static memory so that it does not count as leak).
    let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?;
    // Call start function.
    ecx.call_function(
        start_instance,
        Abi::Rust,
        &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv],
        Some(&ret_place.into()),
        StackPopCleanup::None { cleanup: true },
    )?;

    Ok((ecx, ret_place))
}

/// Evaluates the main function specified by `main_id`.
/// Returns `Some(return_code)` if program executed completed.
/// Returns `None` if an evaluation error occured.
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
    // Copy setting before we move `config`.
    let ignore_leaks = config.ignore_leaks;

    let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) {
        Ok(v) => v,
        Err(err) => {
            err.print_backtrace();
            panic!("Miri initialization error: {}", err.kind())
        }
    };

    // Perform the main execution.
    let res: InterpResult<'_, i64> = (|| {
        // Main loop.
        loop {
            let info = ecx.preprocess_diagnostics();
            match ecx.schedule()? {
                SchedulingAction::ExecuteStep => {
                    assert!(ecx.step()?, "a terminated thread was scheduled for execution");
                }
                SchedulingAction::ExecuteTimeoutCallback => {
                    assert!(
                        ecx.machine.communicate(),
                        "scheduler callbacks require disabled isolation, but the code \
                        that created the callback did not check it"
                    );
                    ecx.run_timeout_callback()?;
                }
                SchedulingAction::ExecuteDtors => {
                    // This will either enable the thread again (so we go back
                    // to `ExecuteStep`), or determine that this thread is done
                    // for good.
                    ecx.schedule_next_tls_dtor_for_active_thread()?;
                }
                SchedulingAction::Stop => {
                    break;
                }
            }
            ecx.process_diagnostics(info);
        }
        let return_code = ecx.read_scalar(&ret_place.into())?.to_machine_isize(&ecx)?;
        Ok(return_code)
    })();

    // Machine cleanup.
    EnvVars::cleanup(&mut ecx).unwrap();

    // Process the result.
    match res {
        Ok(return_code) => {
            if !ignore_leaks {
                // Check for thread leaks.
                if !ecx.have_all_terminated() {
                    tcx.sess.err(
                        "the main thread terminated without waiting for all remaining threads",
                    );
                    tcx.sess.note_without_error("pass `-Zmiri-ignore-leaks` to disable this check");
                    return None;
                }
                // Check for memory leaks.
                info!("Additonal static roots: {:?}", ecx.machine.static_roots);
                let leaks = ecx.memory.leak_report(&ecx.machine.static_roots);
                if leaks != 0 {
                    tcx.sess.err("the evaluated program leaked memory");
                    tcx.sess.note_without_error("pass `-Zmiri-ignore-leaks` to disable this check");
                    // Ignore the provided return code - let the reported error
                    // determine the return code.
                    return None;
                }
            }
            Some(return_code)
        }
        Err(e) => report_error(&ecx, e),
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;
extern crate clap;

#[macro_use]
extern crate futures;
extern crate futures_cpupool;

#[macro_use]
extern crate tokio_core;

use futures::{Async, Poll, Future};
use futures::stream::Stream;

mod all {
    use futures::{Async, Poll, Future};
    enum ElemState<T> where T: Future {
        Pending(T),
        Done(T::Item),
    }

    pub struct All<T> where T: Future {
        elems: Vec<ElemState<T>>,
    }

    impl <T> All<T> where T: Future {
        pub fn new<I>(futures: I) -> All<T> where I: Iterator<Item=T> {
            let mut result = All { elems: Vec::new() };
            for f in futures {
                result.elems.push(ElemState::Pending(f))
            }
            result
        }
    }

    impl <T> Future for All<T> where T: Future {
        type Item = Vec<T::Item>;
        type Error = T::Error;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            let mut all_done = true;

            for idx in 0 .. self.elems.len() {
                let done_val = match &mut self.elems[idx] {
                    &mut ElemState::Pending(ref mut t) => {
                        match t.poll() {
                            Ok(Async::Ready(t)) => t,
                            Ok(Async::NotReady) => {
                                all_done = false;
                                continue
                            }
                            Err(e) => return Err(e),
                        }
                    }
                    &mut ElemState::Done(ref mut _v) => continue,
                };

                self.elems[idx] = ElemState::Done(done_val);
            }

            if all_done {
                let mut result = Vec::new();
                let elems = ::std::mem::replace(&mut self.elems, Vec::new());
                for e in elems.into_iter() {
                    match e {
                        ElemState::Done(t) => result.push(t),
                        _ => unreachable!(),
                    }
                }
                Ok(Async::Ready(result))
            } else {
                Ok(Async::NotReady)
            }
        }
    }
}

struct Knot<F, S, T, E>
    where F: Fn(S) -> T,
          T: Future<Item=(S, bool), Error=E>
{
    f: F,
    in_progress: T,
}

fn tie_knot<F, S, T, E>(initial_state: S, f: F) -> Knot<F, S, T, E>
    where F: Fn(S) -> T,
          T: Future<Item=(S, bool), Error=E>,
{
    let in_progress = f(initial_state);
    Knot {
        f: f,
        in_progress: in_progress,
    }
}

impl <F, S, T, E> Future for Knot<F, S, T, E>
    where F: Fn(S) -> T,
          T: Future<Item=(S, bool), Error=E>
{
    type Item = S;
    type Error = E;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            let (s, more) = try_ready!(self.in_progress.poll());
            if more {
                self.in_progress = (self.f)(s);
            } else {
                return Ok(Async::Ready(s))
            }
        }
    }
}

struct Reading<R> where R: ::std::io::Read {
    reader: Option<R>,
    buffer: Vec<u8>,
    pos: usize,
    frame_end: Option<u8>,
}

impl <R> Reading<R> where R: ::std::io::Read {
    fn new(reader: R) -> Reading<R> {
        Reading {
            reader: Some(reader),
            buffer: Vec::new(),
            pos: 0,
            frame_end: None,
        }
    }
}

impl <R> Future for Reading<R> where R: ::std::io::Read {
    type Item = (Option<Vec<u8>>, R);
    type Error = ::std::io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            if let Some(frame_end) = self.frame_end {
                let n = try_nb!(self.reader.as_mut().unwrap().read(&mut self.buffer[self.pos..frame_end as usize]));
                self.pos += n;
                if self.pos == frame_end as usize {
                    self.pos = 0;
                    let result = ::std::mem::replace(&mut self.buffer, Vec::new());
                    self.frame_end = None;
                    return Ok(Async::Ready((Some(result), self.reader.take().unwrap())))
                }
            } else {
                let mut buf = [0u8];
                let n = try_nb!(self.reader.as_mut().unwrap().read(&mut buf));
                if n == 0 { // EOF
                    return Ok(Async::Ready((None, self.reader.take().unwrap())))
                }

                self.frame_end = Some(buf[0]);
                self.buffer = vec![0; buf[0] as usize];
            }
        }
    }
}

pub struct Writing<W> where W: ::std::io::Write {
    writer: Option<W>,
    message: Vec<u8>,
    pos: usize,
    wrote_header: bool,
}

impl <W> Writing<W> where W: ::std::io::Write {
    fn new(writer: W, message: Vec<u8>) -> Writing<W> {
        Writing {
            writer: Some(writer),
            message: message,
            pos: 0,
            wrote_header: false,
        }
    }
}

impl <W> Future for Writing<W> where W: ::std::io::Write {
    type Item = W;
    type Error = ::std::io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        unimplemented!()
    }
}

fn new_task(handle: &::tokio_core::reactor::Handle,
            addr: &::std::net::SocketAddr) -> Box<Future<Item=(), Error=::std::io::Error> + Send> {
    let publisher = ::tokio_core::net::TcpStream::connect(addr, handle);
    let mut subscribers = Vec::new();
    for _ in 0..3 {
        subscribers.push(::tokio_core::net::TcpStream::connect(addr, handle));
    }
    Box::new(publisher.join(::all::All::new(subscribers.into_iter())).and_then(|(publisher, subscribers)| {
        println!("connected");

        tie_knot((publisher, subscribers, 10), |(publisher, subscribers, n)| {
            println!("looping {}", n);
            futures::finished(((publisher, subscribers, n - 1), n > 0))
        }).map(|_| ())
    }))
}

pub fn run() -> Result<(), ::std::io::Error> {
    use clap::{App, Arg};
    let matches = App::new("Zillions benchmarker")
        .version("0.0.0")
        .about("Does awesome things")
        .arg(Arg::with_name("EXECUTABLE")
             .required(true)
             .index(1)
             .help("The executable to benchmark"))
        .get_matches();

    let executable = matches.value_of("EXECUTABLE").unwrap();

    println!("exectuable: {}", executable);

    let addr_str = "127.0.0.1:8080";
    let addr = match addr_str.parse::<::std::net::SocketAddr>() {
        Ok(a) => a,
        Err(e) => {
            panic!("failed to parse socket address {}", e);
        }
    };

    let _child = ::std::process::Command::new(executable)
        .arg(addr_str)
        .spawn();

    // start tokio reactor
    let mut core = try!(::tokio_core::reactor::Core::new());

    let handle = core.handle();

    let pool = ::futures_cpupool::CpuPool::new_num_cpus();

    let f = pool.spawn(new_task(&handle, &addr));

    try!(core.run(f));

    Ok(())
}

pub fn main() {
    run().expect("top level error");
}
<commit_msg>impl Future for Writing<commit_after>extern crate byteorder;
extern crate clap;

#[macro_use]
extern crate futures;
extern crate futures_cpupool;

#[macro_use]
extern crate tokio_core;

use futures::{Async, Poll, Future};

mod all {
    use futures::{Async, Poll, Future};
    enum ElemState<T> where T: Future {
        Pending(T),
        Done(T::Item),
    }

    pub struct All<T> where T: Future {
        elems: Vec<ElemState<T>>,
    }

    impl <T> All<T> where T: Future {
        pub fn new<I>(futures: I) -> All<T> where I: Iterator<Item=T> {
            let mut result = All { elems: Vec::new() };
            for f in futures {
                result.elems.push(ElemState::Pending(f))
            }
            result
        }
    }

    impl <T> Future for All<T> where T: Future {
        type Item = Vec<T::Item>;
        type Error = T::Error;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            let mut all_done = true;

            for idx in 0 .. self.elems.len() {
                let done_val = match &mut self.elems[idx] {
                    &mut ElemState::Pending(ref mut t) => {
                        match t.poll() {
                            Ok(Async::Ready(t)) => t,
                            Ok(Async::NotReady) => {
                                all_done = false;
                                continue
                            }
                            Err(e) => return Err(e),
                        }
                    }
                    &mut ElemState::Done(ref mut _v) => continue,
                };

                self.elems[idx] = ElemState::Done(done_val);
            }

            if all_done {
                let mut result = Vec::new();
                let elems = ::std::mem::replace(&mut self.elems, Vec::new());
                for e in elems.into_iter() {
                    match e {
                        ElemState::Done(t) => result.push(t),
                        _ => unreachable!(),
                    }
                }
                Ok(Async::Ready(result))
            } else {
                Ok(Async::NotReady)
            }
        }
    }
}

struct Knot<F, S, T, E>
    where F: Fn(S) -> T,
          T: Future<Item=(S, bool), Error=E>
{
    f: F,
    in_progress: T,
}

fn tie_knot<F, S, T, E>(initial_state: S, f: F) -> Knot<F, S, T, E>
    where F: Fn(S) -> T,
          T: Future<Item=(S, bool), Error=E>,
{
    let in_progress = f(initial_state);
    Knot {
        f: f,
        in_progress: in_progress,
    }
}

impl <F, S, T, E> Future for Knot<F, S, T, E>
    where F: Fn(S) -> T,
          T: Future<Item=(S, bool), Error=E>
{
    type Item = S;
    type Error = E;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            let (s, more) = try_ready!(self.in_progress.poll());
            if more {
                self.in_progress = (self.f)(s);
            } else {
                return Ok(Async::Ready(s))
            }
        }
    }
}

struct Reading<R> where R: ::std::io::Read {
    reader: Option<R>,
    buffer: Vec<u8>,
    pos: usize,
    frame_end: Option<u8>,
}

impl <R> Reading<R> where R: ::std::io::Read {
    fn new(reader: R) -> Reading<R> {
        Reading {
            reader: Some(reader),
            buffer: Vec::new(),
            pos: 0,
            frame_end: None,
        }
    }
}

impl <R> Future for Reading<R> where R: ::std::io::Read {
    type Item = (Option<Vec<u8>>, R);
    type Error = ::std::io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            if let Some(frame_end) = self.frame_end {
                let n = try_nb!(self.reader.as_mut().unwrap().read(&mut self.buffer[self.pos..frame_end as usize]));
                self.pos += n;
                if self.pos == frame_end as usize {
                    self.pos = 0;
                    let result = ::std::mem::replace(&mut self.buffer, Vec::new());
                    self.frame_end = None;
                    return Ok(Async::Ready((Some(result), self.reader.take().unwrap())))
                }
            } else {
                let mut buf = [0u8];
                let n = try_nb!(self.reader.as_mut().unwrap().read(&mut buf));
                if n == 0 { // EOF
                    return Ok(Async::Ready((None, self.reader.take().unwrap())))
                }

                self.frame_end = Some(buf[0]);
                self.buffer = vec![0; buf[0] as usize];
            }
        }
    }
}

pub struct Writing<W> where W: ::std::io::Write {
    writer: Option<W>,
    message: Vec<u8>,
    pos: usize,
    wrote_header: bool,
}

impl <W> Writing<W> where W: ::std::io::Write {
    fn new(writer: W, message: Vec<u8>) -> Writing<W> {
        Writing {
            writer: Some(writer),
            message: message,
            pos: 0,
            wrote_header: false,
        }
    }
}

impl <W> Future for Writing<W> where W: ::std::io::Write {
    type Item = W;
    type Error = ::std::io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            if !self.wrote_header {
                let buf = [self.message.len() as u8];
                try_nb!(self.writer.as_mut().unwrap().write(&buf));
            } else {
                let n = try_nb!(self.writer.as_mut().unwrap().write(&self.message[self.pos..]));
                self.pos += n;
                if self.pos >= self.message.len() {
                    return Ok(Async::Ready(self.writer.take().unwrap()))
                }
            }
        }
    }
}

fn new_task(handle: &::tokio_core::reactor::Handle,
            addr: &::std::net::SocketAddr) -> Box<Future<Item=(), Error=::std::io::Error> + Send> {
    let publisher = ::tokio_core::net::TcpStream::connect(addr, handle);
    let mut subscribers = Vec::new();
    for _ in 0..3 {
        subscribers.push(::tokio_core::net::TcpStream::connect(addr, handle));
    }
    Box::new(publisher.join(::all::All::new(subscribers.into_iter())).and_then(|(publisher, subscribers)| {
        println!("connected");

// TODO
//        publisher.write_all([0]).join(::all::All::new(subscibers.into_iter()))

        tie_knot((publisher, subscribers, 10u32), |(publisher, subscribers, n)| {
            Writing::new(publisher, vec![n as u8, 1,2,3]).and_then(move |publisher| {
                println!("looping {}", n);
                futures::finished(((publisher, subscribers, n - 1), n > 0))
            })
        }).map(|_| ())
    }))
}

pub fn run() -> Result<(), ::std::io::Error> {
    use clap::{App, Arg};
    let matches = App::new("Zillions benchmarker")
        .version("0.0.0")
        .about("Does awesome things")
        .arg(Arg::with_name("EXECUTABLE")
             .required(true)
             .index(1)
             .help("The executable to benchmark"))
        .get_matches();

    let executable = matches.value_of("EXECUTABLE").unwrap();

    println!("exectuable: {}", executable);

    let addr_str = "127.0.0.1:8080";
    let addr = match addr_str.parse::<::std::net::SocketAddr>() {
        Ok(a) => a,
        Err(e) => {
            panic!("failed to parse socket address {}", e);
        }
    };

    let _child = ::std::process::Command::new(executable)
        .arg(addr_str)
        .spawn();

    // start tokio reactor
    let mut core = try!(::tokio_core::reactor::Core::new());

    let handle = core.handle();

    let pool = ::futures_cpupool::CpuPool::new_num_cpus();

    let f = pool.spawn(new_task(&handle, &addr));

    try!(core.run(f));

    Ok(())
}

pub fn main() {
    run().expect("top level error");
}
<|endoftext|>


<commit_before>use std::sync::{Mutex, Arc};
use std::sync::atomics::{AtomicUint, SeqCst};

pub struct EWMA {
    pub uncounted: AtomicUint, // This tracks uncounted events
    alpha: f64,
    rate: Mutex<f64>,
    init: bool,
}

pub struct EWMASnapshot {
    value: f64
}

impl EWMASnapshot {
    fn rate(&self) -> f64 {
        return self.value;
    }
}

impl EWMA {
    pub fn rate(&self) -> f64 {
        let r = self.rate.lock();
        *r * (1e9 as f64)
    }

    pub fn snapshot(&self) -> EWMASnapshot {
        return EWMASnapshot{ value: self.rate() };
    }

    pub fn tick(&mut self) {
        let counter: uint = self.uncounted.load(SeqCst);

        self.uncounted.fetch_sub(counter, SeqCst); // Broken atm

        let mut rate = self.rate.lock();
        let i_rate = (counter as f64) / (5e9);

        if self.init {
            *rate += self.alpha * (i_rate - *rate);
        } else {
            self.init = true;
            *rate = i_rate;
        }

        rate.cond.signal();
    }

    pub fn update(&self, n: uint) {
        self.uncounted.fetch_add(n, SeqCst);
    }
}

// Construct a new EWMA with a mutex etc.
pub fn new(alpha: f64) -> EWMA {
    return EWMA{
        uncounted: AtomicUint::new(0u),
        alpha: alpha,
        rate: Mutex::new(0f64),
        init: false,
    }
}

#[cfg(test)]
mod test {
    use ewma;
    use std::num::Float;

    // Tick a minute
    fn elapse_minute(e: &mut ewma::EWMA) {
        for i in range(0i, 12i) {
            e.tick();
        }
    }

    // Returns whether the rate() is within 0.0001 of expected after ticking a minute
    fn within(e: &mut ewma::EWMA, expected: f64) -> bool {
        elapse_minute(e);
        let r: f64 = e.rate();
        (r - expected).abs() < 0.0001
    }

    #[test]
    fn ewma1() {
        let i = -5.0f64/60.0f64/1f64;
        let mut e = ewma::new(1f64 - i.exp());
        e.update(3u);
        e.tick();

        let mut r: f64;

        // initial
        r = e.rate();
        assert_eq!(r, 0.6f64);

        // 1 minute
        assert_eq!(within(&mut e, 0.22072766470286553f64), true);

        // 2 minute
        assert_eq!(within(&mut e, 0.08120116994196772f64), true);

        // 3 minute
        assert_eq!(within(&mut e, 0.029872241020718428f64), true);

        // 4 minute
        assert_eq!(within(&mut e, 0.01098938333324054f64), true);

        // 5 minute
        assert_eq!(within(&mut e, 0.004042768199451294f64), true);

        // 6 minute
        assert_eq!(within(&mut e, 0.0014872513059998212f64), true);

        // 7 minute
        assert_eq!(within(&mut e, 0.0005471291793327122f64), true);

        // 8 minute
        assert_eq!(within(&mut e, 0.00020127757674150815f64), true);

        // 9 minute
        assert_eq!(within(&mut e, 7.404588245200814e-05f64), true);

        // 10 minute
        assert_eq!(within(&mut e, 2.7239957857491083e-05f64), true);

        // 11 minute
        assert_eq!(within(&mut e, 1.0021020474147462e-05f64), true);

        // 12 minute
        assert_eq!(within(&mut e, 3.6865274119969525e-06f64), true);

        // 13 minute
        assert_eq!(within(&mut e, 1.3561976441886433e-06f64), true);

        // 14 minute
        assert_eq!(within(&mut e, 4.989172314621449e-07f64), true);

        // 15 minute
        assert_eq!(within(&mut e, 1.8354139230109722e-07f64), true);
    }

    #[test]
    fn ewma5() {
        let i = -5.0f64/60.0f64/5f64;
        let mut e = ewma::new(1f64 - i.exp());
        e.update(3u);
        e.tick();

        let r: f64 = e.rate();
        assert_eq!(r, 0.6f64);

        // 1 minute
        assert_eq!(within(&mut e, 0.49123845184678905f64), true);

                // 2 minute
        assert_eq!(within(&mut e, 0.4021920276213837f64), true);

        // 3 minute
        assert_eq!(within(&mut e, 0.32928698165641596f64), true);

        // 4 minute
        assert_eq!(within(&mut e, 0.269597378470333f64), true);

        // 5 minute
        assert_eq!(within(&mut e, 0.2207276647028654f64), true);

        // 6 minute
        assert_eq!(within(&mut e, 0.18071652714732128f64), true);

        // 7 minute
        assert_eq!(within(&mut e, 0.14795817836496392f64), true);

        // 8 minute
        assert_eq!(within(&mut e, 0.12113791079679326f64), true);

        // 9 minute
        assert_eq!(within(&mut e, 0.09917933293295193f64), true);

        // 10 minute
        assert_eq!(within(&mut e, 0.08120116994196763f64), true);

        // 11 minute
        assert_eq!(within(&mut e, 0.06648189501740036), true);

        // 12 minute
        assert_eq!(within(&mut e, 0.05443077197364752f64), true);

        // 13 minute
        assert_eq!(within(&mut e, 0.04456414692860035f64), true);

        // 14 minute
        assert_eq!(within(&mut e, 0.03648603757513079f64), true);

        // 15 minute
        assert_eq!(within(&mut e, 0.0298722410207183831020718428f64), true);
    }

        #[test]
    fn ewma15() {
        let i = -5.0f64/60.0f64/15f64;
        let mut e = ewma::new(1f64 - i.exp());
        e.update(3u);
        e.tick();

        let r: f64 = e.rate();
        assert_eq!(r, 0.6f64);

        // 1 minute
        assert_eq!(within(&mut e, 0.5613041910189706f64), true);

        // 2 minute
        assert_eq!(within(&mut e, 0.5251039914257684f64), true);

        // 3 minute
        assert_eq!(within(&mut e, 0.4912384518467888184678905f64), true);

        // 4 minute
        assert_eq!(within(&mut e, 0.459557003018789f64), true);

        // 5 minute
        assert_eq!(within(&mut e, 0.4299187863442732f64), true);

        // 6 minute
        assert_eq!(within(&mut e, 0.4021920276213831f64), true);

        // 7 minute
        assert_eq!(within(&mut e, 0.37625345116383313f64), true);

        // 8 minute
        assert_eq!(within(&mut e, 0.3519877317060185f64), true);

        // 9 minute
        assert_eq!(within(&mut e, 0.3292869816564153165641596f64), true);

        // 10 minute
        assert_eq!(within(&mut e, 0.3080502714195546f64), true);

        // 11 minute
        assert_eq!(within(&mut e, 0.2881831806538789f64), true);

        // 12 minute
        assert_eq!(within(&mut e, 0.26959737847033216f64), true);

        // 13 minute
        assert_eq!(within(&mut e, 0.2522102307052083f64), true);

        // 14 minute
        assert_eq!(within(&mut e, 0.23594443252115815f64), true);

        // 15 minute
        assert_eq!(within(&mut e, 0.2207276647028646247028654470286553f64), true);
    }
}<commit_msg>Move new() to inside impl<commit_after>use std::sync::{Mutex, Arc};
use std::sync::atomics::{AtomicUint, SeqCst};

pub struct EWMA {
    pub uncounted: AtomicUint, // This tracks uncounted events
    alpha: f64,
    rate: Mutex<f64>,
    init: bool,
}

pub struct EWMASnapshot {
    value: f64
}

impl EWMASnapshot {
    fn rate(&self) -> f64 {
        return self.value;
    }
}

impl EWMA {
    pub fn rate(&self) -> f64 {
        let r = self.rate.lock();
        *r * (1e9 as f64)
    }

    pub fn snapshot(&self) -> EWMASnapshot {
        return EWMASnapshot{ value: self.rate() };
    }

    pub fn tick(&mut self) {
        let counter: uint = self.uncounted.load(SeqCst);

        self.uncounted.fetch_sub(counter, SeqCst); // Broken atm

        let mut rate = self.rate.lock();
        let i_rate = (counter as f64) / (5e9);

        if self.init {
            *rate += self.alpha * (i_rate - *rate);
        } else {
            self.init = true;
            *rate = i_rate;
        }

        rate.cond.signal();
    }

    pub fn update(&self, n: uint) {
        self.uncounted.fetch_add(n, SeqCst);
    }

    pub fn new(alpha: f64) -> EWMA {
        return EWMA{
            uncounted: AtomicUint::new(0u),
            alpha: alpha,
            rate: Mutex::new(0f64),
            init: false,
        }
    }

}

#[cfg(test)]
mod test {
    use ewma::EWMA;
    use std::num::Float;

    // Tick a minute
    fn elapse_minute(e: &mut EWMA) {
        for i in range(0i, 12i) {
            e.tick();
        }
    }

    // Returns whether the rate() is within 0.0001 of expected after ticking a minute
    fn within(e: &mut EWMA, expected: f64) -> bool {
        elapse_minute(e);
        let r: f64 = e.rate();
        (r - expected).abs() < 0.0001
    }

    #[test]
    fn ewma1() {
        let i = -5.0f64/60.0f64/1f64;
        let mut e = EWMA::new(1f64 - i.exp());
        e.update(3u);
        e.tick();

        let mut r: f64;

        // initial
        r = e.rate();
        assert_eq!(r, 0.6f64);

        // 1 minute
        assert_eq!(within(&mut e, 0.22072766470286553f64), true);

        // 2 minute
        assert_eq!(within(&mut e, 0.08120116994196772f64), true);

        // 3 minute
        assert_eq!(within(&mut e, 0.029872241020718428f64), true);

        // 4 minute
        assert_eq!(within(&mut e, 0.01098938333324054f64), true);

        // 5 minute
        assert_eq!(within(&mut e, 0.004042768199451294f64), true);

        // 6 minute
        assert_eq!(within(&mut e, 0.0014872513059998212f64), true);

        // 7 minute
        assert_eq!(within(&mut e, 0.0005471291793327122f64), true);

        // 8 minute
        assert_eq!(within(&mut e, 0.00020127757674150815f64), true);

        // 9 minute
        assert_eq!(within(&mut e, 7.404588245200814e-05f64), true);

        // 10 minute
        assert_eq!(within(&mut e, 2.7239957857491083e-05f64), true);

        // 11 minute
        assert_eq!(within(&mut e, 1.0021020474147462e-05f64), true);

        // 12 minute
        assert_eq!(within(&mut e, 3.6865274119969525e-06f64), true);

        // 13 minute
        assert_eq!(within(&mut e, 1.3561976441886433e-06f64), true);

        // 14 minute
        assert_eq!(within(&mut e, 4.989172314621449e-07f64), true);

        // 15 minute
        assert_eq!(within(&mut e, 1.8354139230109722e-07f64), true);
    }

    #[test]
    fn ewma5() {
        let i = -5.0f64/60.0f64/5f64;
        let mut e = EWMA::new(1f64 - i.exp());
        e.update(3u);
        e.tick();

        let r: f64 = e.rate();
        assert_eq!(r, 0.6f64);

        // 1 minute
        assert_eq!(within(&mut e, 0.49123845184678905f64), true);

                // 2 minute
        assert_eq!(within(&mut e, 0.4021920276213837f64), true);

        // 3 minute
        assert_eq!(within(&mut e, 0.32928698165641596f64), true);

        // 4 minute
        assert_eq!(within(&mut e, 0.269597378470333f64), true);

        // 5 minute
        assert_eq!(within(&mut e, 0.2207276647028654f64), true);

        // 6 minute
        assert_eq!(within(&mut e, 0.18071652714732128f64), true);

        // 7 minute
        assert_eq!(within(&mut e, 0.14795817836496392f64), true);

        // 8 minute
        assert_eq!(within(&mut e, 0.12113791079679326f64), true);

        // 9 minute
        assert_eq!(within(&mut e, 0.09917933293295193f64), true);

        // 10 minute
        assert_eq!(within(&mut e, 0.08120116994196763f64), true);

        // 11 minute
        assert_eq!(within(&mut e, 0.06648189501740036), true);

        // 12 minute
        assert_eq!(within(&mut e, 0.05443077197364752f64), true);

        // 13 minute
        assert_eq!(within(&mut e, 0.04456414692860035f64), true);

        // 14 minute
        assert_eq!(within(&mut e, 0.03648603757513079f64), true);

        // 15 minute
        assert_eq!(within(&mut e, 0.0298722410207183831020718428f64), true);
    }

        #[test]
    fn ewma15() {
        let i = -5.0f64/60.0f64/15f64;
        let mut e = EWMA::new(1f64 - i.exp());
        e.update(3u);
        e.tick();

        let r: f64 = e.rate();
        assert_eq!(r, 0.6f64);

        // 1 minute
        assert_eq!(within(&mut e, 0.5613041910189706f64), true);

        // 2 minute
        assert_eq!(within(&mut e, 0.5251039914257684f64), true);

        // 3 minute
        assert_eq!(within(&mut e, 0.4912384518467888184678905f64), true);

        // 4 minute
        assert_eq!(within(&mut e, 0.459557003018789f64), true);

        // 5 minute
        assert_eq!(within(&mut e, 0.4299187863442732f64), true);

        // 6 minute
        assert_eq!(within(&mut e, 0.4021920276213831f64), true);

        // 7 minute
        assert_eq!(within(&mut e, 0.37625345116383313f64), true);

        // 8 minute
        assert_eq!(within(&mut e, 0.3519877317060185f64), true);

        // 9 minute
        assert_eq!(within(&mut e, 0.3292869816564153165641596f64), true);

        // 10 minute
        assert_eq!(within(&mut e, 0.3080502714195546f64), true);

        // 11 minute
        assert_eq!(within(&mut e, 0.2881831806538789f64), true);

        // 12 minute
        assert_eq!(within(&mut e, 0.26959737847033216f64), true);

        // 13 minute
        assert_eq!(within(&mut e, 0.2522102307052083f64), true);

        // 14 minute
        assert_eq!(within(&mut e, 0.23594443252115815f64), true);

        // 15 minute
        assert_eq!(within(&mut e, 0.2207276647028646247028654470286553f64), true);
    }
}<|endoftext|>


<commit_before>use std::fmt;
use std::ffi::CStr;
use { ffi, FtResult, GlyphSlot, Matrix, Vector };
use std::marker::PhantomData;

#[repr(u32)]
#[derive(Copy, Clone)]
pub enum KerningMode {
    KerningDefault  = ffi::FT_KERNING_DEFAULT,
    KerningUnfitted = ffi::FT_KERNING_UNFITTED,
    KerningUnscaled = ffi::FT_KERNING_UNSCALED
}

bitflags! {
    flags LoadFlag: i32 {
        const DEFAULT                    = ffi::FT_LOAD_DEFAULT,
        const NO_SCALE                   = ffi::FT_LOAD_NO_SCALE,
        const NO_HINTING                 = ffi::FT_LOAD_NO_HINTING,
        const RENDER                     = ffi::FT_LOAD_RENDER,
        const NO_BITMAP                  = ffi::FT_LOAD_NO_BITMAP,
        const VERTICAL_LAYOUT            = ffi::FT_LOAD_VERTICAL_LAYOUT,
        const FORCE_AUTOHINT             = ffi::FT_LOAD_FORCE_AUTOHINT,
        const CROP_BITMAP                = ffi::FT_LOAD_CROP_BITMAP,
        const PEDANTIC                   = ffi::FT_LOAD_PEDANTIC,
        const IGNORE_GLOBAL_ADVANCE_WITH = ffi::FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH,
        const NO_RECURSE                 = ffi::FT_LOAD_NO_RECURSE,
        const IGNORE_TRANSFORM           = ffi::FT_LOAD_IGNORE_TRANSFORM,
        const MONOCHROME                 = ffi::FT_LOAD_MONOCHROME,
        const LINEAR_DESIGN              = ffi::FT_LOAD_LINEAR_DESIGN,
        const NO_AUTOHINT                = ffi::FT_LOAD_NO_AUTOHINT,
        const TARGET_NORMAL              = ffi::FT_LOAD_TARGET_NORMAL,
        const TARGET_LIGHT               = ffi::FT_LOAD_TARGET_LIGHT,
        const TARGET_MONO                = ffi::FT_LOAD_TARGET_MONO,
        const TARGET_LCD                 = ffi::FT_LOAD_TARGET_LCD,
        const TARGET_LCD_V               = ffi::FT_LOAD_TARGET_LCD_V,
        const COLOR                      = ffi::FT_LOAD_COLOR
    }
}

#[derive(Eq, PartialEq, Hash)]
pub struct Face<'a> {
    library_raw: ffi::FT_Library,
    raw: ffi::FT_Face,
    glyph: GlyphSlot,
    _phantom: PhantomData<&'a ()>
}

impl<'a> Clone for Face<'a> {
    fn clone(&self) -> Self {
        let err = unsafe {
            ffi::FT_Reference_Library(self.library_raw)
        };
        if err != ffi::FT_Err_Ok {
            panic!("Failed to reference library");
        }
        let err = unsafe {
            ffi::FT_Reference_Face(self.raw)
        };
        if err != ffi::FT_Err_Ok {
            panic!("Failed to reference face");
        }
        Face { ..*self }
    }
}

impl<'a> Face<'a> {
    pub fn from_raw(library_raw: ffi::FT_Library, raw: ffi::FT_Face) -> Self {
        unsafe {
            ffi::FT_Reference_Library(library_raw);
        }
        Face {
            library_raw: library_raw,
            raw: raw,
            glyph: unsafe { GlyphSlot::from_raw(library_raw, (*raw).glyph) },
            _phantom: PhantomData
        }
    }

    pub fn attach_file(&self, filepathname: &str) -> FtResult<()> {
        let err = unsafe {
            ffi::FT_Attach_File(self.raw, filepathname.as_ptr() as *const _)
        };
        if err == ffi::FT_Err_Ok {
            Ok(())
        } else {
            Err(err.into())
        }
    }

    pub fn reference(&self) -> FtResult<()> {
        let err = unsafe {
            ffi::FT_Reference_Face(self.raw)
        };
        if err == ffi::FT_Err_Ok {
            Ok(())
        } else {
            Err(err.into())
        }
    }

    pub fn set_char_size(&self, char_width: isize, char_height: isize, horz_resolution: u32,
                         vert_resolution: u32) -> FtResult<()> {
        let err = unsafe {
            ffi::FT_Set_Char_Size(self.raw, char_width as ffi::FT_F26Dot6,
                                  char_height as ffi::FT_F26Dot6, horz_resolution,
                                  vert_resolution)
        };
        if err == ffi::FT_Err_Ok {
            Ok(())
        } else {
            Err(err.into())
        }
    }

    pub fn set_pixel_sizes(&self, pixel_width: u32, pixel_height: u32) -> FtResult<()> {
        let err = unsafe {
            ffi::FT_Set_Pixel_Sizes(self.raw, pixel_width, pixel_height)
        };
        if err == ffi::FT_Err_Ok {
            Ok(())
        } else {
            Err(err.into())
        }
    }

    pub fn load_glyph(&self, glyph_index: u32, load_flags: LoadFlag) -> FtResult<()> {
        let err = unsafe {
            ffi::FT_Load_Glyph(self.raw, glyph_index, load_flags.bits)
        };
        if err == ffi::FT_Err_Ok {
            Ok(())
        } else {
            Err(err.into())
        }
    }

    pub fn load_char(&self, char_code: usize, load_flags: LoadFlag) -> FtResult<()> {
        let err = unsafe {
            ffi::FT_Load_Char(self.raw, char_code as ffi::FT_ULong, load_flags.bits)
        };
        if err == ffi::FT_Err_Ok {
            Ok(())
        } else {
            Err(err.into())
        }
    }

    pub fn set_transform(&self, matrix: &mut Matrix, delta: &mut Vector) {
        unsafe {
            ffi::FT_Set_Transform(self.raw, matrix, delta);
        }
    }

    pub fn get_char_index(&self, charcode: usize) -> u32 {
        unsafe {
            ffi::FT_Get_Char_Index(self.raw, charcode as ffi::FT_ULong)
        }
    }

    pub fn get_kerning(&self, left_char_index: u32, right_char_index: u32, kern_mode: KerningMode)
        -> FtResult<Vector> {
        let mut vec = Vector { x: 0, y: 0 };

        let err = unsafe {
            ffi::FT_Get_Kerning(self.raw, left_char_index, right_char_index,
                                kern_mode as u32, &mut vec)
        };
        if err == ffi::FT_Err_Ok {
            Ok(vec)
        } else {
            Err(err.into())
        }
    }

    // According to FreeType doc, each time you load a new glyph image,
    // the previous one is erased from the glyph slot.
    #[inline(always)]
    pub fn glyph(&self) -> &GlyphSlot {
        &self.glyph
    }

    #[inline(always)]
    pub fn has_horizontal(&self) -> bool {
        ffi::FT_HAS_HORIZONTAL(self.raw)
    }

    #[inline(always)]
    pub fn has_vertical(&self) -> bool {
        ffi::FT_HAS_VERTICAL(self.raw)
    }

    #[inline(always)]
    pub fn has_kerning(&self) -> bool {
        ffi::FT_HAS_KERNING(self.raw)
    }

    #[inline(always)]
    pub fn is_scalable(&self) -> bool {
        ffi::FT_IS_SCALABLE(self.raw)
    }

    #[inline(always)]
    pub fn is_sfnt(&self) -> bool {
        ffi::FT_IS_SFNT(self.raw)
    }

    #[inline(always)]
    pub fn is_fixed_width(&self) -> bool {
        ffi::FT_IS_FIXED_WIDTH(self.raw)
    }

    #[inline(always)]
    pub fn has_fixed_sizes(&self) -> bool {
        ffi::FT_HAS_FIXED_SIZES(self.raw)
    }

    #[inline(always)]
    pub fn has_glyph_names(&self) -> bool {
        ffi::FT_HAS_GLYPH_NAMES(self.raw)
    }

    #[inline(always)]
    pub fn is_cid_keyed(&self) -> bool {
        ffi::FT_IS_CID_KEYED(self.raw)
    }

    #[inline(always)]
    pub fn is_tricky(&self) -> bool {
        ffi::FT_IS_TRICKY(self.raw)
    }

    #[inline(always)]
    pub fn has_color(&self) -> bool {
        ffi::FT_HAS_COLOR(self.raw)
    }

    #[inline(always)]
    pub fn raw(&self) -> &ffi::FT_FaceRec {
        unsafe {
            &*self.raw
        }
    }

    #[inline(always)]
    pub fn raw_mut(&mut self) -> &mut ffi::FT_FaceRec {
        unsafe {
            &mut *self.raw
        }
    }

    #[inline(always)]
    pub fn ascender(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ascender
        }
    }

    #[inline(always)]
    pub fn descender(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).descender
        }
    }

    #[inline(always)]
    pub fn em_size(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).units_per_EM as i16
        }
    }

    #[inline(always)]
    pub fn height(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).height
        }
    }

    #[inline(always)]
    pub fn max_advance_width(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).max_advance_width
        }
    }

    #[inline(always)]
    pub fn max_advance_height(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).max_advance_height
        }
    }

    #[inline(always)]
    pub fn underline_position(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).underline_position
        }
    }

    #[inline(always)]
    pub fn underline_thickness(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).underline_thickness
        }
    }

    pub fn family_name(&self) -> Option<String> {
        let family_name = unsafe { (*self.raw).family_name };

        if family_name.is_null() {
            None
        } else {
            let family_name = unsafe {
                CStr::from_ptr(family_name).to_bytes().to_vec()
            };
            String::from_utf8(family_name).ok()
        }
    }

    pub fn style_name(&self) -> Option<String> {
        let style_name = unsafe { (*self.raw).style_name };

        if style_name.is_null() {
            None
        } else {
            let style_name = unsafe {
                CStr::from_ptr(style_name).to_bytes().to_vec()
            };
            String::from_utf8(style_name).ok()
        }
    }

    pub fn size_metrics(&self) -> Option<ffi::FT_Size_Metrics> {
        if self.raw.is_null() {
            None
        } else {
            let size = unsafe { (*self.raw).size };
            if size.is_null() {
                None
            } else {
                Some(unsafe { (*size).metrics })
            }
        }
    }

    pub fn postscript_name(&self) -> Option<String> {
        let face_name = unsafe { ffi::FT_Get_Postscript_Name(self.raw) };
        if face_name.is_null() {
            None
        } else {
            let face_name = unsafe {
                CStr::from_ptr(face_name).to_bytes().to_vec()
            };
            String::from_utf8(face_name).ok()
        }
    }
}

impl<'a> fmt::Debug for Face<'a> {
    fn fmt(&self, form: &mut fmt::Formatter) -> fmt::Result {
        let name = self.style_name().unwrap_or("[unknown name]".to_owned());
        try!(form.write_str("Font Face: "));
        form.write_str(&name[..])
    }
}

impl<'a> Drop for Face<'a> {
    fn drop(&mut self) {
        let err = unsafe {
            ffi::FT_Done_Face(self.raw)
        };
        if err != ffi::FT_Err_Ok {
            panic!("Failed to drop face");
        }
        let err = unsafe {
            ffi::FT_Done_Library(self.library_raw)
        };
        if err != ffi::FT_Err_Ok {
            panic!("Failed to drop library")
        }
    }
}
<commit_msg>Update face.rs<commit_after>use std::fmt;
use std::ffi::CStr;
use { ffi, FtResult, GlyphSlot, Matrix, Vector };
use std::marker::PhantomData;

#[repr(u32)]
#[derive(Copy, Clone)]
pub enum KerningMode {
    KerningDefault  = ffi::FT_KERNING_DEFAULT,
    KerningUnfitted = ffi::FT_KERNING_UNFITTED,
    KerningUnscaled = ffi::FT_KERNING_UNSCALED
}

bitflags! {
    flags LoadFlag: i32 {
        const DEFAULT                    = ffi::FT_LOAD_DEFAULT,
        const NO_SCALE                   = ffi::FT_LOAD_NO_SCALE,
        const NO_HINTING                 = ffi::FT_LOAD_NO_HINTING,
        const RENDER                     = ffi::FT_LOAD_RENDER,
        const NO_BITMAP                  = ffi::FT_LOAD_NO_BITMAP,
        const VERTICAL_LAYOUT            = ffi::FT_LOAD_VERTICAL_LAYOUT,
        const FORCE_AUTOHINT             = ffi::FT_LOAD_FORCE_AUTOHINT,
        const CROP_BITMAP                = ffi::FT_LOAD_CROP_BITMAP,
        const PEDANTIC                   = ffi::FT_LOAD_PEDANTIC,
        const IGNORE_GLOBAL_ADVANCE_WITH = ffi::FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH,
        const NO_RECURSE                 = ffi::FT_LOAD_NO_RECURSE,
        const IGNORE_TRANSFORM           = ffi::FT_LOAD_IGNORE_TRANSFORM,
        const MONOCHROME                 = ffi::FT_LOAD_MONOCHROME,
        const LINEAR_DESIGN              = ffi::FT_LOAD_LINEAR_DESIGN,
        const NO_AUTOHINT                = ffi::FT_LOAD_NO_AUTOHINT,
        const TARGET_NORMAL              = ffi::FT_LOAD_TARGET_NORMAL,
        const TARGET_LIGHT               = ffi::FT_LOAD_TARGET_LIGHT,
        const TARGET_MONO                = ffi::FT_LOAD_TARGET_MONO,
        const TARGET_LCD                 = ffi::FT_LOAD_TARGET_LCD,
        const TARGET_LCD_V               = ffi::FT_LOAD_TARGET_LCD_V,
        const COLOR                      = ffi::FT_LOAD_COLOR
    }
}

#[derive(Eq, PartialEq, Hash)]
pub struct Face<'a> {
    library_raw: ffi::FT_Library,
    raw: ffi::FT_Face,
    glyph: GlyphSlot,
    _phantom: PhantomData<&'a ()>
}

impl<'a> Clone for Face<'a> {
    fn clone(&self) -> Self {
        let err = unsafe {
            ffi::FT_Reference_Library(self.library_raw)
        };
        if err != ffi::FT_Err_Ok {
            panic!("Failed to reference library");
        }
        let err = unsafe {
            ffi::FT_Reference_Face(self.raw)
        };
        if err != ffi::FT_Err_Ok {
            panic!("Failed to reference face");
        }
        Face { ..*self }
    }
}

impl<'a> Face<'a> {
    pub fn from_raw(library_raw: ffi::FT_Library, raw: ffi::FT_Face) -> Self {
        unsafe {
            ffi::FT_Reference_Library(library_raw);
        }
        Face {
            library_raw: library_raw,
            raw: raw,
            glyph: unsafe { GlyphSlot::from_raw(library_raw, (*raw).glyph) },
            _phantom: PhantomData
        }
    }

    pub fn attach_file(&self, filepathname: &str) -> FtResult<()> {
        let err = unsafe {
            ffi::FT_Attach_File(self.raw, filepathname.as_ptr() as *const _)
        };
        if err == ffi::FT_Err_Ok {
            Ok(())
        } else {
            Err(err.into())
        }
    }

    pub fn reference(&self) -> FtResult<()> {
        let err = unsafe {
            ffi::FT_Reference_Face(self.raw)
        };
        if err == ffi::FT_Err_Ok {
            Ok(())
        } else {
            Err(err.into())
        }
    }

    pub fn set_char_size(&self, char_width: isize, char_height: isize, horz_resolution: u32,
                         vert_resolution: u32) -> FtResult<()> {
        let err = unsafe {
            ffi::FT_Set_Char_Size(self.raw, char_width as ffi::FT_F26Dot6,
                                  char_height as ffi::FT_F26Dot6, horz_resolution,
                                  vert_resolution)
        };
        if err == ffi::FT_Err_Ok {
            Ok(())
        } else {
            Err(err.into())
        }
    }

    pub fn set_pixel_sizes(&self, pixel_width: u32, pixel_height: u32) -> FtResult<()> {
        let err = unsafe {
            ffi::FT_Set_Pixel_Sizes(self.raw, pixel_width, pixel_height)
        };
        if err == ffi::FT_Err_Ok {
            Ok(())
        } else {
            Err(err.into())
        }
    }

    pub fn load_glyph(&self, glyph_index: u32, load_flags: LoadFlag) -> FtResult<()> {
        let err = unsafe {
            ffi::FT_Load_Glyph(self.raw, glyph_index, load_flags.bits)
        };
        if err == ffi::FT_Err_Ok {
            Ok(())
        } else {
            Err(err.into())
        }
    }

    pub fn load_char(&self, char_code: usize, load_flags: LoadFlag) -> FtResult<()> {
        let err = unsafe {
            ffi::FT_Load_Char(self.raw, char_code as ffi::FT_ULong, load_flags.bits)
        };
        if err == ffi::FT_Err_Ok {
            Ok(())
        } else {
            Err(err.into())
        }
    }

    pub fn set_transform(&self, matrix: &mut Matrix, delta: &mut Vector) {
        unsafe {
            ffi::FT_Set_Transform(self.raw, matrix, delta);
        }
    }

    pub fn get_char_index(&self, charcode: usize) -> u32 {
        unsafe {
            ffi::FT_Get_Char_Index(self.raw, charcode as ffi::FT_ULong)
        }
    }

    pub fn get_kerning(&self, left_char_index: u32, right_char_index: u32, kern_mode: KerningMode)
        -> FtResult<Vector> {
        let mut vec = Vector { x: 0, y: 0 };

        let err = unsafe {
            ffi::FT_Get_Kerning(self.raw, left_char_index, right_char_index,
                                kern_mode as u32, &mut vec)
        };
        if err == ffi::FT_Err_Ok {
            Ok(vec)
        } else {
            Err(err.into())
        }
    }

    // According to FreeType doc, each time you load a new glyph image,
    // the previous one is erased from the glyph slot.
    #[inline(always)]
    pub fn glyph(&self) -> &GlyphSlot {
        &self.glyph
    }

    #[inline(always)]
    pub fn has_horizontal(&self) -> bool {
        ffi::FT_HAS_HORIZONTAL(self.raw)
    }

    #[inline(always)]
    pub fn has_vertical(&self) -> bool {
        ffi::FT_HAS_VERTICAL(self.raw)
    }

    #[inline(always)]
    pub fn has_kerning(&self) -> bool {
        ffi::FT_HAS_KERNING(self.raw)
    }

    #[inline(always)]
    pub fn is_scalable(&self) -> bool {
        ffi::FT_IS_SCALABLE(self.raw)
    }

    #[inline(always)]
    pub fn is_sfnt(&self) -> bool {
        ffi::FT_IS_SFNT(self.raw)
    }

    #[inline(always)]
    pub fn is_fixed_width(&self) -> bool {
        ffi::FT_IS_FIXED_WIDTH(self.raw)
    }

    #[inline(always)]
    pub fn has_fixed_sizes(&self) -> bool {
        ffi::FT_HAS_FIXED_SIZES(self.raw)
    }

    #[inline(always)]
    pub fn has_glyph_names(&self) -> bool {
        ffi::FT_HAS_GLYPH_NAMES(self.raw)
    }

    #[inline(always)]
    pub fn is_cid_keyed(&self) -> bool {
        ffi::FT_IS_CID_KEYED(self.raw)
    }

    #[inline(always)]
    pub fn is_tricky(&self) -> bool {
        ffi::FT_IS_TRICKY(self.raw)
    }

    #[inline(always)]
    pub fn has_color(&self) -> bool {
        ffi::FT_HAS_COLOR(self.raw)
    }

    #[inline(always)]
    pub fn raw(&self) -> &ffi::FT_FaceRec {
        unsafe {
            &*self.raw
        }
    }

    #[inline(always)]
    pub fn raw_mut(&mut self) -> &mut ffi::FT_FaceRec {
        unsafe {
            &mut *self.raw
        }
    }

    #[inline(always)]
    pub fn ascender(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ascender
        }
    }

    #[inline(always)]
    pub fn descender(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).descender
        }
    }

    #[inline(always)]
    pub fn em_size(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).units_per_EM as i16
        }
    }

    #[inline(always)]
    pub fn height(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).height
        }
    }

    #[inline(always)]
    pub fn max_advance_width(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).max_advance_width
        }
    }

    #[inline(always)]
    pub fn max_advance_height(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).max_advance_height
        }
    }

    #[inline(always)]
    pub fn underline_position(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).underline_position
        }
    }

    #[inline(always)]
    pub fn underline_thickness(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).underline_thickness
        }
    }

    pub fn family_name(&self) -> Option<String> {
        let family_name = unsafe { (*self.raw).family_name };

        if family_name.is_null() {
            None
        } else {
            let family_name = unsafe {
                CStr::from_ptr(family_name as *const _).to_bytes().to_vec()
            };
            String::from_utf8(family_name).ok()
        }
    }

    pub fn style_name(&self) -> Option<String> {
        let style_name = unsafe { (*self.raw).style_name };

        if style_name.is_null() {
            None
        } else {
            let style_name = unsafe {
                CStr::from_ptr(style_name as *const _).to_bytes().to_vec()
            };
            String::from_utf8(style_name).ok()
        }
    }

    pub fn size_metrics(&self) -> Option<ffi::FT_Size_Metrics> {
        if self.raw.is_null() {
            None
        } else {
            let size = unsafe { (*self.raw).size };
            if size.is_null() {
                None
            } else {
                Some(unsafe { (*size).metrics })
            }
        }
    }

    pub fn postscript_name(&self) -> Option<String> {
        let face_name = unsafe { ffi::FT_Get_Postscript_Name(self.raw) };
        if face_name.is_null() {
            None
        } else {
            let face_name = unsafe {
                CStr::from_ptr(face_name as *const _).to_bytes().to_vec()
            };
            String::from_utf8(face_name).ok()
        }
    }
}

impl<'a> fmt::Debug for Face<'a> {
    fn fmt(&self, form: &mut fmt::Formatter) -> fmt::Result {
        let name = self.style_name().unwrap_or("[unknown name]".to_owned());
        try!(form.write_str("Font Face: "));
        form.write_str(&name[..])
    }
}

impl<'a> Drop for Face<'a> {
    fn drop(&mut self) {
        let err = unsafe {
            ffi::FT_Done_Face(self.raw)
        };
        if err != ffi::FT_Err_Ok {
            panic!("Failed to drop face");
        }
        let err = unsafe {
            ffi::FT_Done_Library(self.library_raw)
        };
        if err != ffi::FT_Err_Ok {
            panic!("Failed to drop library")
        }
    }
}
<|endoftext|>


<commit_before>use std::env;

use cargo::ops::CompileOptions;
use cargo::ops;
use cargo::util::important_paths::{find_root_manifest_for_cwd};
use cargo::util::{CliResult, CliError, Config};

#[derive(RustcDecodable)]
struct Options {
    arg_opts: Option<Vec<String>>,
    flag_package: Option<String>,
    flag_jobs: Option<u32>,
    flag_features: Vec<String>,
    flag_no_default_features: bool,
    flag_target: Option<String>,
    flag_manifest_path: Option<String>,
    flag_verbose: bool,
    flag_quiet: bool,
    flag_release: bool,
    flag_lib: bool,
    flag_bin: Vec<String>,
    flag_example: Vec<String>,
    flag_test: Vec<String>,
    flag_bench: Vec<String>,
}

pub const USAGE: &'static str = "
Compile a package and all of its dependencies

Usage:
    cargo rustc [options] [--] [<opts>...]

Options:
    -h, --help               Print this message
    -p SPEC, --package SPEC  The profile to compile for
    -j N, --jobs N           The number of jobs to run in parallel
    --lib                    Build only this package's library
    --bin NAME               Build only the specified binary
    --example NAME           Build only the specified example
    --test NAME              Build only the specified test
    --bench NAME             Build only the specified benchmark
    --release                Build artifacts in release mode, with optimizations
    --features FEATURES      Features to compile for the package
    --no-default-features    Do not compile default features for the package
    --target TRIPLE          Target triple which compiles will be for
    --manifest-path PATH     Path to the manifest to fetch depednencies for
    -v, --verbose            Use verbose output
    -q, --quiet              No output printed to stdout

The specified target for the current package (or package specified by SPEC if
provided) will be compiled along with all of its dependencies. The specified
<opts>... will all be passed to the final compiler invocation, not any of the
dependencies. Note that the compiler will still unconditionally receive
arguments such as -L, --extern, and --crate-type, and the specified <opts>...
will simply be added to the compiler invocation.

This command requires that only one target is being compiled. If more than one
target is available for the current package the filters of --lib, --bin, etc,
must be used to select which target is compiled.
";

pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
    debug!("executing; cmd=cargo-rustc; args={:?}",
           env::args().collect::<Vec<_>>());
    try!(config.shell().set_verbosity(options.flag_verbose, options.flag_quiet));

    let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));

    let opts = CompileOptions {
        config: config,
        jobs: options.flag_jobs,
        target: options.flag_target.as_ref().map(|t| &t[..]),
        features: &options.flag_features,
        no_default_features: options.flag_no_default_features,
        spec: options.flag_package.as_ref().map(|s| &s[..]),
        exec_engine: None,
        mode: ops::CompileMode::Build,
        release: options.flag_release,
        filter: ops::CompileFilter::new(options.flag_lib,
                                        &options.flag_bin,
                                        &options.flag_test,
                                        &options.flag_example,
                                        &options.flag_bench),
        target_rustc_args: options.arg_opts.as_ref().map(|a| &a[..]),
    };

    ops::compile(&root, &opts).map(|_| None).map_err(|err| {
        CliError::from_boxed(err, 101)
    })
}

<commit_msg>Fix minor typo in `cargo rustc --help`.<commit_after>use std::env;

use cargo::ops::CompileOptions;
use cargo::ops;
use cargo::util::important_paths::{find_root_manifest_for_cwd};
use cargo::util::{CliResult, CliError, Config};

#[derive(RustcDecodable)]
struct Options {
    arg_opts: Option<Vec<String>>,
    flag_package: Option<String>,
    flag_jobs: Option<u32>,
    flag_features: Vec<String>,
    flag_no_default_features: bool,
    flag_target: Option<String>,
    flag_manifest_path: Option<String>,
    flag_verbose: bool,
    flag_quiet: bool,
    flag_release: bool,
    flag_lib: bool,
    flag_bin: Vec<String>,
    flag_example: Vec<String>,
    flag_test: Vec<String>,
    flag_bench: Vec<String>,
}

pub const USAGE: &'static str = "
Compile a package and all of its dependencies

Usage:
    cargo rustc [options] [--] [<opts>...]

Options:
    -h, --help               Print this message
    -p SPEC, --package SPEC  The profile to compile for
    -j N, --jobs N           The number of jobs to run in parallel
    --lib                    Build only this package's library
    --bin NAME               Build only the specified binary
    --example NAME           Build only the specified example
    --test NAME              Build only the specified test
    --bench NAME             Build only the specified benchmark
    --release                Build artifacts in release mode, with optimizations
    --features FEATURES      Features to compile for the package
    --no-default-features    Do not compile default features for the package
    --target TRIPLE          Target triple which compiles will be for
    --manifest-path PATH     Path to the manifest to fetch dependencies for
    -v, --verbose            Use verbose output
    -q, --quiet              No output printed to stdout

The specified target for the current package (or package specified by SPEC if
provided) will be compiled along with all of its dependencies. The specified
<opts>... will all be passed to the final compiler invocation, not any of the
dependencies. Note that the compiler will still unconditionally receive
arguments such as -L, --extern, and --crate-type, and the specified <opts>...
will simply be added to the compiler invocation.

This command requires that only one target is being compiled. If more than one
target is available for the current package the filters of --lib, --bin, etc,
must be used to select which target is compiled.
";

pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
    debug!("executing; cmd=cargo-rustc; args={:?}",
           env::args().collect::<Vec<_>>());
    try!(config.shell().set_verbosity(options.flag_verbose, options.flag_quiet));

    let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));

    let opts = CompileOptions {
        config: config,
        jobs: options.flag_jobs,
        target: options.flag_target.as_ref().map(|t| &t[..]),
        features: &options.flag_features,
        no_default_features: options.flag_no_default_features,
        spec: options.flag_package.as_ref().map(|s| &s[..]),
        exec_engine: None,
        mode: ops::CompileMode::Build,
        release: options.flag_release,
        filter: ops::CompileFilter::new(options.flag_lib,
                                        &options.flag_bin,
                                        &options.flag_test,
                                        &options.flag_example,
                                        &options.flag_bench),
        target_rustc_args: options.arg_opts.as_ref().map(|a| &a[..]),
    };

    ops::compile(&root, &opts).map(|_| None).map_err(|err| {
        CliError::from_boxed(err, 101)
    })
}

<|endoftext|>


<commit_before>use imgui::{Ui,ImStr,ImString};
use lichen::parse::{StreamParser,Env};

use std::fs;
use std::path::Path;

use app::AppState;

use std::io::{BufReader};
use std::fs::File;

pub struct FileState {
    /// MAX_PATH set to 260 chars
    cd: ImString,
    idx: i32,
    files: Vec<String>,
    selected: Option<String>,
    stream: Option<StreamParser<BufReader<File>>>,
    failed: String,
}

impl Default for FileState {
    fn default() -> Self {
        let mut cd = ImString::from(im_str!("./"));
        cd.reserve(261); //arbitrary max path size

        FileState {
            cd: cd,
            idx: 1,
            files: vec![],
            selected: None,
            stream: None,
            failed: "".to_owned(),
        }
    }
}

impl FileState {
    fn update(&mut self) -> Option<Env> {
        if self.idx > 0 { // chose a file?
            self.failed.clear();

            if let Some(file) = self.files.get(self.idx as usize) {
                self.cd.clear();
                self.cd.push_str(file);
                self.idx = -1;
            }
        }
        else if self.idx == 0 { // up a directory?
            self.failed.clear();
            self.to_parent();
        }

        let cd = self.cd.to_string();
        if Path::new(&cd).is_dir() {
            if let Ok(paths) = fs::read_dir(&cd) {
                self.files = paths
                    .filter(|p| p.is_ok())
                    .map(|p| {
                        p.unwrap().path().as_path().to_str().unwrap().to_owned()
                    })
                    .collect();

                //self.files.insert(0,"./".to_owned());
                self.files.insert(0,"..".to_owned());
            }
            // NOTE: we should throw a warning here if directory cannot be traversed
        }
        else {
            if !cd.is_empty() {
                self.selected = Some(cd);
            }
        }

        if self.stream.is_some() {
            let r = self.step_stream();
            if !self.failed.is_empty() {
                self.stream = None;
            }
            r
        }
        else { None }
    }

    /// Steps through the stream chunks, finally returns parsed lichen environment
    fn step_stream (&mut self) -> Option<Env> {
        let r = {
            if let Some(ref mut stream) = self.stream {
                stream.next()
            }
            else { None }
        };

        if r.is_none() { // close stream, we're probably done
            let mut env = Env::empty();
            if let Some(ref mut stream) = self.stream {
                if let Err(e) = stream.sink(&mut env) {
                    self.failed = e.to_owned();
                    return None;
                }
            }

            self.stream = None;
            self.to_parent();

            return Some(env);
        }

        None
    }

    fn to_parent(&mut self) {
        self.selected = None;
        if let Some(path) = Path::new(&self.cd.to_string()).parent() {
            self.cd.clear();
            self.cd.push_str(path.to_str().expect("ERROR: Cannot parse path into string"));
            self.idx = -1;
        }
        // NOTE: this fails if we're at the top of a relative directory listing,
        // or the root of the drive/share
    }

    pub fn render (&mut self, ui: &Ui, state: &mut AppState) {
        if !state.open_file { return }
        state.env = self.update(); // NOTE: we should check if the environment is empty
        state.open_file = !state.env.is_some(); // close file if done

        ui.window(im_str!("Select source"))
            .always_auto_resize(true)
            .movable(true)
            .show_borders(true)
            .opened(&mut state.open_file)
            .build(||{
                ui.text(im_str!("Select a source file to be parsed and evaluated.\nSource files must be parsable through the lichen crate."));
                ui.separator();
                ui.input_text(im_str!("Current Directory"), &mut self.cd)
                    .enter_returns_true(true)
                    .build();
                ui.separator();

                // NOTE: to appease the borrow checker and have the proper argument for list_box
                // we must build the list in two steps
                let paths: Vec<ImString> = self.files.iter().map(|p| {
                    im_str!("{:}", p).to_owned()
                }).collect();

                let paths: Vec<&ImStr> = paths.iter().map(|p|p.as_ref()).collect();

                ui.list_box(im_str!("Files"),
                            &mut self.idx,
                            &paths[..],
                            paths.len() as i32);

                if let Some(ref file) = self.selected {
                    ui.text(im_str!("Select File {:}?",file));

                    if ui.small_button(im_str!("open")) {
                        if let Ok(f) = File::open(file) {
                            let f = BufReader::new(f);
                            let s = StreamParser::new(f,None);
                            self.stream = Some(s);
                        }
                    }
                }

                if !self.failed.is_empty() {
                    ui.text(im_str!("Failed to parse file {:}\nParse Error at: {:}",
                                    &self.cd.to_str(), &self.failed));
                }
            })
    }

}

<commit_msg>remove<commit_after>use imgui::{Ui,ImStr,ImString};
use lichen::parse::{StreamParser,Env};

use std::fs;
use std::path::Path;

use app::AppState;

use std::io::{BufReader};
use std::fs::File;

pub struct FileState {
    /// MAX_PATH set to 260 chars
    cd: ImString,
    idx: i32,
    files: Vec<String>,
    selected: Option<String>,
    stream: Option<StreamParser<BufReader<File>>>,
    failed: String,
}

impl Default for FileState {
    fn default() -> Self {
        let mut cd = ImString::from(im_str!("./"));
        cd.reserve(261); //arbitrary max path size

        FileState {
            cd: cd,
            idx: 1,
            files: vec![],
            selected: None,
            stream: None,
            failed: "".to_owned(),
        }
    }
}

impl FileState {
    fn update(&mut self) -> Option<Env> {
        if self.idx > 0 { // chose a file?
            self.failed.clear();

            if let Some(file) = self.files.get(self.idx as usize) {
                self.cd.clear();
                self.cd.push_str(file);
                self.idx = -1;
            }
        }
        else if self.idx == 0 { // up a directory?
            self.failed.clear();
            self.to_parent();
        }

        let cd = self.cd.to_string();
        if Path::new(&cd).is_dir() {
            if let Ok(paths) = fs::read_dir(&cd) {
                self.files = paths
                    .filter(|p| p.is_ok())
                    .map(|p| {
                        p.unwrap().path().as_path().to_str().unwrap().to_owned()
                    })
                    .collect();

                self.files.insert(0,"..".to_owned());
            }
            // NOTE: we should throw a warning here if directory cannot be traversed
        }
        else {
            if !cd.is_empty() {
                self.selected = Some(cd);
            }
        }

        if self.stream.is_some() {
            let r = self.step_stream();
            if !self.failed.is_empty() {
                self.stream = None;
            }
            r
        }
        else { None }
    }

    /// Steps through the stream chunks, finally returns parsed lichen environment
    fn step_stream (&mut self) -> Option<Env> {
        let r = {
            if let Some(ref mut stream) = self.stream {
                stream.next()
            }
            else { None }
        };

        if r.is_none() { // close stream, we're probably done
            let mut env = Env::empty();
            if let Some(ref mut stream) = self.stream {
                if let Err(e) = stream.sink(&mut env) {
                    self.failed = e.to_owned();
                    return None;
                }
            }

            self.stream = None;
            self.to_parent();

            return Some(env);
        }

        None
    }

    fn to_parent(&mut self) {
        self.selected = None;
        if let Some(path) = Path::new(&self.cd.to_string()).parent() {
            self.cd.clear();
            self.cd.push_str(path.to_str().expect("ERROR: Cannot parse path into string"));
            self.idx = -1;
        }
        // NOTE: this fails if we're at the top of a relative directory listing,
        // or the root of the drive/share
    }

    pub fn render (&mut self, ui: &Ui, state: &mut AppState) {
        if !state.open_file { return }
        state.env = self.update(); // NOTE: we should check if the environment is empty
        state.open_file = !state.env.is_some(); // close file if done

        ui.window(im_str!("Select source"))
            .always_auto_resize(true)
            .movable(true)
            .show_borders(true)
            .opened(&mut state.open_file)
            .build(||{
                ui.text(im_str!("Select a source file to be parsed and evaluated.\nSource files must be parsable through the lichen crate."));
                ui.separator();
                ui.input_text(im_str!("Current Directory"), &mut self.cd)
                    .enter_returns_true(true)
                    .build();
                ui.separator();

                // NOTE: to appease the borrow checker and have the proper argument for list_box
                // we must build the list in two steps
                let paths: Vec<ImString> = self.files.iter().map(|p| {
                    im_str!("{:}", p).to_owned()
                }).collect();

                let paths: Vec<&ImStr> = paths.iter().map(|p|p.as_ref()).collect();

                ui.list_box(im_str!("Files"),
                            &mut self.idx,
                            &paths[..],
                            paths.len() as i32);

                if let Some(ref file) = self.selected {
                    ui.text(im_str!("Select File {:}?",file));

                    if ui.small_button(im_str!("open")) {
                        if let Ok(f) = File::open(file) {
                            let f = BufReader::new(f);
                            let s = StreamParser::new(f,None);
                            self.stream = Some(s);
                        }
                    }
                }

                if !self.failed.is_empty() {
                    ui.text(im_str!("Failed to parse file {:}\nParse Error at: {:}",
                                    &self.cd.to_str(), &self.failed));
                }
            })
    }

}

<|endoftext|>


<commit_before>#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Export {
    pub name: String,
    pub func: String,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum Expr {
    Add(Typ,Box<Expr>,Box<Expr>),
    Return(usize),
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Function {
    pub name: String,
    pub typ: FunctionTyp,
    pub locals: Vec<Var>,
    pub body: Vec<Expr>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct FunctionTyp {
    pub params: Vec<Var>,
    pub result: Option<Typ>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Import {
    pub func: String,
    pub module: String,
    pub name: String,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Memory {
    pub init: usize,
    pub max: Option<usize>,
    pub segments: Vec<Segment>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Module {
    pub memory: Option<Memory>,
    pub imports: Vec<Import>,
    pub exports: Vec<Export>,
    pub functions: Vec<Function>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Segment {
    pub addr: usize,
    pub data: String,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum Typ {
    I32,
    I64,
    F32,
    F64,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Var {
    pub name: String,
    pub typ: Typ,
}
<commit_msg>Added FunctionTyp to Import in AST.<commit_after>use parser::combinators::Consumer;

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Export {
    pub name: String,
    pub func: String,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum Expr {
    Add(Typ,Box<Expr>,Box<Expr>),
    Return(usize),
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Function {
    pub name: String,
    pub typ: FunctionTyp,
    pub locals: Vec<Var>,
    pub body: Vec<Expr>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct FunctionTyp {
    pub params: Vec<Var>,
    pub result: Option<Typ>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Import {
    pub func: String,
    pub module: String,
    pub name: String,
    pub typ: FunctionTyp,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Memory {
    pub init: usize,
    pub max: Option<usize>,
    pub segments: Vec<Segment>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Module {
    pub memory: Option<Memory>,
    pub imports: Vec<Import>,
    pub exports: Vec<Export>,
    pub functions: Vec<Function>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Segment {
    pub addr: usize,
    pub data: String,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum Typ {
    I32,
    I64,
    F32,
    F64,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Var {
    pub name: String,
    pub typ: Typ,
}
<|endoftext|>