<commit_before>/// This declares a list of types which can be allocated by `Arena`.
///
/// The `few` modifier will cause allocation to use the shared arena and recording the destructor.
/// This is faster and more memory efficient if there's only a few allocations of the type.
/// Leaving `few` out will cause the type to get its own dedicated `TypedArena` which is
/// faster and more memory efficient if there is lots of allocations.
///
/// Specifying the `decode` modifier will add decode impls for `&T` and `&[T]` where `T` is the type
/// listed. These impls will appear in the implement_ty_decoder! macro.
#[macro_export]
macro_rules! arena_types {
    ($macro:path, $args:tt, $tcx:lifetime) => (
        $macro!($args, [
            [] layouts: rustc_target::abi::Layout,
            // AdtDef are interned and compared by address
            [] adt_def: rustc_middle::ty::AdtDef,
            [decode] tables: rustc_middle::ty::TypeckTables<$tcx>,
            [] const_allocs: rustc_middle::mir::interpret::Allocation,
            // Required for the incremental on-disk cache
            [few, decode] mir_keys: rustc_hir::def_id::DefIdSet,
            [] region_scope_tree: rustc_middle::middle::region::ScopeTree,
            [] dropck_outlives:
                rustc_middle::infer::canonical::Canonical<'tcx,
                    rustc_middle::infer::canonical::QueryResponse<'tcx,
                        rustc_middle::traits::query::DropckOutlivesResult<'tcx>
                    >
                >,
            [] normalize_projection_ty:
                rustc_middle::infer::canonical::Canonical<'tcx,
                    rustc_middle::infer::canonical::QueryResponse<'tcx,
                        rustc_middle::traits::query::NormalizationResult<'tcx>
                    >
                >,
            [] implied_outlives_bounds:
                rustc_middle::infer::canonical::Canonical<'tcx,
                    rustc_middle::infer::canonical::QueryResponse<'tcx,
                        Vec<rustc_middle::traits::query::OutlivesBound<'tcx>>
                    >
                >,
            [] type_op_subtype:
                rustc_middle::infer::canonical::Canonical<'tcx,
                    rustc_middle::infer::canonical::QueryResponse<'tcx, ()>
                >,
            [] type_op_normalize_poly_fn_sig:
                rustc_middle::infer::canonical::Canonical<'tcx,
                    rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::PolyFnSig<'tcx>>
                >,
            [] type_op_normalize_fn_sig:
                rustc_middle::infer::canonical::Canonical<'tcx,
                    rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::FnSig<'tcx>>
                >,
            [] type_op_normalize_predicate:
                rustc_middle::infer::canonical::Canonical<'tcx,
                    rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Predicate<'tcx>>
                >,
            [] type_op_normalize_ty:
                rustc_middle::infer::canonical::Canonical<'tcx,
                    rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Ty<'tcx>>
                >,
            [few] all_traits: Vec<rustc_hir::def_id::DefId>,
            [few] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels,
            [few] foreign_module: rustc_middle::middle::cstore::ForeignModule,
            [few] foreign_modules: Vec<rustc_middle::middle::cstore::ForeignModule>,
            [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>,
            [] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation,
            [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<$tcx>,
            [] attribute: rustc_ast::ast::Attribute,
            [] name_set: rustc_data_structures::fx::FxHashSet<rustc_span::symbol::Symbol>,
            [] hir_id_set: rustc_hir::HirIdSet,

            // Interned types
            [] tys: rustc_middle::ty::TyS<$tcx>,

            // HIR query types
            [few] indexed_hir: rustc_middle::hir::map::IndexedHir<$tcx>,
            [few] hir_definitions: rustc_hir::definitions::Definitions,
            [] hir_owner: rustc_middle::hir::Owner<$tcx>,
            [] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>,

            // Note that this deliberately duplicates items in the `rustc_hir::arena`,
            // since we need to allocate this type on both the `rustc_hir` arena
            // (during lowering) and the `librustc_middle` arena (for decoding MIR)
            [decode] asm_template: rustc_ast::ast::InlineAsmTemplatePiece,

        ], $tcx);
    )
}

arena_types!(arena::declare_arena, [], 'tcx);
<commit_msg>Add Span to arena_types! for decoding &'tcx [Span]<commit_after>/// This declares a list of types which can be allocated by `Arena`.
///
/// The `few` modifier will cause allocation to use the shared arena and recording the destructor.
/// This is faster and more memory efficient if there's only a few allocations of the type.
/// Leaving `few` out will cause the type to get its own dedicated `TypedArena` which is
/// faster and more memory efficient if there is lots of allocations.
///
/// Specifying the `decode` modifier will add decode impls for `&T` and `&[T]` where `T` is the type
/// listed. These impls will appear in the implement_ty_decoder! macro.
#[macro_export]
macro_rules! arena_types {
    ($macro:path, $args:tt, $tcx:lifetime) => (
        $macro!($args, [
            [] layouts: rustc_target::abi::Layout,
            // AdtDef are interned and compared by address
            [] adt_def: rustc_middle::ty::AdtDef,
            [decode] tables: rustc_middle::ty::TypeckTables<$tcx>,
            [] const_allocs: rustc_middle::mir::interpret::Allocation,
            // Required for the incremental on-disk cache
            [few, decode] mir_keys: rustc_hir::def_id::DefIdSet,
            [] region_scope_tree: rustc_middle::middle::region::ScopeTree,
            [] dropck_outlives:
                rustc_middle::infer::canonical::Canonical<'tcx,
                    rustc_middle::infer::canonical::QueryResponse<'tcx,
                        rustc_middle::traits::query::DropckOutlivesResult<'tcx>
                    >
                >,
            [] normalize_projection_ty:
                rustc_middle::infer::canonical::Canonical<'tcx,
                    rustc_middle::infer::canonical::QueryResponse<'tcx,
                        rustc_middle::traits::query::NormalizationResult<'tcx>
                    >
                >,
            [] implied_outlives_bounds:
                rustc_middle::infer::canonical::Canonical<'tcx,
                    rustc_middle::infer::canonical::QueryResponse<'tcx,
                        Vec<rustc_middle::traits::query::OutlivesBound<'tcx>>
                    >
                >,
            [] type_op_subtype:
                rustc_middle::infer::canonical::Canonical<'tcx,
                    rustc_middle::infer::canonical::QueryResponse<'tcx, ()>
                >,
            [] type_op_normalize_poly_fn_sig:
                rustc_middle::infer::canonical::Canonical<'tcx,
                    rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::PolyFnSig<'tcx>>
                >,
            [] type_op_normalize_fn_sig:
                rustc_middle::infer::canonical::Canonical<'tcx,
                    rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::FnSig<'tcx>>
                >,
            [] type_op_normalize_predicate:
                rustc_middle::infer::canonical::Canonical<'tcx,
                    rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Predicate<'tcx>>
                >,
            [] type_op_normalize_ty:
                rustc_middle::infer::canonical::Canonical<'tcx,
                    rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Ty<'tcx>>
                >,
            [few] all_traits: Vec<rustc_hir::def_id::DefId>,
            [few] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels,
            [few] foreign_module: rustc_middle::middle::cstore::ForeignModule,
            [few] foreign_modules: Vec<rustc_middle::middle::cstore::ForeignModule>,
            [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>,
            [] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation,
            [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<$tcx>,
            [] attribute: rustc_ast::ast::Attribute,
            [] name_set: rustc_data_structures::fx::FxHashSet<rustc_span::symbol::Symbol>,
            [] hir_id_set: rustc_hir::HirIdSet,

            // Interned types
            [] tys: rustc_middle::ty::TyS<$tcx>,

            // HIR query types
            [few] indexed_hir: rustc_middle::hir::map::IndexedHir<$tcx>,
            [few] hir_definitions: rustc_hir::definitions::Definitions,
            [] hir_owner: rustc_middle::hir::Owner<$tcx>,
            [] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>,

            // Note that this deliberately duplicates items in the `rustc_hir::arena`,
            // since we need to allocate this type on both the `rustc_hir` arena
            // (during lowering) and the `librustc_middle` arena (for decoding MIR)
            [decode] asm_template: rustc_ast::ast::InlineAsmTemplatePiece,

            // This is used to decode the &'tcx [Span] for InlineAsm's line_spans.
            [decode] span: rustc_span::Span,
        ], $tcx);
    )
}

arena_types!(arena::declare_arena, [], 'tcx);
<|endoftext|>


<commit_before>// Portions of this file are Copyright 2014 The Rust Project Developers.
// See http://rust-lang.org/COPYRIGHT.

use libc;
use {Errno, Result};
use std::mem;
use std::ptr;

pub use libc::{
    SIGHUP,
    SIGINT,
    SIGQUIT,
    SIGILL,
    SIGABRT,
    SIGFPE,
    SIGKILL,
    SIGSEGV,
    SIGPIPE,
    SIGALRM,
    SIGTERM,
    SIGTRAP,
    SIGIOT,
    SIGBUS,
    SIGSYS,
    SIGURG,
    SIGSTOP,
    SIGTSTP,
    SIGCONT,
    SIGCHLD,
    SIGTTIN,
    SIGTTOU,
    SIGIO,
    SIGXCPU,
    SIGXFSZ,
    SIGVTALRM,
    SIGPROF,
    SIGWINCH,
    SIGUSR1,
    SIGUSR2,
};

// This doesn't always exist, but when it does, it's 7
pub const SIGEMT: libc::c_int = 7;

pub const NSIG: libc::c_int = 32;

bitflags!{
    flags SaFlags: libc::c_int {
        const SA_NOCLDSTOP = libc::SA_NOCLDSTOP,
        const SA_NOCLDWAIT = libc::SA_NOCLDWAIT,
        const SA_NODEFER   = libc::SA_NODEFER,
        const SA_ONSTACK   = libc::SA_ONSTACK,
        const SA_RESETHAND = libc::SA_RESETHAND,
        const SA_RESTART   = libc::SA_RESTART,
        const SA_SIGINFO   = libc::SA_SIGINFO,
    }
}

bitflags!{
    flags SigFlags: libc::c_int {
        const SIG_BLOCK   = libc::SIG_BLOCK,
        const SIG_UNBLOCK = libc::SIG_UNBLOCK,
        const SIG_SETMASK = libc::SIG_SETMASK,
    }
}

#[derive(Clone, Copy)]
pub struct SigSet {
    sigset: libc::sigset_t
}

pub type SigNum = libc::c_int;

impl SigSet {
    pub fn all() -> SigSet {
        let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
        let _ = unsafe { libc::sigfillset(&mut sigset as *mut libc::sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn empty() -> SigSet {
        let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
        let _ = unsafe { libc::sigemptyset(&mut sigset as *mut libc::sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn add(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signum) };

        Errno::result(res).map(drop)
    }

    pub fn remove(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signum) };

        Errno::result(res).map(drop)
    }

    pub fn contains(&self, signum: SigNum) -> Result<bool> {
        let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signum) };

        match try!(Errno::result(res)) {
            1 => Ok(true),
            0 => Ok(false),
            _ => unreachable!("unexpected value from sigismember"),
        }
    }

    /// Gets the currently blocked (masked) set of signals for the calling thread.
    pub fn thread_get_mask() -> Result<SigSet> {
        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
        try!(pthread_sigmask(SigFlags::empty(), None, Some(&mut oldmask)));
        Ok(oldmask)
    }

    /// Sets the set of signals as the signal mask for the calling thread.
    pub fn thread_set_mask(&self) -> Result<()> {
        pthread_sigmask(SIG_SETMASK, Some(self), None)
    }

    /// Adds the set of signals to the signal mask for the calling thread.
    pub fn thread_block(&self) -> Result<()> {
        pthread_sigmask(SIG_BLOCK, Some(self), None)
    }

    /// Removes the set of signals from the signal mask for the calling thread.
    pub fn thread_unblock(&self) -> Result<()> {
        pthread_sigmask(SIG_UNBLOCK, Some(self), None)
    }

    /// Sets the set of signals as the signal mask, and returns the old mask.
    pub fn thread_swap_mask(&self, how: SigFlags) -> Result<SigSet> {
        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
        try!(pthread_sigmask(how, Some(self), Some(&mut oldmask)));
        Ok(oldmask)
    }

    /// Suspends execution of the calling thread until one of the signals in the
    /// signal mask becomes pending, and returns the accepted signal.
    pub fn wait(&self) -> Result<SigNum> {
        let mut signum: SigNum = unsafe { mem::uninitialized() };
        let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, &mut signum) };

        Errno::result(res).map(|_| signum)
    }
}

impl AsRef<libc::sigset_t> for SigSet {
    fn as_ref(&self) -> &libc::sigset_t {
        &self.sigset
    }
}

#[allow(unknown_lints)]
#[cfg_attr(not(raw_pointer_derive_allowed), allow(raw_pointer_derive))]
#[derive(Clone, Copy, PartialEq)]
pub enum SigHandler {
    SigDfl,
    SigIgn,
    Handler(extern fn(SigNum)),
    SigAction(extern fn(SigNum, *mut libc::siginfo_t, *mut libc::c_void))
}

pub struct SigAction {
    sigaction: libc::sigaction
}

impl SigAction {
    /// This function will set or unset the flag `SA_SIGINFO` depending on the
    /// type of the `handler` argument.
    pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
        let mut s = unsafe { mem::uninitialized::<libc::sigaction>() };
        s.sa_sigaction = match handler {
            SigHandler::SigDfl => unsafe { mem::transmute(libc::SIG_DFL) },
            SigHandler::SigIgn => unsafe { mem::transmute(libc::SIG_IGN) },
            SigHandler::Handler(f) => unsafe { mem::transmute(f) },
            SigHandler::SigAction(f) => unsafe { mem::transmute(f) },
        };
        s.sa_flags = match handler {
            SigHandler::SigAction(_) => (flags | SA_SIGINFO).bits(),
            _ => (flags - SA_SIGINFO).bits(),
        };
        s.sa_mask = mask.sigset;

        SigAction { sigaction: s }
    }
}

pub unsafe fn sigaction(signum: SigNum, sigaction: &SigAction) -> Result<SigAction> {
    let mut oldact = mem::uninitialized::<libc::sigaction>();

    let res =
        libc::sigaction(signum, &sigaction.sigaction as *const libc::sigaction, &mut oldact as *mut libc::sigaction);

    Errno::result(res).map(|_| SigAction { sigaction: oldact })
}

/// Manages the signal mask (set of blocked signals) for the calling thread.
///
/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
/// and no modification will take place.
///
/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
///
/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
/// and then it will be updated with `set`.
///
/// If both `set` and `oldset` is None, this function is a no-op.
///
/// For more information, visit the [pthread_sigmask](http://man7.org/linux/man-pages/man3/pthread_sigmask.3.html),
/// or [sigprocmask](http://man7.org/linux/man-pages/man2/sigprocmask.2.html) man pages.
pub fn pthread_sigmask(how: SigFlags,
                       set: Option<&SigSet>,
                       oldset: Option<&mut SigSet>) -> Result<()> {
    if set.is_none() && oldset.is_none() {
        return Ok(())
    }

    let res = unsafe {
        // if set or oldset is None, pass in null pointers instead
        libc::pthread_sigmask(how.bits(),
                             set.map_or_else(|| ptr::null::<libc::sigset_t>(),
                                             |s| &s.sigset as *const libc::sigset_t),
                             oldset.map_or_else(|| ptr::null_mut::<libc::sigset_t>(),
                                                |os| &mut os.sigset as *mut libc::sigset_t))
    };

    Errno::result(res).map(drop)
}

pub fn kill(pid: libc::pid_t, signum: SigNum) -> Result<()> {
    let res = unsafe { libc::kill(pid, signum) };

    Errno::result(res).map(drop)
}

pub fn raise(signum: SigNum) -> Result<()> {
    let res = unsafe { libc::raise(signum) };

    Errno::result(res).map(drop)
}

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

    #[test]
    fn test_contains() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();

        assert_eq!(mask.contains(SIGUSR1), Ok(true));
        assert_eq!(mask.contains(SIGUSR2), Ok(false));

        let all = SigSet::all();
        assert_eq!(all.contains(SIGUSR1), Ok(true));
        assert_eq!(all.contains(SIGUSR2), Ok(true));
    }

    #[test]
    fn test_thread_signal_block() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();

        assert!(mask.thread_block().is_ok());
    }

    #[test]
    fn test_thread_signal_swap() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();
        mask.thread_block().unwrap();

        assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1).unwrap());

        let mask2 = SigSet::empty();
        mask.add(SIGUSR2).unwrap();

        let oldmask = mask2.thread_swap_mask(SIG_SETMASK).unwrap();

        assert!(oldmask.contains(SIGUSR1).unwrap());
        assert!(!oldmask.contains(SIGUSR2).unwrap());
    }

    // TODO(#251): Re-enable after figuring out flakiness.
    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    #[test]
    fn test_sigwait() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();
        mask.add(SIGUSR2).unwrap();
        mask.thread_block().unwrap();

        raise(SIGUSR1).unwrap();
        assert_eq!(mask.wait().unwrap(), SIGUSR1);
    }
}
<commit_msg>Add SigSet::extend and SigSet::clear.<commit_after>// Portions of this file are Copyright 2014 The Rust Project Developers.
// See http://rust-lang.org/COPYRIGHT.

use libc;
use {Errno, Result};
use std::mem;
use std::ptr;

pub use libc::{
    SIGHUP,
    SIGINT,
    SIGQUIT,
    SIGILL,
    SIGABRT,
    SIGFPE,
    SIGKILL,
    SIGSEGV,
    SIGPIPE,
    SIGALRM,
    SIGTERM,
    SIGTRAP,
    SIGIOT,
    SIGBUS,
    SIGSYS,
    SIGURG,
    SIGSTOP,
    SIGTSTP,
    SIGCONT,
    SIGCHLD,
    SIGTTIN,
    SIGTTOU,
    SIGIO,
    SIGXCPU,
    SIGXFSZ,
    SIGVTALRM,
    SIGPROF,
    SIGWINCH,
    SIGUSR1,
    SIGUSR2,
};

// This doesn't always exist, but when it does, it's 7
pub const SIGEMT: libc::c_int = 7;

pub const NSIG: libc::c_int = 32;

bitflags!{
    flags SaFlags: libc::c_int {
        const SA_NOCLDSTOP = libc::SA_NOCLDSTOP,
        const SA_NOCLDWAIT = libc::SA_NOCLDWAIT,
        const SA_NODEFER   = libc::SA_NODEFER,
        const SA_ONSTACK   = libc::SA_ONSTACK,
        const SA_RESETHAND = libc::SA_RESETHAND,
        const SA_RESTART   = libc::SA_RESTART,
        const SA_SIGINFO   = libc::SA_SIGINFO,
    }
}

bitflags!{
    flags SigFlags: libc::c_int {
        const SIG_BLOCK   = libc::SIG_BLOCK,
        const SIG_UNBLOCK = libc::SIG_UNBLOCK,
        const SIG_SETMASK = libc::SIG_SETMASK,
    }
}

#[derive(Clone, Copy)]
pub struct SigSet {
    sigset: libc::sigset_t
}

pub type SigNum = libc::c_int;

impl SigSet {
    pub fn all() -> SigSet {
        let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
        let _ = unsafe { libc::sigfillset(&mut sigset as *mut libc::sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn empty() -> SigSet {
        let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
        let _ = unsafe { libc::sigemptyset(&mut sigset as *mut libc::sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn add(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signum) };

        Errno::result(res).map(drop)
    }

    pub fn clear(&mut self) -> Result<()> {
        let res = unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };

        Errno::result(res).map(drop)
    }

    pub fn remove(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signum) };

        Errno::result(res).map(drop)
    }

    pub fn extend(&mut self, other: &SigSet) -> Result<()> {
        for i in 1..NSIG {
            if try!(other.contains(i)) {
                try!(self.add(i));
            }
        }
        Ok(())
    }

    pub fn contains(&self, signum: SigNum) -> Result<bool> {
        let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signum) };

        match try!(Errno::result(res)) {
            1 => Ok(true),
            0 => Ok(false),
            _ => unreachable!("unexpected value from sigismember"),
        }
    }

    /// Gets the currently blocked (masked) set of signals for the calling thread.
    pub fn thread_get_mask() -> Result<SigSet> {
        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
        try!(pthread_sigmask(SigFlags::empty(), None, Some(&mut oldmask)));
        Ok(oldmask)
    }

    /// Sets the set of signals as the signal mask for the calling thread.
    pub fn thread_set_mask(&self) -> Result<()> {
        pthread_sigmask(SIG_SETMASK, Some(self), None)
    }

    /// Adds the set of signals to the signal mask for the calling thread.
    pub fn thread_block(&self) -> Result<()> {
        pthread_sigmask(SIG_BLOCK, Some(self), None)
    }

    /// Removes the set of signals from the signal mask for the calling thread.
    pub fn thread_unblock(&self) -> Result<()> {
        pthread_sigmask(SIG_UNBLOCK, Some(self), None)
    }

    /// Sets the set of signals as the signal mask, and returns the old mask.
    pub fn thread_swap_mask(&self, how: SigFlags) -> Result<SigSet> {
        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
        try!(pthread_sigmask(how, Some(self), Some(&mut oldmask)));
        Ok(oldmask)
    }

    /// Suspends execution of the calling thread until one of the signals in the
    /// signal mask becomes pending, and returns the accepted signal.
    pub fn wait(&self) -> Result<SigNum> {
        let mut signum: SigNum = unsafe { mem::uninitialized() };
        let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, &mut signum) };

        Errno::result(res).map(|_| signum)
    }
}

impl AsRef<libc::sigset_t> for SigSet {
    fn as_ref(&self) -> &libc::sigset_t {
        &self.sigset
    }
}

#[allow(unknown_lints)]
#[cfg_attr(not(raw_pointer_derive_allowed), allow(raw_pointer_derive))]
#[derive(Clone, Copy, PartialEq)]
pub enum SigHandler {
    SigDfl,
    SigIgn,
    Handler(extern fn(SigNum)),
    SigAction(extern fn(SigNum, *mut libc::siginfo_t, *mut libc::c_void))
}

pub struct SigAction {
    sigaction: libc::sigaction
}

impl SigAction {
    /// This function will set or unset the flag `SA_SIGINFO` depending on the
    /// type of the `handler` argument.
    pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
        let mut s = unsafe { mem::uninitialized::<libc::sigaction>() };
        s.sa_sigaction = match handler {
            SigHandler::SigDfl => unsafe { mem::transmute(libc::SIG_DFL) },
            SigHandler::SigIgn => unsafe { mem::transmute(libc::SIG_IGN) },
            SigHandler::Handler(f) => unsafe { mem::transmute(f) },
            SigHandler::SigAction(f) => unsafe { mem::transmute(f) },
        };
        s.sa_flags = match handler {
            SigHandler::SigAction(_) => (flags | SA_SIGINFO).bits(),
            _ => (flags - SA_SIGINFO).bits(),
        };
        s.sa_mask = mask.sigset;

        SigAction { sigaction: s }
    }
}

pub unsafe fn sigaction(signum: SigNum, sigaction: &SigAction) -> Result<SigAction> {
    let mut oldact = mem::uninitialized::<libc::sigaction>();

    let res =
        libc::sigaction(signum, &sigaction.sigaction as *const libc::sigaction, &mut oldact as *mut libc::sigaction);

    Errno::result(res).map(|_| SigAction { sigaction: oldact })
}

/// Manages the signal mask (set of blocked signals) for the calling thread.
///
/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
/// and no modification will take place.
///
/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
///
/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
/// and then it will be updated with `set`.
///
/// If both `set` and `oldset` is None, this function is a no-op.
///
/// For more information, visit the [pthread_sigmask](http://man7.org/linux/man-pages/man3/pthread_sigmask.3.html),
/// or [sigprocmask](http://man7.org/linux/man-pages/man2/sigprocmask.2.html) man pages.
pub fn pthread_sigmask(how: SigFlags,
                       set: Option<&SigSet>,
                       oldset: Option<&mut SigSet>) -> Result<()> {
    if set.is_none() && oldset.is_none() {
        return Ok(())
    }

    let res = unsafe {
        // if set or oldset is None, pass in null pointers instead
        libc::pthread_sigmask(how.bits(),
                             set.map_or_else(|| ptr::null::<libc::sigset_t>(),
                                             |s| &s.sigset as *const libc::sigset_t),
                             oldset.map_or_else(|| ptr::null_mut::<libc::sigset_t>(),
                                                |os| &mut os.sigset as *mut libc::sigset_t))
    };

    Errno::result(res).map(drop)
}

pub fn kill(pid: libc::pid_t, signum: SigNum) -> Result<()> {
    let res = unsafe { libc::kill(pid, signum) };

    Errno::result(res).map(drop)
}

pub fn raise(signum: SigNum) -> Result<()> {
    let res = unsafe { libc::raise(signum) };

    Errno::result(res).map(drop)
}

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

    #[test]
    fn test_contains() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();

        assert_eq!(mask.contains(SIGUSR1), Ok(true));
        assert_eq!(mask.contains(SIGUSR2), Ok(false));

        let all = SigSet::all();
        assert_eq!(all.contains(SIGUSR1), Ok(true));
        assert_eq!(all.contains(SIGUSR2), Ok(true));
    }

    #[test]
    fn test_clear() {
        let mut set = SigSet::all();
        set.clear().unwrap();
        for i in 1..NSIG {
            assert_eq!(set.contains(i), Ok(false));
        }
    }

    #[test]
    fn test_extend() {
        let mut one_signal = SigSet::empty();
        one_signal.add(SIGUSR1).unwrap();

        let mut two_signals = SigSet::empty();
        two_signals.add(SIGUSR2).unwrap();
        two_signals.extend(&one_signal).unwrap();

        assert_eq!(two_signals.contains(SIGUSR1), Ok(true));
        assert_eq!(two_signals.contains(SIGUSR2), Ok(true));
    }

    #[test]
    fn test_thread_signal_block() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();

        assert!(mask.thread_block().is_ok());
    }

    #[test]
    fn test_thread_signal_swap() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();
        mask.thread_block().unwrap();

        assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1).unwrap());

        let mask2 = SigSet::empty();
        mask.add(SIGUSR2).unwrap();

        let oldmask = mask2.thread_swap_mask(SIG_SETMASK).unwrap();

        assert!(oldmask.contains(SIGUSR1).unwrap());
        assert!(!oldmask.contains(SIGUSR2).unwrap());
    }

    // TODO(#251): Re-enable after figuring out flakiness.
    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    #[test]
    fn test_sigwait() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();
        mask.add(SIGUSR2).unwrap();
        mask.thread_block().unwrap();

        raise(SIGUSR1).unwrap();
        assert_eq!(mask.wait().unwrap(), SIGUSR1);
    }
}
<|endoftext|>


<commit_before>// Portions of this file are Copyright 2014 The Rust Project Developers.
// See http://rust-lang.org/COPYRIGHT.

use libc;
use {Errno, Result};
use std::mem;
use std::ptr;

pub use libc::{
    SIGHUP,
    SIGINT,
    SIGQUIT,
    SIGILL,
    SIGABRT,
    SIGFPE,
    SIGKILL,
    SIGSEGV,
    SIGPIPE,
    SIGALRM,
    SIGTERM,
    SIGTRAP,
    SIGIOT,
    SIGBUS,
    SIGSYS,
    SIGURG,
    SIGSTOP,
    SIGTSTP,
    SIGCONT,
    SIGCHLD,
    SIGTTIN,
    SIGTTOU,
    SIGIO,
    SIGXCPU,
    SIGXFSZ,
    SIGVTALRM,
    SIGPROF,
    SIGWINCH,
    SIGUSR1,
    SIGUSR2,
};

// This doesn't always exist, but when it does, it's 7
pub const SIGEMT: libc::c_int = 7;

pub const NSIG: libc::c_int = 32;

bitflags!{
    flags SaFlag: libc::c_int {
        const SA_NOCLDSTOP = libc::SA_NOCLDSTOP,
        const SA_NOCLDWAIT = libc::SA_NOCLDWAIT,
        const SA_NODEFER   = libc::SA_NODEFER,
        const SA_ONSTACK   = libc::SA_ONSTACK,
        const SA_RESETHAND = libc::SA_RESETHAND,
        const SA_RESTART   = libc::SA_RESTART,
        const SA_SIGINFO   = libc::SA_SIGINFO,
    }
}

bitflags!{
    flags SigFlag: libc::c_int {
        const SIG_BLOCK   = libc::SIG_BLOCK,
        const SIG_UNBLOCK = libc::SIG_UNBLOCK,
        const SIG_SETMASK = libc::SIG_SETMASK,
    }
}

mod ffi {
    use libc;
    extern {
        pub fn sigwait(set: *const libc::sigset_t, sig: *mut libc::c_int) -> libc::c_int;
    }
}

#[derive(Clone, Copy)]
pub struct SigSet {
    sigset: libc::sigset_t
}

pub type SigNum = libc::c_int;

impl SigSet {
    pub fn all() -> SigSet {
        let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
        let _ = unsafe { libc::sigfillset(&mut sigset as *mut libc::sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn empty() -> SigSet {
        let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
        let _ = unsafe { libc::sigemptyset(&mut sigset as *mut libc::sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn add(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signum) };

        Errno::result(res).map(drop)
    }

    pub fn remove(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signum) };

        Errno::result(res).map(drop)
    }

    pub fn contains(&self, signum: SigNum) -> Result<bool> {
        let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signum) };

        match try!(Errno::result(res)) {
            1 => Ok(true),
            0 => Ok(false),
            _ => unreachable!("unexpected value from sigismember"),
        }
    }

    /// Gets the currently blocked (masked) set of signals for the calling thread.
    pub fn thread_get_mask() -> Result<SigSet> {
        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
        try!(pthread_sigmask(SigFlag::empty(), None, Some(&mut oldmask)));
        Ok(oldmask)
    }

    /// Sets the set of signals as the signal mask for the calling thread.
    pub fn thread_set_mask(&self) -> Result<()> {
        pthread_sigmask(SIG_SETMASK, Some(self), None)
    }

    /// Adds the set of signals to the signal mask for the calling thread.
    pub fn thread_block(&self) -> Result<()> {
        pthread_sigmask(SIG_BLOCK, Some(self), None)
    }

    /// Removes the set of signals from the signal mask for the calling thread.
    pub fn thread_unblock(&self) -> Result<()> {
        pthread_sigmask(SIG_UNBLOCK, Some(self), None)
    }

    /// Sets the set of signals as the signal mask, and returns the old mask.
    pub fn thread_swap_mask(&self, how: SigFlag) -> Result<SigSet> {
        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
        try!(pthread_sigmask(how, Some(self), Some(&mut oldmask)));
        Ok(oldmask)
    }

    /// Suspends execution of the calling thread until one of the signals in the
    /// signal mask becomes pending, and returns the accepted signal.
    pub fn wait(&self) -> Result<SigNum> {
        let mut signum: SigNum = unsafe { mem::uninitialized() };
        let res = unsafe { ffi::sigwait(&self.sigset as *const libc::sigset_t, &mut signum) };

        Errno::result(res).map(|_| signum)
    }
}

impl AsRef<libc::sigset_t> for SigSet {
    fn as_ref(&self) -> &libc::sigset_t {
        &self.sigset
    }
}

#[allow(unknown_lints)]
#[allow(raw_pointer_derive)]
#[derive(Clone, Copy, PartialEq)]
pub enum SigHandler {
    SigDfl,
    SigIgn,
    Handler(extern fn(SigNum)),
    SigAction(extern fn(SigNum, *mut libc::siginfo_t, *mut libc::c_void))
}

pub struct SigAction {
    sigaction: libc::sigaction
}

impl SigAction {
    /// This function will set or unset the flag `SA_SIGINFO` depending on the
    /// type of the `handler` argument.
    pub fn new(handler: SigHandler, flags: SaFlag, mask: SigSet) -> SigAction {
        let mut s = unsafe { mem::uninitialized::<libc::sigaction>() };
        s.sa_sigaction = match handler {
            SigHandler::SigDfl => unsafe { mem::transmute(libc::SIG_DFL) },
            SigHandler::SigIgn => unsafe { mem::transmute(libc::SIG_IGN) },
            SigHandler::Handler(f) => unsafe { mem::transmute(f) },
            SigHandler::SigAction(f) => unsafe { mem::transmute(f) },
        };
        s.sa_flags = match handler {
            SigHandler::SigAction(_) => (flags | SA_SIGINFO).bits(),
            _ => (flags - SA_SIGINFO).bits(),
        };
        s.sa_mask = mask.sigset;

        SigAction { sigaction: s }
    }
}

pub unsafe fn sigaction(signum: SigNum, sigaction: &SigAction) -> Result<SigAction> {
    let mut oldact = mem::uninitialized::<libc::sigaction>();

    let res =
        libc::sigaction(signum, &sigaction.sigaction as *const libc::sigaction, &mut oldact as *mut libc::sigaction);

    Errno::result(res).map(|_| SigAction { sigaction: oldact })
}

/// Manages the signal mask (set of blocked signals) for the calling thread.
///
/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
/// and no modification will take place.
///
/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
///
/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
/// and then it will be updated with `set`.
///
/// If both `set` and `oldset` is None, this function is a no-op.
///
/// For more information, visit the [pthread_sigmask](http://man7.org/linux/man-pages/man3/pthread_sigmask.3.html),
/// or [sigprocmask](http://man7.org/linux/man-pages/man2/sigprocmask.2.html) man pages.
pub fn pthread_sigmask(how: SigFlag,
                       set: Option<&SigSet>,
                       oldset: Option<&mut SigSet>) -> Result<()> {
    if set.is_none() && oldset.is_none() {
        return Ok(())
    }

    let res = unsafe {
        // if set or oldset is None, pass in null pointers instead
        libc::pthread_sigmask(how.bits(),
                             set.map_or_else(|| ptr::null::<libc::sigset_t>(),
                                             |s| &s.sigset as *const libc::sigset_t),
                             oldset.map_or_else(|| ptr::null_mut::<libc::sigset_t>(),
                                                |os| &mut os.sigset as *mut libc::sigset_t))
    };

    Errno::result(res).map(drop)
}

pub fn kill(pid: libc::pid_t, signum: SigNum) -> Result<()> {
    let res = unsafe { libc::kill(pid, signum) };

    Errno::result(res).map(drop)
}

pub fn raise(signum: SigNum) -> Result<()> {
    let res = unsafe { libc::raise(signum) };

    Errno::result(res).map(drop)
}

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

    #[test]
    fn test_contains() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();

        assert_eq!(mask.contains(SIGUSR1), Ok(true));
        assert_eq!(mask.contains(SIGUSR2), Ok(false));

        let all = SigSet::all();
        assert_eq!(all.contains(SIGUSR1), Ok(true));
        assert_eq!(all.contains(SIGUSR2), Ok(true));
    }

    #[test]
    fn test_thread_signal_block() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();

        assert!(mask.thread_block().is_ok());
    }

    #[test]
    fn test_thread_signal_swap() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();
        mask.thread_block().unwrap();

        assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1).unwrap());

        let mask2 = SigSet::empty();
        mask.add(SIGUSR2).unwrap();

        let oldmask = mask2.thread_swap_mask(SIG_SETMASK).unwrap();

        assert!(oldmask.contains(SIGUSR1).unwrap());
        assert!(!oldmask.contains(SIGUSR2).unwrap());
    }

    #[test]
    fn test_sigwait() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();
        mask.add(SIGUSR2).unwrap();
        mask.thread_block().unwrap();

        raise(SIGUSR1).unwrap();
        assert_eq!(mask.wait().unwrap(), SIGUSR1);
    }
}
<commit_msg>tests: Disable test_sigwait on apple platforms<commit_after>// Portions of this file are Copyright 2014 The Rust Project Developers.
// See http://rust-lang.org/COPYRIGHT.

use libc;
use {Errno, Result};
use std::mem;
use std::ptr;

pub use libc::{
    SIGHUP,
    SIGINT,
    SIGQUIT,
    SIGILL,
    SIGABRT,
    SIGFPE,
    SIGKILL,
    SIGSEGV,
    SIGPIPE,
    SIGALRM,
    SIGTERM,
    SIGTRAP,
    SIGIOT,
    SIGBUS,
    SIGSYS,
    SIGURG,
    SIGSTOP,
    SIGTSTP,
    SIGCONT,
    SIGCHLD,
    SIGTTIN,
    SIGTTOU,
    SIGIO,
    SIGXCPU,
    SIGXFSZ,
    SIGVTALRM,
    SIGPROF,
    SIGWINCH,
    SIGUSR1,
    SIGUSR2,
};

// This doesn't always exist, but when it does, it's 7
pub const SIGEMT: libc::c_int = 7;

pub const NSIG: libc::c_int = 32;

bitflags!{
    flags SaFlag: libc::c_int {
        const SA_NOCLDSTOP = libc::SA_NOCLDSTOP,
        const SA_NOCLDWAIT = libc::SA_NOCLDWAIT,
        const SA_NODEFER   = libc::SA_NODEFER,
        const SA_ONSTACK   = libc::SA_ONSTACK,
        const SA_RESETHAND = libc::SA_RESETHAND,
        const SA_RESTART   = libc::SA_RESTART,
        const SA_SIGINFO   = libc::SA_SIGINFO,
    }
}

bitflags!{
    flags SigFlag: libc::c_int {
        const SIG_BLOCK   = libc::SIG_BLOCK,
        const SIG_UNBLOCK = libc::SIG_UNBLOCK,
        const SIG_SETMASK = libc::SIG_SETMASK,
    }
}

mod ffi {
    use libc;
    extern {
        pub fn sigwait(set: *const libc::sigset_t, sig: *mut libc::c_int) -> libc::c_int;
    }
}

#[derive(Clone, Copy)]
pub struct SigSet {
    sigset: libc::sigset_t
}

pub type SigNum = libc::c_int;

impl SigSet {
    pub fn all() -> SigSet {
        let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
        let _ = unsafe { libc::sigfillset(&mut sigset as *mut libc::sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn empty() -> SigSet {
        let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
        let _ = unsafe { libc::sigemptyset(&mut sigset as *mut libc::sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn add(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signum) };

        Errno::result(res).map(drop)
    }

    pub fn remove(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signum) };

        Errno::result(res).map(drop)
    }

    pub fn contains(&self, signum: SigNum) -> Result<bool> {
        let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signum) };

        match try!(Errno::result(res)) {
            1 => Ok(true),
            0 => Ok(false),
            _ => unreachable!("unexpected value from sigismember"),
        }
    }

    /// Gets the currently blocked (masked) set of signals for the calling thread.
    pub fn thread_get_mask() -> Result<SigSet> {
        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
        try!(pthread_sigmask(SigFlag::empty(), None, Some(&mut oldmask)));
        Ok(oldmask)
    }

    /// Sets the set of signals as the signal mask for the calling thread.
    pub fn thread_set_mask(&self) -> Result<()> {
        pthread_sigmask(SIG_SETMASK, Some(self), None)
    }

    /// Adds the set of signals to the signal mask for the calling thread.
    pub fn thread_block(&self) -> Result<()> {
        pthread_sigmask(SIG_BLOCK, Some(self), None)
    }

    /// Removes the set of signals from the signal mask for the calling thread.
    pub fn thread_unblock(&self) -> Result<()> {
        pthread_sigmask(SIG_UNBLOCK, Some(self), None)
    }

    /// Sets the set of signals as the signal mask, and returns the old mask.
    pub fn thread_swap_mask(&self, how: SigFlag) -> Result<SigSet> {
        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
        try!(pthread_sigmask(how, Some(self), Some(&mut oldmask)));
        Ok(oldmask)
    }

    /// Suspends execution of the calling thread until one of the signals in the
    /// signal mask becomes pending, and returns the accepted signal.
    pub fn wait(&self) -> Result<SigNum> {
        let mut signum: SigNum = unsafe { mem::uninitialized() };
        let res = unsafe { ffi::sigwait(&self.sigset as *const libc::sigset_t, &mut signum) };

        Errno::result(res).map(|_| signum)
    }
}

impl AsRef<libc::sigset_t> for SigSet {
    fn as_ref(&self) -> &libc::sigset_t {
        &self.sigset
    }
}

#[allow(unknown_lints)]
#[allow(raw_pointer_derive)]
#[derive(Clone, Copy, PartialEq)]
pub enum SigHandler {
    SigDfl,
    SigIgn,
    Handler(extern fn(SigNum)),
    SigAction(extern fn(SigNum, *mut libc::siginfo_t, *mut libc::c_void))
}

pub struct SigAction {
    sigaction: libc::sigaction
}

impl SigAction {
    /// This function will set or unset the flag `SA_SIGINFO` depending on the
    /// type of the `handler` argument.
    pub fn new(handler: SigHandler, flags: SaFlag, mask: SigSet) -> SigAction {
        let mut s = unsafe { mem::uninitialized::<libc::sigaction>() };
        s.sa_sigaction = match handler {
            SigHandler::SigDfl => unsafe { mem::transmute(libc::SIG_DFL) },
            SigHandler::SigIgn => unsafe { mem::transmute(libc::SIG_IGN) },
            SigHandler::Handler(f) => unsafe { mem::transmute(f) },
            SigHandler::SigAction(f) => unsafe { mem::transmute(f) },
        };
        s.sa_flags = match handler {
            SigHandler::SigAction(_) => (flags | SA_SIGINFO).bits(),
            _ => (flags - SA_SIGINFO).bits(),
        };
        s.sa_mask = mask.sigset;

        SigAction { sigaction: s }
    }
}

pub unsafe fn sigaction(signum: SigNum, sigaction: &SigAction) -> Result<SigAction> {
    let mut oldact = mem::uninitialized::<libc::sigaction>();

    let res =
        libc::sigaction(signum, &sigaction.sigaction as *const libc::sigaction, &mut oldact as *mut libc::sigaction);

    Errno::result(res).map(|_| SigAction { sigaction: oldact })
}

/// Manages the signal mask (set of blocked signals) for the calling thread.
///
/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
/// and no modification will take place.
///
/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
///
/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
/// and then it will be updated with `set`.
///
/// If both `set` and `oldset` is None, this function is a no-op.
///
/// For more information, visit the [pthread_sigmask](http://man7.org/linux/man-pages/man3/pthread_sigmask.3.html),
/// or [sigprocmask](http://man7.org/linux/man-pages/man2/sigprocmask.2.html) man pages.
pub fn pthread_sigmask(how: SigFlag,
                       set: Option<&SigSet>,
                       oldset: Option<&mut SigSet>) -> Result<()> {
    if set.is_none() && oldset.is_none() {
        return Ok(())
    }

    let res = unsafe {
        // if set or oldset is None, pass in null pointers instead
        libc::pthread_sigmask(how.bits(),
                             set.map_or_else(|| ptr::null::<libc::sigset_t>(),
                                             |s| &s.sigset as *const libc::sigset_t),
                             oldset.map_or_else(|| ptr::null_mut::<libc::sigset_t>(),
                                                |os| &mut os.sigset as *mut libc::sigset_t))
    };

    Errno::result(res).map(drop)
}

pub fn kill(pid: libc::pid_t, signum: SigNum) -> Result<()> {
    let res = unsafe { libc::kill(pid, signum) };

    Errno::result(res).map(drop)
}

pub fn raise(signum: SigNum) -> Result<()> {
    let res = unsafe { libc::raise(signum) };

    Errno::result(res).map(drop)
}

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

    #[test]
    fn test_contains() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();

        assert_eq!(mask.contains(SIGUSR1), Ok(true));
        assert_eq!(mask.contains(SIGUSR2), Ok(false));

        let all = SigSet::all();
        assert_eq!(all.contains(SIGUSR1), Ok(true));
        assert_eq!(all.contains(SIGUSR2), Ok(true));
    }

    #[test]
    fn test_thread_signal_block() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();

        assert!(mask.thread_block().is_ok());
    }

    #[test]
    fn test_thread_signal_swap() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();
        mask.thread_block().unwrap();

        assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1).unwrap());

        let mask2 = SigSet::empty();
        mask.add(SIGUSR2).unwrap();

        let oldmask = mask2.thread_swap_mask(SIG_SETMASK).unwrap();

        assert!(oldmask.contains(SIGUSR1).unwrap());
        assert!(!oldmask.contains(SIGUSR2).unwrap());
    }

    // TODO(#251): Re-enable after figuring out flakiness.
    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    #[test]
    fn test_sigwait() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();
        mask.add(SIGUSR2).unwrap();
        mask.thread_block().unwrap();

        raise(SIGUSR1).unwrap();
        assert_eq!(mask.wait().unwrap(), SIGUSR1);
    }
}
<|endoftext|>


<commit_before>extern crate dft;

#[derive(Clone, Debug)]
pub struct FrequencyBucket {
    pub min_freq: f64,
    pub max_freq: f64,
    pub intensity: f64
}

impl FrequencyBucket {
    pub fn ave_freq(&self) -> f64 {
        (self.min_freq + self.max_freq) / 2.0
    }
}

pub fn fft(input: &Vec<f64>, sample_rate: f64) -> Vec<FrequencyBucket> {
    let frames = input.len();
    let mean_input = input.iter().sum::<f64>()/input.len() as f64;

    let mut intensities = input.iter().map(|x|x-mean_input).collect::<Vec<_>>();
    let plan = dft::Plan::new(dft::Operation::Forward, frames);
    dft::transform(&mut intensities, &plan);

    let frequency_resolution = sample_rate / 2.0 / frames as f64;

    intensities.iter().enumerate().map(|(index, &value)| {
        let index = index as f64;
        FrequencyBucket {
            min_freq: index * frequency_resolution,
            max_freq: (index+1.0) * frequency_resolution,
            intensity: value
        }
    }).collect()
}

pub fn find_fundamental_frequency(frequency_domain: &Vec<FrequencyBucket>) -> Option<f64> {
    //TODO look at all significant frequencies, find fundamental
    //TODO return None is none of them are significant
    let positive_buckets = frequency_domain.iter().filter(|x| x.intensity > 0.0).cloned().collect::<Vec<_>>();
    let average_intensity = positive_buckets.iter().map(|x| x.intensity).sum::<f64>() / frequency_domain.len() as f64;
    let significant_buckets = positive_buckets.iter().filter(|x| x.intensity > average_intensity).cloned().collect::<Vec<_>>();

    let max_bucket = significant_buckets.iter()
        .fold(None as Option<::transforms::FrequencyBucket>, |max, next|
              if max.is_none() || max.clone().unwrap().intensity < next.intensity { Some(next.clone()) } else { max }
        ).unwrap();

    Some(max_bucket.ave_freq())
}

pub fn correlation(input: &Vec<f64>) -> Vec<f64> {
    let mut correlation = Vec::with_capacity(input.len());
    for offset in 0..input.len() {
        let mut c = 0.0;
        for i in 0..input.len()-offset {
            let j = i+offset;
            c += input[i] * input[j];
        }
        correlation.push(c);
    }
    correlation
}

pub fn find_fundamental_frequency_correlation(input: &Vec<f64>, sample_rate: f64) -> Option<f64> {
    let correlation = correlation(&input);

    let mut first_peak_width = 0;
    for offset in 0..correlation.len() {
        if correlation[offset] < 0.0 {
            first_peak_width = offset;
            break;
        }
    }
    if first_peak_width == 0 {
        return None;
    }

    let peak = correlation.iter()
        .enumerate()
        .skip(first_peak_width)
        .fold((first_peak_width, 0.0 as f64), |(xi, xmag), (yi, &ymag)| if ymag > xmag { (yi, ymag) } else { (xi, xmag) });

    let (peak_index, _) = peak;
    Some(sample_rate / peak_index as f64)
}

fn interpolate(correlation: &Vec<f64>, x: f64) -> f64 {
    if x < 0.0 {
        println!("<0");
        correlation[0]
    }
    else if x >= correlation.len() as f64 {
        println!(">len");
        correlation[correlation.len()-1]
    }
    else {
        let x0 = x.floor();
        let y0 = correlation[x0 as usize];
        let x1 = x.ceil();
        let y1 = correlation[x1 as usize];

        (y0*(x1-x) + y1*(x-x0)) / (x1-x0)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::f64::consts::PI;

    const SAMPLE_RATE: f64 = 44100.0;
    const FRAMES: usize = 512;

    fn frequency_resolution() -> f64 {
        SAMPLE_RATE / 2.0 / FRAMES as f64
    }

    fn sin_arg(f: f64, t: f64, phase: f64) -> f64 {
        2.0 as f64 * PI * f * t + phase
    }

    fn sample_sinusoud(amplitude: f64, frequency: f64, phase: f64) -> Vec<f64> {
        (0..FRAMES)
            .map(|x| {
                let t = x as f64 / SAMPLE_RATE;
                sin_arg(frequency, t, phase).sin() * amplitude
            }).collect()
    }

    #[test]
    fn fft_on_sine_wave() {
        let frequency = 440.0 as f64; //concert A

        let samples = sample_sinusoud(1.0, frequency, 0.0);
        let frequency_domain = fft(&samples, SAMPLE_RATE);
        let fundamental = find_fundamental_frequency(&frequency_domain).unwrap();

        assert!((fundamental-frequency).abs() < frequency_resolution(), "expected={}, actual={}", frequency, fundamental);
    }

    #[test]
    fn fft_on_two_sine_waves() {
        //Unfortunately, real signals won't be this neat
        let samples1a = sample_sinusoud(2.0, 440.0, 0.0);
        let samples2a = sample_sinusoud(1.0, 880.0, 0.0);
        let expected_fundamental = 440.0;

        let samples = samples1a.iter().zip(samples2a.iter())
            .map(|(a, b)| a+b)
            .collect();
        let frequency_domain = fft(&samples, SAMPLE_RATE);

        let fundamental = find_fundamental_frequency(&frequency_domain).unwrap();

        assert!((fundamental-expected_fundamental).abs() < frequency_resolution(), "expected_fundamental={}, actual={}", expected_fundamental, fundamental);
    }

    #[test]
    fn correlation_on_sine_wave() {
        let frequency = 440.0 as f64; //concert A

        let samples = sample_sinusoud(1.0, frequency, 0.0);
        let fundamental = find_fundamental_frequency_correlation(&samples, SAMPLE_RATE).unwrap();
        assert!((fundamental-frequency).abs() < frequency_resolution(), "expected={}, actual={}", frequency, fundamental);
    }

    #[test]
    fn correlation_on_two_sine_waves() {
        //Unfortunately, real signals won't be this neat
        let samples1a = sample_sinusoud(2.0, 440.0, 0.0);
        let samples2a = sample_sinusoud(1.0, 880.0, 0.0);
        let expected_fundamental = 440.0;

        let samples = samples1a.iter().zip(samples2a.iter())
            .map(|(a, b)| a+b)
            .collect();

        let fundamental = find_fundamental_frequency_correlation(&samples, SAMPLE_RATE).unwrap();

        assert!((fundamental-expected_fundamental).abs() < frequency_resolution(), "expected_fundamental={}, actual={}", expected_fundamental, fundamental);
    }

    #[test]
    fn interpolate_half_way() {
        assert_eq!(0.5, interpolate(&vec!(0.0, 1.0), 0.5))
    }
}

pub fn hz_to_midi_number(hz: f64) -> f64 {
    69.0 + 12.0 * (hz / 440.0).log2()
}

pub fn hz_to_cents_error(hz: f64) -> f64 {
    let midi_number = hz_to_midi_number(hz);
    let cents = (midi_number * 100.0).round() % 100.0;
    if cents >= 50.0 {
        cents - 100.0
    }
    else {
        cents
    }
}

pub fn hz_to_pitch(hz: f64) -> String {
    let pitch_names = [
        "C",
        "C#",
        "D",
        "Eb",
        "E",
        "F",
        "F#",
        "G",
        "G#",
        "A",
        "Bb",
        "B"
    ];

    let midi_number = hz_to_midi_number(hz);
    //midi_number of 0 is C-1.

    let rounded_pitch = midi_number.round() as i32;
    let name = pitch_names[rounded_pitch as usize % pitch_names.len()].to_string();
    let octave = rounded_pitch / pitch_names.len() as i32 - 1; //0 is C-1
    if octave < 0 {
        return "< C1".to_string();
    }

    let mut cents = ((midi_number * 100.0).round() % 100.0) as i32;
    if cents >= 50 {
        //don't need to adjust pitch here, that's already been done by the round above
        cents -= 100;
    }

    format!("{}{} {:+}", name, octave, cents)
}

#[test]
fn a4_is_correct() {
    assert_eq!(hz_to_pitch(440.0), "A4 +0");
}

#[test]
fn a2_is_correct() {
    assert_eq!(hz_to_pitch(110.0), "A2 +0");
}

#[test]
fn c4_is_correct() {
    assert_eq!(hz_to_pitch(261.63), "C4 +0");
}

#[test]
fn f5_is_correct() {
    assert_eq!(hz_to_pitch(698.46), "F5 +0");
}

pub fn align_to_rising_edge(samples: &Vec<f64>) -> Vec<f64> {
    samples.iter()
        .skip_while(|x| !x.is_sign_negative())
        .skip_while(|x| x.is_sign_negative())
        .cloned()
        .collect()
}
<commit_msg>Added binary search to refine fundamental frequency search on the correlation<commit_after>extern crate dft;

#[derive(Clone, Debug)]
pub struct FrequencyBucket {
    pub min_freq: f64,
    pub max_freq: f64,
    pub intensity: f64
}

impl FrequencyBucket {
    pub fn ave_freq(&self) -> f64 {
        (self.min_freq + self.max_freq) / 2.0
    }
}

pub fn fft(input: &Vec<f64>, sample_rate: f64) -> Vec<FrequencyBucket> {
    let frames = input.len();
    let mean_input = input.iter().sum::<f64>()/input.len() as f64;

    let mut intensities = input.iter().map(|x|x-mean_input).collect::<Vec<_>>();
    let plan = dft::Plan::new(dft::Operation::Forward, frames);
    dft::transform(&mut intensities, &plan);

    let frequency_resolution = sample_rate / 2.0 / frames as f64;

    intensities.iter().enumerate().map(|(index, &value)| {
        let index = index as f64;
        FrequencyBucket {
            min_freq: index * frequency_resolution,
            max_freq: (index+1.0) * frequency_resolution,
            intensity: value
        }
    }).collect()
}

pub fn find_fundamental_frequency(frequency_domain: &Vec<FrequencyBucket>) -> Option<f64> {
    //TODO look at all significant frequencies, find fundamental
    //TODO return None is none of them are significant
    let positive_buckets = frequency_domain.iter().filter(|x| x.intensity > 0.0).cloned().collect::<Vec<_>>();
    let average_intensity = positive_buckets.iter().map(|x| x.intensity).sum::<f64>() / frequency_domain.len() as f64;
    let significant_buckets = positive_buckets.iter().filter(|x| x.intensity > average_intensity).cloned().collect::<Vec<_>>();

    let max_bucket = significant_buckets.iter()
        .fold(None as Option<::transforms::FrequencyBucket>, |max, next|
              if max.is_none() || max.clone().unwrap().intensity < next.intensity { Some(next.clone()) } else { max }
        ).unwrap();

    Some(max_bucket.ave_freq())
}

pub fn correlation(input: &Vec<f64>) -> Vec<f64> {
    let mut correlation = Vec::with_capacity(input.len());
    for offset in 0..input.len() {
        let mut c = 0.0;
        for i in 0..input.len()-offset {
            let j = i+offset;
            c += input[i] * input[j];
        }
        correlation.push(c);
    }
    correlation
}

pub fn find_fundamental_frequency_correlation(input: &Vec<f64>, sample_rate: f64) -> Option<f64> {
    let correlation = correlation(&input);

    let mut first_peak_width = 0;
    for offset in 0..correlation.len() {
        if correlation[offset] < 0.0 {
            first_peak_width = offset;
            break;
        }
    }
    if first_peak_width == 0 {
        return None;
    }

    let peak = correlation.iter()
        .enumerate()
        .skip(first_peak_width)
        .fold((first_peak_width, 0.0 as f64), |(xi, xmag), (yi, &ymag)| if ymag > xmag { (yi, ymag) } else { (xi, xmag) });

    let (peak_index, _) = peak;

    let refined_peak_index = refine_fundamentals(&correlation, peak_index as f64);

    Some(sample_rate / refined_peak_index)
}

fn refine_fundamentals(correlation: &Vec<f64>, initial_guess: f64) -> f64 {
    let mut low_bound = initial_guess - 0.5;
    let mut high_bound = initial_guess + 0.5;

    for _ in 0..5 {
        let data_points = 2 * correlation.len() / high_bound.ceil() as usize;
        let low_guess = score_guess(&correlation, low_bound, data_points);
        let high_guess = score_guess(&correlation, high_bound, data_points);

        let midpoint = (low_bound + high_bound) / 2.0;
        if high_guess > low_guess {
            low_bound = midpoint;
        }
        else {
            high_bound = midpoint;
        }
    }
    (low_bound + high_bound) / 2.0
}

fn score_guess(correlation: &Vec<f64>, period: f64, data_points: usize) -> f64 {
    let mut score = 0.0;
    for i in 0..data_points {
        if i % 2 == 0 {
            score += i as f64 * interpolate(&correlation, i as f64 * period / 2.0);
        }
        else {
            score -= i as f64 * interpolate(&correlation, i as f64 * period / 2.0);
        }
    }
    score
}

fn interpolate(correlation: &Vec<f64>, x: f64) -> f64 {
    if x < 0.0 {
        println!("<0");
        correlation[0]
    }
    else if x >= correlation.len() as f64 {
        println!(">len");
        correlation[correlation.len()-1]
    }
    else {
        let x0 = x.floor();
        let y0 = correlation[x0 as usize];
        let x1 = x.ceil();
        let y1 = correlation[x1 as usize];

        if (x0 as usize == x1 as usize) {
            y0
        }
        else {
            (y0*(x1-x) + y1*(x-x0)) / (x1-x0)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::f64::consts::PI;

    const SAMPLE_RATE: f64 = 44100.0;
    const FRAMES: usize = 512;

    fn frequency_resolution() -> f64 {
        SAMPLE_RATE / 2.0 / FRAMES as f64
    }

    fn sin_arg(f: f64, t: f64, phase: f64) -> f64 {
        2.0 as f64 * PI * f * t + phase
    }

    fn sample_sinusoud(amplitude: f64, frequency: f64, phase: f64) -> Vec<f64> {
        (0..FRAMES)
            .map(|x| {
                let t = x as f64 / SAMPLE_RATE;
                sin_arg(frequency, t, phase).sin() * amplitude
            }).collect()
    }

    #[test]
    fn fft_on_sine_wave() {
        let frequency = 440.0 as f64; //concert A

        let samples = sample_sinusoud(1.0, frequency, 0.0);
        let frequency_domain = fft(&samples, SAMPLE_RATE);
        let fundamental = find_fundamental_frequency(&frequency_domain).unwrap();

        assert!((fundamental-frequency).abs() < frequency_resolution(), "expected={}, actual={}", frequency, fundamental);
    }

    #[test]
    fn fft_on_two_sine_waves() {
        //Unfortunately, real signals won't be this neat
        let samples1a = sample_sinusoud(2.0, 440.0, 0.0);
        let samples2a = sample_sinusoud(1.0, 880.0, 0.0);
        let expected_fundamental = 440.0;

        let samples = samples1a.iter().zip(samples2a.iter())
            .map(|(a, b)| a+b)
            .collect();
        let frequency_domain = fft(&samples, SAMPLE_RATE);

        let fundamental = find_fundamental_frequency(&frequency_domain).unwrap();

        assert!((fundamental-expected_fundamental).abs() < frequency_resolution(), "expected_fundamental={}, actual={}", expected_fundamental, fundamental);
    }

    #[test]
    fn correlation_on_sine_wave() {
        let frequency = 440.0 as f64; //concert A

        let samples = sample_sinusoud(1.0, frequency, 0.0);
        let fundamental = find_fundamental_frequency_correlation(&samples, SAMPLE_RATE).unwrap();
        assert!((fundamental-frequency).abs() < frequency_resolution(), "expected={}, actual={}", frequency, fundamental);
    }

    #[test]
    fn correlation_on_two_sine_waves() {
        //Unfortunately, real signals won't be this neat
        let samples1a = sample_sinusoud(2.0, 440.0, 0.0);
        let samples2a = sample_sinusoud(1.0, 880.0, 0.0);
        let expected_fundamental = 440.0;

        let samples = samples1a.iter().zip(samples2a.iter())
            .map(|(a, b)| a+b)
            .collect();

        let fundamental = find_fundamental_frequency_correlation(&samples, SAMPLE_RATE).unwrap();

        assert!((fundamental-expected_fundamental).abs() < frequency_resolution(), "expected_fundamental={}, actual={}", expected_fundamental, fundamental);
    }

    #[test]
    fn interpolate_half_way() {
        assert_eq!(0.5, interpolate(&vec!(0.0, 1.0), 0.5))
    }
}

pub fn hz_to_midi_number(hz: f64) -> f64 {
    69.0 + 12.0 * (hz / 440.0).log2()
}

pub fn hz_to_cents_error(hz: f64) -> f64 {
    let midi_number = hz_to_midi_number(hz);
    let cents = (midi_number * 100.0).round() % 100.0;
    if cents >= 50.0 {
        cents - 100.0
    }
    else {
        cents
    }
}

pub fn hz_to_pitch(hz: f64) -> String {
    let pitch_names = [
        "C",
        "C#",
        "D",
        "Eb",
        "E",
        "F",
        "F#",
        "G",
        "G#",
        "A",
        "Bb",
        "B"
    ];

    let midi_number = hz_to_midi_number(hz);
    //midi_number of 0 is C-1.

    let rounded_pitch = midi_number.round() as i32;
    let name = pitch_names[rounded_pitch as usize % pitch_names.len()].to_string();
    let octave = rounded_pitch / pitch_names.len() as i32 - 1; //0 is C-1
    if octave < 0 {
        return "< C1".to_string();
    }

    let mut cents = ((midi_number * 100.0).round() % 100.0) as i32;
    if cents >= 50 {
        //don't need to adjust pitch here, that's already been done by the round above
        cents -= 100;
    }

    format!("{}{} {:+}", name, octave, cents)
}

#[test]
fn a4_is_correct() {
    assert_eq!(hz_to_pitch(440.0), "A4 +0");
}

#[test]
fn a2_is_correct() {
    assert_eq!(hz_to_pitch(110.0), "A2 +0");
}

#[test]
fn c4_is_correct() {
    assert_eq!(hz_to_pitch(261.63), "C4 +0");
}

#[test]
fn f5_is_correct() {
    assert_eq!(hz_to_pitch(698.46), "F5 +0");
}

pub fn align_to_rising_edge(samples: &Vec<f64>) -> Vec<f64> {
    samples.iter()
        .skip_while(|x| !x.is_sign_negative())
        .skip_while(|x| x.is_sign_negative())
        .cloned()
        .collect()
}
<|endoftext|>


<commit_before>#![allow(unused_imports)]
use rustc_serialize::json;

#[test]
fn reply_keyboard_markup() {
    use ReplyKeyboardMarkup as RKM;

    // Test default values
    assert_eq!(RKM::default(), RKM {
        keyboard: Vec::new(),
        resize_keyboard: None,
        one_time_keyboard: None,
        selective: None,
    });

    // Test encoding
    let x = RKM::default();
    assert_eq!(json::encode(&x).unwrap(), r#"{"keyboard":[]}"#.to_string());

    let x = RKM { resize_keyboard: Some(true), ..Default::default() };
    assert_eq!(json::encode(&x).unwrap(),
        r#"{"keyboard":[],"resize_keyboard":true}"#.to_string());

    let x = RKM {
        keyboard: vec![vec!["ABC".into()], vec!["X".into(), "Y".into()]],
        resize_keyboard: Some(false),
        ..Default::default()
    };
    assert_eq!(json::encode(&x).unwrap(),
        r#"{"keyboard":[["ABC"],["X","Y"]],"resize_keyboard":false}"#.to_string());
}

#[test]
fn keyboard_markup() {
    use ReplyKeyboardMarkup as RKM;
    use ReplyMarkup as RM;

    // Test encoding
    let x = RM::Keyboard(RKM::default());
    assert_eq!(json::encode(&x).unwrap(), r#"{"keyboard":[]}"#.to_string());

    let x = RM::KeyboardHide(false);
    assert_eq!(json::encode(&x).unwrap(),
        r#"{"hide_keyboard":true,"selective":false}"#.to_string());

    let x = RM::ForceReply(true);
    assert_eq!(json::encode(&x).unwrap(),
        r#"{"force_reply":true,"selective":true}"#.to_string());
}

#[test]
fn decode_group_chat() {
    use Chat;

    let blob = r#"{"title":"This is a group chat","id":-12345678,"type":"group"}"#;
    let chat: Chat = json::decode(&blob).unwrap();
    assert!(chat.is_group());
}

#[test]
fn decode_user_chat() {
    use Chat;
    use User;

    let blob = r#"{"first_name":"test","id":123456789,"username":"test","type":"private"}"#;
    let chat: Chat = json::decode(&blob).unwrap();
    let user: User = json::decode(&blob).unwrap();

    assert!(chat.is_user());
    assert_eq!(Chat::Private(user), chat);
}

#[test]
fn decode_update() {
    use Update;
    let blob = r#"{
        "message" : {
            "text" : "The quick brown fox jumps over the lazy dog",
            "from" : {
                "first_name" : "test",
                "id" : 123456789,
                "username" : "test"
            },
            "date" : 1437821492,
            "message_id" : 74,
            "chat" : {
                "title" : "This is a group chat",
                "id" : -12345678,
                "type": "group"
            }
        },
        "update_id" : 123456789
    }"#;
    let _: Update = json::decode(&blob).unwrap();
}

#[test]
fn decode_get_updates_response() {
    use Response;
    use Update;

    let blob = r#"{
        "result" : [
            {
                "message" : {
                    "text" : "This is the first message",
                    "from" : {
                        "username" : "test",
                        "id" : 123456789,
                        "first_name" : "Test"
                    },
                    "date" : 1437821579,
                    "message_id" : 78,
                    "chat" : {
                        "username" : "test",
                        "id" : 123456789,
                        "first_name" : "Test",
                        "type": "private"
                    }
                },
                "update_id" : 123456789
            },
            {
                "message" : {
                    "text" : "This is the second message",
                    "from" : {
                        "username" : "test",
                        "id" : 123456789,
                        "first_name" : "Test"
                    },
                    "date" : 1437821579,
                    "message_id" : 79,
                    "chat" : {
                        "username" : "test",
                        "id" : 123456789,
                        "first_name" : "Test",
                        "type": "private"
                    }
                },
                "update_id" : 123456790
            }
        ],
        "ok" : true
    }"#;

    let _: Response<Vec<Update>> = json::decode(&blob).unwrap();
}
<commit_msg>Add decode_supergroup_chat, decode_channel_chat and decode_channel_with_username_chat tests<commit_after>#![allow(unused_imports)]
use rustc_serialize::json;

#[test]
fn reply_keyboard_markup() {
    use ReplyKeyboardMarkup as RKM;

    // Test default values
    assert_eq!(RKM::default(), RKM {
        keyboard: Vec::new(),
        resize_keyboard: None,
        one_time_keyboard: None,
        selective: None,
    });

    // Test encoding
    let x = RKM::default();
    assert_eq!(json::encode(&x).unwrap(), r#"{"keyboard":[]}"#.to_string());

    let x = RKM { resize_keyboard: Some(true), ..Default::default() };
    assert_eq!(json::encode(&x).unwrap(),
        r#"{"keyboard":[],"resize_keyboard":true}"#.to_string());

    let x = RKM {
        keyboard: vec![vec!["ABC".into()], vec!["X".into(), "Y".into()]],
        resize_keyboard: Some(false),
        ..Default::default()
    };
    assert_eq!(json::encode(&x).unwrap(),
        r#"{"keyboard":[["ABC"],["X","Y"]],"resize_keyboard":false}"#.to_string());
}

#[test]
fn keyboard_markup() {
    use ReplyKeyboardMarkup as RKM;
    use ReplyMarkup as RM;

    // Test encoding
    let x = RM::Keyboard(RKM::default());
    assert_eq!(json::encode(&x).unwrap(), r#"{"keyboard":[]}"#.to_string());

    let x = RM::KeyboardHide(false);
    assert_eq!(json::encode(&x).unwrap(),
        r#"{"hide_keyboard":true,"selective":false}"#.to_string());

    let x = RM::ForceReply(true);
    assert_eq!(json::encode(&x).unwrap(),
        r#"{"force_reply":true,"selective":true}"#.to_string());
}

#[test]
fn decode_group_chat() {
    use Chat;

    let blob = r#"{"title":"This is a group chat","id":-12345678,"type":"group"}"#;
    let chat: Chat = json::decode(&blob).unwrap();
    assert!(chat.is_group());
}

#[test]
fn decode_supergroup_chat() {
    use Chat;

    let blob = r#"{"title":"This is a group chat","id":-12345678,"type":"supergroup"}"#;
    let chat: Chat = json::decode(&blob).unwrap();
    assert!(chat.is_supergroup());
}

#[test]
fn decode_channel_chat() {
    use Chat;

    let blob = r#"{"title":"This is a group chat","id":-12345678,"type":"channel"}"#;
    let chat: Chat = json::decode(&blob).unwrap();
    assert!(chat.is_channel());
}

#[test]
fn decode_channel_with_username_chat() {
    use Chat;

    let blob = r#"{"title":"This is a group chat","id":-12345678,"type":"channel", "username": "foo"}"#;
    let chat: Chat = json::decode(&blob).unwrap();
    assert!(chat.is_channel());
}

#[test]
fn decode_user_chat() {
    use Chat;
    use User;

    let blob = r#"{"first_name":"test","id":123456789,"username":"test","type":"private"}"#;
    let chat: Chat = json::decode(&blob).unwrap();
    let user: User = json::decode(&blob).unwrap();

    assert!(chat.is_user());
    assert_eq!(Chat::Private(user), chat);
}

#[test]
fn decode_update() {
    use Update;
    let blob = r#"{
        "message" : {
            "text" : "The quick brown fox jumps over the lazy dog",
            "from" : {
                "first_name" : "test",
                "id" : 123456789,
                "username" : "test"
            },
            "date" : 1437821492,
            "message_id" : 74,
            "chat" : {
                "title" : "This is a group chat",
                "id" : -12345678,
                "type": "group"
            }
        },
        "update_id" : 123456789
    }"#;
    let _: Update = json::decode(&blob).unwrap();
}

#[test]
fn decode_get_updates_response() {
    use Response;
    use Update;

    let blob = r#"{
        "result" : [
            {
                "message" : {
                    "text" : "This is the first message",
                    "from" : {
                        "username" : "test",
                        "id" : 123456789,
                        "first_name" : "Test"
                    },
                    "date" : 1437821579,
                    "message_id" : 78,
                    "chat" : {
                        "username" : "test",
                        "id" : 123456789,
                        "first_name" : "Test",
                        "type": "private"
                    }
                },
                "update_id" : 123456789
            },
            {
                "message" : {
                    "text" : "This is the second message",
                    "from" : {
                        "username" : "test",
                        "id" : 123456789,
                        "first_name" : "Test"
                    },
                    "date" : 1437821579,
                    "message_id" : 79,
                    "chat" : {
                        "username" : "test",
                        "id" : 123456789,
                        "first_name" : "Test",
                        "type": "private"
                    }
                },
                "update_id" : 123456790
            }
        ],
        "ok" : true
    }"#;

    let _: Response<Vec<Update>> = json::decode(&blob).unwrap();
}
<|endoftext|>


<commit_before>use rand::StdRng;
use rand::Rng;
use rand::SeedableRng;
use std::iter;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::collections::BTreeMap;
use super::terrain::TerrainType;
use super::location::Location;
use super::mapgen;
use super::{AreaSpec};
use super::components::{Category};
use super::spawn::Spawn;

// Note to maintainer: Due to the way serialization works, Area *must* be
// generated to have exactly the same contents every time given the same seed
// value. That means absolutely no outside sources of randomness. Only use an
// internal generator initialized with the given seed value. And watch out for
// surprise randomness. A map generator in a previous project used memory
// addresses of temporary structures as indexing keys, and ended up with a
// nondeterminism bug that depended on the numerical order of the arbitrary
// address values.

#[derive(Copy, Clone, RustcDecodable, RustcEncodable)]
pub struct AreaSeed {
    pub rng_seed: u32,
    pub spec: AreaSpec,
}

#[derive(Clone)]
/// Immutable procedurally generated terrain initialized on random seed.
pub struct Area {
    /// Random number generator seed. Must uniquely define the Area contents.
    pub seed: AreaSeed,
    /// Stored terrain.
    pub terrain: BTreeMap<Location, TerrainType>,
    /// Valid slots to spawn things in, basically open floor and connected to
    /// areas the player can reach. (Does not handle stuff like monsters that
    /// spawn in water for now.)
    _open_slots: Vec<Location>,
    /// Where the player should enter the area.
    player_entrance: Location,
    /// Non-player entities to create when first initializing the map.
    spawns: Vec<(Spawn, Location)>,
}

impl Decodable for Area {
    fn decode<D: Decoder>(d: &mut D) -> Result<Area, D::Error> {
        let seed: AreaSeed = try!(Decodable::decode(d));
        Ok(Area::new(seed.rng_seed, seed.spec))
    }
}

impl Encodable for Area {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.seed.encode(s)
    }
}

impl Area {
    pub fn new(rng_seed: u32, spec: AreaSpec) -> Area {
        let num_mobs = 32;
        let num_items = 12;

        let mut terrain = BTreeMap::new();
        let mut rng: StdRng = SeedableRng::from_seed(&[rng_seed as usize + spec.depth as usize][..]);
        mapgen::gen_herringbone(
            &mut rng,
            &spec,
            |p, t| {terrain.insert(Location::new(0, 0) + p, t);});

        // Generate open slots that can be used to spawn stuff.

        // No connectivity analysis yet, trusting that herringbone map has
        // total connectivity. Later on, use Dijkstra map that spreads from
        // entrance/exit as a reachability floodfill to do something cleverer
        // here.
        let mut opens: Vec<Location> = terrain.iter()
            .filter(|&(_, &t)| t.valid_spawn_spot())
            .map(|(&loc, _)| loc)
            .collect();
        rng.shuffle(&mut opens);

        let entrance = opens.pop().unwrap();

        let mut spawns = vec![];

        // XXX: copy-pasting the space-finding code.
        spawns.extend(
            iter::repeat(Spawn::new(spec.depth, vec![Category::Mob], vec![spec.biome]))
            .take(num_mobs)
            .filter_map(|spawn|
            if let Some(loc) = opens.pop() { Some((spawn, loc)) } else { None }));

        spawns.extend(
            iter::repeat(Spawn::new(spec.depth, vec![Category::Item], vec![spec.biome]))
            .take(num_items)
            .filter_map(|spawn|
            if let Some(loc) = opens.pop() { Some((spawn, loc)) } else { None }));

        Area {
            seed: AreaSeed { rng_seed: rng_seed, spec: spec },
            terrain: terrain,
            _open_slots: opens,
            player_entrance: entrance,
            spawns: spawns,
        }
    }

    /// Return terrain at given location.
    pub fn terrain(&self, loc: Location) -> TerrainType {
        match self.terrain.get(&loc) {
            Some(&t) => t,
            None => self.default_terrain(loc)
        }
    }

    /// List the objects that should be hatched in the world during init. This
    /// is tied to map generation, so it goes in the area module.
    pub fn get_spawns(&self) -> Vec<(Spawn, Location)> { self.spawns.clone() }

    pub fn player_entrance(&self) -> Location {
        self.player_entrance
    }

    fn default_terrain(&self, _loc: Location) -> TerrainType {
        self.seed.spec.biome.default_terrain()
    }
}
<commit_msg>Note about HashMap nondeterminism in mapgen comment<commit_after>use rand::StdRng;
use rand::Rng;
use rand::SeedableRng;
use std::iter;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::collections::BTreeMap;
use super::terrain::TerrainType;
use super::location::Location;
use super::mapgen;
use super::{AreaSpec};
use super::components::{Category};
use super::spawn::Spawn;

// Note to maintainer: Due to the way serialization works, Area *must* be
// generated to have exactly the same contents every time given the same seed
// value. That means absolutely no outside sources of randomness. Only use an
// internal generator initialized with the given seed value. And watch out for
// surprise randomness. A map generator in a previous project used memory
// addresses of temporary structures as indexing keys, and ended up with a
// nondeterminism bug that depended on the numerical order of the arbitrary
// address values. Relying on the iteration order of collections::HashMap has
// introduced at least one nondeterminism bug to map generation.

#[derive(Copy, Clone, RustcDecodable, RustcEncodable)]
pub struct AreaSeed {
    pub rng_seed: u32,
    pub spec: AreaSpec,
}

#[derive(Clone)]
/// Immutable procedurally generated terrain initialized on random seed.
pub struct Area {
    /// Random number generator seed. Must uniquely define the Area contents.
    pub seed: AreaSeed,
    /// Stored terrain.
    pub terrain: BTreeMap<Location, TerrainType>,
    /// Valid slots to spawn things in, basically open floor and connected to
    /// areas the player can reach. (Does not handle stuff like monsters that
    /// spawn in water for now.)
    _open_slots: Vec<Location>,
    /// Where the player should enter the area.
    player_entrance: Location,
    /// Non-player entities to create when first initializing the map.
    spawns: Vec<(Spawn, Location)>,
}

impl Decodable for Area {
    fn decode<D: Decoder>(d: &mut D) -> Result<Area, D::Error> {
        let seed: AreaSeed = try!(Decodable::decode(d));
        Ok(Area::new(seed.rng_seed, seed.spec))
    }
}

impl Encodable for Area {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.seed.encode(s)
    }
}

impl Area {
    pub fn new(rng_seed: u32, spec: AreaSpec) -> Area {
        let num_mobs = 32;
        let num_items = 12;

        let mut terrain = BTreeMap::new();
        let mut rng: StdRng = SeedableRng::from_seed(&[rng_seed as usize + spec.depth as usize][..]);
        mapgen::gen_herringbone(
            &mut rng,
            &spec,
            |p, t| {terrain.insert(Location::new(0, 0) + p, t);});

        // Generate open slots that can be used to spawn stuff.

        // No connectivity analysis yet, trusting that herringbone map has
        // total connectivity. Later on, use Dijkstra map that spreads from
        // entrance/exit as a reachability floodfill to do something cleverer
        // here.
        let mut opens: Vec<Location> = terrain.iter()
            .filter(|&(_, &t)| t.valid_spawn_spot())
            .map(|(&loc, _)| loc)
            .collect();
        rng.shuffle(&mut opens);

        let entrance = opens.pop().unwrap();

        let mut spawns = vec![];

        // XXX: copy-pasting the space-finding code.
        spawns.extend(
            iter::repeat(Spawn::new(spec.depth, vec![Category::Mob], vec![spec.biome]))
            .take(num_mobs)
            .filter_map(|spawn|
            if let Some(loc) = opens.pop() { Some((spawn, loc)) } else { None }));

        spawns.extend(
            iter::repeat(Spawn::new(spec.depth, vec![Category::Item], vec![spec.biome]))
            .take(num_items)
            .filter_map(|spawn|
            if let Some(loc) = opens.pop() { Some((spawn, loc)) } else { None }));

        Area {
            seed: AreaSeed { rng_seed: rng_seed, spec: spec },
            terrain: terrain,
            _open_slots: opens,
            player_entrance: entrance,
            spawns: spawns,
        }
    }

    /// Return terrain at given location.
    pub fn terrain(&self, loc: Location) -> TerrainType {
        match self.terrain.get(&loc) {
            Some(&t) => t,
            None => self.default_terrain(loc)
        }
    }

    /// List the objects that should be hatched in the world during init. This
    /// is tied to map generation, so it goes in the area module.
    pub fn get_spawns(&self) -> Vec<(Spawn, Location)> { self.spawns.clone() }

    pub fn player_entrance(&self) -> Location {
        self.player_entrance
    }

    fn default_terrain(&self, _loc: Location) -> TerrainType {
        self.seed.spec.biome.default_terrain()
    }
}
<|endoftext|>


<commit_before>#[allow(dead_code)]
use xml;
use xml::reader::events::XmlEvent;
use std::borrow::Cow;

enum XmlParserState {
    Idle,
    MethodName,
    Parami4
}

pub struct XmlRequest<'a> {
    method_name: Cow<'a, str>,
}

impl<'a> XmlRequest<'a> {
    pub fn parse_xmlrpc_request(&mut self, request_str: &str) {
        let mut parser = xml::EventReader::from_str(request_str);
        let mut state = XmlParserState::Idle;

        loop {
            state = match state {
                XmlParserState::Idle => {
                    match parser.next() {
                        XmlEvent::EndDocument | XmlEvent::Error(_) => break,
                        XmlEvent::StartDocument { .. } => XmlParserState::Idle,
                        XmlEvent::StartElement { name, .. } => {
                            match name.local_name.as_ref() {
                                "methodName" => {
                                    self.method_name = Cow::Owned(name.local_name);
                                    XmlParserState::MethodName
                                }
                                "i4" => XmlParserState::Parami4,
                                // TODO: handle all opening tags
                                _ => XmlParserState::Idle
                            }
                        },
                        // TODO: match the closing element.
                        _ => {
                            println!("Non start element");
                            XmlParserState::Idle
                        }
                    }
                }
                XmlParserState::MethodName => {
                    match parser.next() {
                        XmlEvent::Characters(text) => {
                            println!("Method name characters: {}", text);
                            //self.method_name = text;
                            XmlParserState::MethodName
                        },
                        _ => {
                            XmlParserState::Idle
                        }
                    }
                }
                XmlParserState::Parami4 => {
                    match parser.next() {
                        XmlEvent::Characters(text) => {
                            println!("Param i4: {}", text);
                            XmlParserState::Idle
                        }
                        _ => XmlParserState::Idle
                    }
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::XmlRequest;
    use std::borrow::Cow;

    #[test]
    fn test_parse_xml() {
        let request_str= "\
        <?xml version=\"1.0\"?>\n\
        <methodCall>\n\
          <methodName>life</methodName>\n\
          <params>\n\
            <param>\n\
              <value><i4>42</i4></value>\n\
            </param>\n\
          </params>\n\
        </methodCall>\n";
        let mut xml_request_parser = XmlRequest { method_name: Cow::Borrowed("")};
        xml_request_parser.parse_xmlrpc_request(request_str);
        assert_eq!(xml_request_parser.method_name, "life");
    }
}
<commit_msg>Store the method mane when finding it<commit_after>#[allow(dead_code)]
use xml;
use xml::reader::events::XmlEvent;
use std::borrow::Cow;

enum XmlParserState {
    Idle,
    MethodName,
    Parami4
}

pub struct XmlRequest<'a> {
    method_name: Cow<'a, str>,
}

impl<'a> XmlRequest<'a> {
    pub fn parse_xmlrpc_request(&mut self, request_str: &str) {
        let mut parser = xml::EventReader::from_str(request_str);
        let mut state = XmlParserState::Idle;

        loop {
            state = match state {
                XmlParserState::Idle => {
                    match parser.next() {
                        XmlEvent::EndDocument | XmlEvent::Error(_) => break,
                        XmlEvent::StartDocument { .. } => XmlParserState::Idle,
                        XmlEvent::StartElement { name, .. } => {
                            match name.local_name.as_ref() {
                                "methodName" => {
                                    XmlParserState::MethodName
                                }
                                "i4" => XmlParserState::Parami4,
                                // TODO: handle all opening tags
                                _ => XmlParserState::Idle
                            }
                        },
                        // TODO: match the closing element.
                        _ => {
                            println!("Non start element");
                            XmlParserState::Idle
                        }
                    }
                }
                XmlParserState::MethodName => {
                    match parser.next() {
                        XmlEvent::Characters(text) => {
                            println!("Method name characters: {}", text);
                            self.method_name = Cow::Owned(text);
                            XmlParserState::MethodName
                        },
                        _ => {
                            XmlParserState::Idle
                        }
                    }
                }
                XmlParserState::Parami4 => {
                    match parser.next() {
                        XmlEvent::Characters(text) => {
                            println!("Param i4: {}", text);
                            XmlParserState::Idle
                        }
                        _ => XmlParserState::Idle
                    }
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::XmlRequest;
    use std::borrow::Cow;

    #[test]
    fn test_parse_xml() {
        let request_str= "\
        <?xml version=\"1.0\"?>\n\
        <methodCall>\n\
          <methodName>life</methodName>\n\
          <params>\n\
            <param>\n\
              <value><i4>42</i4></value>\n\
            </param>\n\
          </params>\n\
        </methodCall>\n";
        let mut xml_request_parser = XmlRequest { method_name: Cow::Borrowed("")};
        xml_request_parser.parse_xmlrpc_request(request_str);
        assert_eq!(xml_request_parser.method_name, "life");
    }
}
<|endoftext|>


<commit_before>
pub fn key_xor(data: &[u8], key: u8) -> Vec<u8> {
    data.iter().map(|&x| x ^ key ).collect()
}

fn rel_square_dist(values1: &[f64], values2: &[f64]) -> f64 {
    values1.iter()
           .zip(values2.iter())
           .fold(0.0, |s, (&a, &b)| {
               let rel = if a != 0.0 { b/a - 1.0 } else { 1.0 };
               s + rel * rel
           })
           .sqrt()
}

fn count_letters(data: &[u8]) -> Vec<uint> {
    let mut act_count = Vec::from_fn(26, |x| 0 * x );

    for c in data.iter() {
        match *c as uint {
            uc@65...90 => act_count[uc-65] += 1,
            lc@97...122 => act_count[lc-97] += 1,
            _ => ()
        }
    }

    act_count
}

pub fn score(data: &[u8]) -> f64 {
    // normal frequencies of english letters a-z in %
    let nom_frequencies : &[f64] = [ 8.167, 1.492, 2.782, 4.253, 12.702, 2.228, 2.015, 6.094, 6.966, 0.153, 0.772, 4.025,
        2.406, 6.749, 7.507, 1.929, 0.095, 5.987, 6.327, 9.056, 2.758, 0.978, 2.360, 0.150, 1.974, 0.074 ];

    let act_count = count_letters(data);
    let total = act_count.iter().fold(0, |s, &a| s + a);

    if total == 0 {
        // no characters found at all
        return data.len() as f64 * 100.0;
    }

    let act_frequencies : Vec<f64> = act_count.iter().map(|&v| (v as f64) * 100f64 / (total as f64)).collect();

    (data.len() - total) as f64 + rel_square_dist(nom_frequencies, act_frequencies.as_slice())
}

pub fn decode_xor(data: &[u8]) -> (Vec<u8>, u8, f64) {
    let mut best_score = 100.0f64;
    let mut best_result = vec![];
    let mut best_key = 0u8;
    // keep TAB, LF, CR as printable
    let unprintable_chars : [u8, ..30]= [0,1,2,3,4,5,6,7,8,11,12,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,127];

    for key in range(0u8, 255u8) {
        let plain = key_xor(data, key);
        let unprintable = plain.iter().filter( |&c| unprintable_chars.iter().any(|&v| v == *c) ).count();

        // unprintable characters are out immediately
        if unprintable > 0 {
            continue;
        }

        // score the remaining possibilities
        let new_score = score(plain.as_slice());

        if new_score < best_score {
            best_result = plain;
            best_score = new_score;
            best_key = key;
        }
    }

    (best_result, best_key, best_score)
}

#[test]
fn test_key_xor() {
    assert_eq!(key_xor([255, 128, 0], 64), vec![191, 192, 64]);
}

#[test]
fn test_rel_square_dist() {
    assert_eq!(rel_square_dist([],[]), 0.0f64);
    assert_eq!(rel_square_dist([1.0, 1.0],[1.0, 1.0]), 0.0);
    assert_eq!(rel_square_dist([0.0, 1.0],[1.0, 0.0]), 2.0.sqrt());
    assert_eq!(rel_square_dist([-1.0, 1.0, 1.0],[1.0, -1.0, 0.0]), 3.0);}

#[test]
fn test_count_letters() {
    assert_eq!(count_letters([]), vec![0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
    assert_eq!(count_letters(b"abcdabc"), vec![2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
    assert_eq!(count_letters(b"zZzZxXxX"), vec![0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,4]);
    assert_eq!(count_letters(b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), vec![2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]);
}

#[test]
fn test_score_basics() {
    assert_eq!(score([]), score(b"232093582$%$!-_.,") );
    assert!(score([]) > score(b"A") );
    assert!(score(b"this is the end, my friend") < score(b"7ufhgvbnftz56ufgvghtzuh54") );
    assert_eq!(score(b"this is the end, my friend"), score(b"endmythisfriend!!!theis.") );
}

#[test]
fn test_score_challenge() {
    assert!( score([11, 42, 50, 101, 49, 45, 36, 49, 101, 49, 45, 32, 101, 53, 36, 55, 49, 60, 101, 44, 54, 101, 47, 48, 40, 53, 44, 43, 34, 79])
           > score([78, 111, 119, 32, 116, 104, 97, 116, 32, 116, 104, 101, 32, 112, 97, 114, 116, 121, 32, 105, 115, 32, 106, 117, 109, 112, 105, 110, 103, 10]) )
}
<commit_msg>Increase penalty for non letter characters<commit_after>
pub fn key_xor(data: &[u8], key: u8) -> Vec<u8> {
    data.iter().map(|&x| x ^ key ).collect()
}

fn rel_square_dist(values1: &[f64], values2: &[f64]) -> f64 {
    values1.iter()
           .zip(values2.iter())
           .fold(0.0, |s, (&a, &b)| {
               let rel = if a != 0.0 { b/a - 1.0 } else { 1.0 };
               s + rel * rel
           })
           .sqrt()
}

fn count_letters(data: &[u8]) -> Vec<uint> {
    let mut act_count = Vec::from_fn(26, |x| 0 * x );

    for c in data.iter() {
        match *c as uint {
            uc@65...90 => act_count[uc-65] += 1,
            lc@97...122 => act_count[lc-97] += 1,
            _ => ()
        }
    }

    act_count
}

pub fn score(data: &[u8]) -> f64 {
    // normal frequencies of english letters a-z in %
    let nom_frequencies : &[f64] = [ 8.167, 1.492, 2.782, 4.253, 12.702, 2.228, 2.015, 6.094, 6.966, 0.153, 0.772, 4.025,
        2.406, 6.749, 7.507, 1.929, 0.095, 5.987, 6.327, 9.056, 2.758, 0.978, 2.360, 0.150, 1.974, 0.074 ];

    let act_count = count_letters(data);
    let total = act_count.iter().fold(0, |s, &a| s + a);

    if total == 0 {
        // no characters found at all
        return data.len() as f64 * 100.0;
    }

    let act_frequencies : Vec<f64> = act_count.iter().map(|&v| (v as f64) * 100f64 / (total as f64)).collect();

    (data.len() - total) as f64 * 10.0 + rel_square_dist(nom_frequencies, act_frequencies.as_slice())
}

pub fn decode_xor(data: &[u8]) -> (Vec<u8>, u8, f64) {
    let mut best_score = 1000.0f64;
    let mut best_result = vec![];
    let mut best_key = 0u8;
    // keep TAB, LF, CR as printable
    let unprintable_chars : [u8, ..30]= [0,1,2,3,4,5,6,7,8,11,12,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,127];

    for key in range(0u8, 255u8) {
        let plain = key_xor(data, key);
        let unprintable = plain.iter().filter( |&c| unprintable_chars.iter().any(|&v| v == *c) ).count();

        // unprintable characters are out immediately
        if unprintable > 0 {
            continue;
        }

        // score the remaining possibilities
        let new_score = score(plain.as_slice());

        if new_score < best_score {
            best_result = plain;
            best_score = new_score;
            best_key = key;
        }
    }

    (best_result, best_key, best_score)
}

#[test]
fn test_key_xor() {
    assert_eq!(key_xor([255, 128, 0], 64), vec![191, 192, 64]);
}

#[test]
fn test_rel_square_dist() {
    assert_eq!(rel_square_dist([],[]), 0.0f64);
    assert_eq!(rel_square_dist([1.0, 1.0],[1.0, 1.0]), 0.0);
    assert_eq!(rel_square_dist([0.0, 1.0],[1.0, 0.0]), 2.0.sqrt());
    assert_eq!(rel_square_dist([-1.0, 1.0, 1.0],[1.0, -1.0, 0.0]), 3.0);}

#[test]
fn test_count_letters() {
    assert_eq!(count_letters([]), vec![0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
    assert_eq!(count_letters(b"abcdabc"), vec![2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
    assert_eq!(count_letters(b"zZzZxXxX"), vec![0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,4]);
    assert_eq!(count_letters(b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), vec![2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]);
}

#[test]
fn test_score_basics() {
    assert_eq!(score([]), score(b"232093582$%$!-_.,") );
    assert!(score([]) > score(b"A") );
    assert!(score(b"this is the end, my friend") < score(b"7ufhgvbnftz56ufgvghtzuh54") );
    assert_eq!(score(b"this is the end, my friend"), score(b"endmythisfriend!!!theis.") );
}

#[test]
fn test_score_challenge() {
    assert!( score([11, 42, 50, 101, 49, 45, 36, 49, 101, 49, 45, 32, 101, 53, 36, 55, 49, 60, 101, 44, 54, 101, 47, 48, 40, 53, 44, 43, 34, 79])
           > score([78, 111, 119, 32, 116, 104, 97, 116, 32, 116, 104, 101, 32, 112, 97, 114, 116, 121, 32, 105, 115, 32, 106, 117, 109, 112, 105, 110, 103, 10]) )
}
<|endoftext|>


<commit_before><commit_msg>finally fixed :)<commit_after><|endoftext|>