<commit_before>#![feature(test)]

extern crate test;
extern crate num_bigint;
extern crate num_integer;
extern crate num_traits;
extern crate rand;

use test::Bencher;
use num_bigint::{BigUint, RandBigInt};
use num_integer::Integer;
use num_traits::Zero;
use rand::{SeedableRng, StdRng};

fn get_rng() -> StdRng {
    let seed: &[_] = &[1, 2, 3, 4];
    SeedableRng::from_seed(seed)
}

fn bench(b: &mut Bencher, bits: usize, gcd: fn(&BigUint, &BigUint) -> BigUint) {
    let mut rng = get_rng();
    let x = rng.gen_biguint(bits);
    let y = rng.gen_biguint(bits);

    assert_eq!(euclid(&x, &y), x.gcd(&y));

    b.iter(|| gcd(&x, &y));
}

fn euclid(x: &BigUint, y: &BigUint) -> BigUint {
    // Use Euclid's algorithm
    let mut m = x.clone();
    let mut n = y.clone();
    while !m.is_zero() {
        let temp = m;
        m = n % &temp;
        n = temp;
    }
    return n;
}

#[bench]
fn gcd_euclid_0064(b: &mut Bencher) {
    bench(b, 64, euclid);
}

#[bench]
fn gcd_euclid_0256(b: &mut Bencher) {
    bench(b, 256, euclid);
}

#[bench]
fn gcd_euclid_1024(b: &mut Bencher) {
    bench(b, 1024, euclid);
}

#[bench]
fn gcd_euclid_4096(b: &mut Bencher) {
    bench(b, 4096, euclid);
}

// Integer for BigUint now uses Stein for gcd

#[bench]
fn gcd_stein_0064(b: &mut Bencher) {
    bench(b, 64, BigUint::gcd);
}

#[bench]
fn gcd_stein_0256(b: &mut Bencher) {
    bench(b, 256, BigUint::gcd);
}

#[bench]
fn gcd_stein_1024(b: &mut Bencher) {
    bench(b, 1024, BigUint::gcd);
}

#[bench]
fn gcd_stein_4096(b: &mut Bencher) {
    bench(b, 4096, BigUint::gcd);
}
<commit_msg>chmod -x benches/gcd.rs<commit_after>#![feature(test)]

extern crate test;
extern crate num_bigint;
extern crate num_integer;
extern crate num_traits;
extern crate rand;

use test::Bencher;
use num_bigint::{BigUint, RandBigInt};
use num_integer::Integer;
use num_traits::Zero;
use rand::{SeedableRng, StdRng};

fn get_rng() -> StdRng {
    let seed: &[_] = &[1, 2, 3, 4];
    SeedableRng::from_seed(seed)
}

fn bench(b: &mut Bencher, bits: usize, gcd: fn(&BigUint, &BigUint) -> BigUint) {
    let mut rng = get_rng();
    let x = rng.gen_biguint(bits);
    let y = rng.gen_biguint(bits);

    assert_eq!(euclid(&x, &y), x.gcd(&y));

    b.iter(|| gcd(&x, &y));
}

fn euclid(x: &BigUint, y: &BigUint) -> BigUint {
    // Use Euclid's algorithm
    let mut m = x.clone();
    let mut n = y.clone();
    while !m.is_zero() {
        let temp = m;
        m = n % &temp;
        n = temp;
    }
    return n;
}

#[bench]
fn gcd_euclid_0064(b: &mut Bencher) {
    bench(b, 64, euclid);
}

#[bench]
fn gcd_euclid_0256(b: &mut Bencher) {
    bench(b, 256, euclid);
}

#[bench]
fn gcd_euclid_1024(b: &mut Bencher) {
    bench(b, 1024, euclid);
}

#[bench]
fn gcd_euclid_4096(b: &mut Bencher) {
    bench(b, 4096, euclid);
}

// Integer for BigUint now uses Stein for gcd

#[bench]
fn gcd_stein_0064(b: &mut Bencher) {
    bench(b, 64, BigUint::gcd);
}

#[bench]
fn gcd_stein_0256(b: &mut Bencher) {
    bench(b, 256, BigUint::gcd);
}

#[bench]
fn gcd_stein_1024(b: &mut Bencher) {
    bench(b, 1024, BigUint::gcd);
}

#[bench]
fn gcd_stein_4096(b: &mut Bencher) {
    bench(b, 4096, BigUint::gcd);
}
<|endoftext|>


<commit_before>use crate::cdsl::operands::{OperandKind, OperandKindBuilder as Builder};

use std::collections::HashMap;

pub fn define() -> Vec<OperandKind> {
    let mut kinds = Vec::new();

    // A 64-bit immediate integer operand.
    //
    // This type of immediate integer can interact with SSA values with any
    // IntType type.
    let imm64 = Builder::new_imm("imm64")
        .doc("A 64-bit immediate integer.")
        .finish();
    kinds.push(imm64);

    // An unsigned 8-bit immediate integer operand.
    //
    // This small operand is used to indicate lane indexes in SIMD vectors and
    // immediate bit counts on shift instructions.
    let uimm8 = Builder::new_imm("uimm8")
        .doc("An 8-bit immediate unsigned integer.")
        .finish();
    kinds.push(uimm8);

    // An unsigned 32-bit immediate integer operand.
    let uimm32 = Builder::new_imm("uimm32")
        .doc("A 32-bit immediate unsigned integer.")
        .finish();
    kinds.push(uimm32);

    // A 32-bit immediate signed offset.
    //
    // This is used to represent an immediate address offset in load/store
    // instructions.
    let offset32 = Builder::new_imm("offset32")
        .doc("A 32-bit immediate signed offset.")
        .default_member("offset")
        .finish();
    kinds.push(offset32);

    // A 32-bit immediate floating point operand.
    //
    // IEEE 754-2008 binary32 interchange format.
    let ieee32 = Builder::new_imm("ieee32")
        .doc("A 32-bit immediate floating point number.")
        .finish();
    kinds.push(ieee32);

    // A 64-bit immediate floating point operand.
    //
    // IEEE 754-2008 binary64 interchange format.
    let ieee64 = Builder::new_imm("ieee64")
        .doc("A 64-bit immediate floating point number.")
        .finish();
    kinds.push(ieee64);

    // An immediate boolean operand.
    //
    // This type of immediate boolean can interact with SSA values with any
    // BoolType type.
    let boolean = Builder::new_imm("boolean")
        .doc("An immediate boolean.")
        .rust_type("bool")
        .finish();
    kinds.push(boolean);

    // A condition code for comparing integer values.
    // This enumerated operand kind is used for the `icmp` instruction and corresponds to the
    // condcodes::IntCC` Rust type.
    let mut intcc_values = HashMap::new();
    intcc_values.insert("eq", "Equal");
    intcc_values.insert("ne", "NotEqual");
    intcc_values.insert("sge", "UnsignedGreaterThanOrEqual");
    intcc_values.insert("sgt", "UnsignedGreaterThan");
    intcc_values.insert("sle", "UnsignedLessThanOrEqual");
    intcc_values.insert("slt", "UnsignedLessThan");
    intcc_values.insert("uge", "UnsignedGreaterThanOrEqual");
    intcc_values.insert("ugt", "UnsignedGreaterThan");
    intcc_values.insert("ule", "UnsignedLessThanOrEqual");
    intcc_values.insert("ult", "UnsignedLessThan");
    let intcc = Builder::new_enum("intcc", intcc_values)
        .doc("An integer comparison condition code.")
        .default_member("cond")
        .rust_type("ir::condcodes::IntCC")
        .finish();
    kinds.push(intcc);

    // A condition code for comparing floating point values.  This enumerated operand kind is used
    // for the `fcmp` instruction and corresponds to the `condcodes::FloatCC` Rust type.
    let mut floatcc_values = HashMap::new();
    floatcc_values.insert("ord", "Ordered");
    floatcc_values.insert("uno", "Unordered");
    floatcc_values.insert("eq", "Equal");
    floatcc_values.insert("ne", "NotEqual");
    floatcc_values.insert("one", "OrderedNotEqual");
    floatcc_values.insert("ueq", "UnorderedOrEqual");
    floatcc_values.insert("lt", "LessThan");
    floatcc_values.insert("le", "LessThanOrEqual");
    floatcc_values.insert("gt", "GreaterThan");
    floatcc_values.insert("ge", "GreaterThanOrEqual");
    floatcc_values.insert("ult", "UnorderedOrLessThan");
    floatcc_values.insert("ule", "UnorderedOrLessThanOrEqual");
    floatcc_values.insert("ugt", "UnorderedOrGreaterThan");
    floatcc_values.insert("uge", "UnorderedOrGreaterThanOrEqual");
    let floatcc = Builder::new_enum("floatcc", floatcc_values)
        .doc("A floating point comparison condition code")
        .default_member("cond")
        .rust_type("ir::condcodes::FloatCC")
        .finish();
    kinds.push(floatcc);

    // Flags for memory operations like :clif:inst:`load` and :clif:inst:`store`.
    let memflags = Builder::new_imm("memflags")
        .doc("Memory operation flags")
        .default_member("flags")
        .rust_type("ir::MemFlags")
        .finish();
    kinds.push(memflags);

    // A register unit in the current target ISA.
    let regunit = Builder::new_imm("regunit")
        .doc("A register unit in the target ISA")
        .rust_type("isa::RegUnit")
        .finish();
    kinds.push(regunit);

    // A trap code indicating the reason for trapping.
    //
    // The Rust enum type also has a `User(u16)` variant for user-provided trap
    // codes.
    let mut trapcode_values = HashMap::new();
    trapcode_values.insert("stk_ovf", "StackOverflow");
    trapcode_values.insert("heap_oob", "HeapOutOfBounds");
    trapcode_values.insert("int_ovf", "IntegerOverflow");
    trapcode_values.insert("int_divz", "IntegerDivisionByZero");
    let trapcode = Builder::new_enum("trapcode", trapcode_values)
        .doc("A trap reason code.")
        .default_member("code")
        .rust_type("ir::TrapCode")
        .finish();
    kinds.push(trapcode);

    return kinds;
}
<commit_msg>[meta] Fix condition codes in immediates;<commit_after>use crate::cdsl::operands::{OperandKind, OperandKindBuilder as Builder};

use std::collections::HashMap;

pub fn define() -> Vec<OperandKind> {
    let mut kinds = Vec::new();

    // A 64-bit immediate integer operand.
    //
    // This type of immediate integer can interact with SSA values with any
    // IntType type.
    let imm64 = Builder::new_imm("imm64")
        .doc("A 64-bit immediate integer.")
        .finish();
    kinds.push(imm64);

    // An unsigned 8-bit immediate integer operand.
    //
    // This small operand is used to indicate lane indexes in SIMD vectors and
    // immediate bit counts on shift instructions.
    let uimm8 = Builder::new_imm("uimm8")
        .doc("An 8-bit immediate unsigned integer.")
        .finish();
    kinds.push(uimm8);

    // An unsigned 32-bit immediate integer operand.
    let uimm32 = Builder::new_imm("uimm32")
        .doc("A 32-bit immediate unsigned integer.")
        .finish();
    kinds.push(uimm32);

    // A 32-bit immediate signed offset.
    //
    // This is used to represent an immediate address offset in load/store
    // instructions.
    let offset32 = Builder::new_imm("offset32")
        .doc("A 32-bit immediate signed offset.")
        .default_member("offset")
        .finish();
    kinds.push(offset32);

    // A 32-bit immediate floating point operand.
    //
    // IEEE 754-2008 binary32 interchange format.
    let ieee32 = Builder::new_imm("ieee32")
        .doc("A 32-bit immediate floating point number.")
        .finish();
    kinds.push(ieee32);

    // A 64-bit immediate floating point operand.
    //
    // IEEE 754-2008 binary64 interchange format.
    let ieee64 = Builder::new_imm("ieee64")
        .doc("A 64-bit immediate floating point number.")
        .finish();
    kinds.push(ieee64);

    // An immediate boolean operand.
    //
    // This type of immediate boolean can interact with SSA values with any
    // BoolType type.
    let boolean = Builder::new_imm("boolean")
        .doc("An immediate boolean.")
        .rust_type("bool")
        .finish();
    kinds.push(boolean);

    // A condition code for comparing integer values.
    // This enumerated operand kind is used for the `icmp` instruction and corresponds to the
    // condcodes::IntCC` Rust type.
    let mut intcc_values = HashMap::new();
    intcc_values.insert("eq", "Equal");
    intcc_values.insert("ne", "NotEqual");
    intcc_values.insert("sge", "SignedGreaterThanOrEqual");
    intcc_values.insert("sgt", "SignedGreaterThan");
    intcc_values.insert("sle", "SignedLessThanOrEqual");
    intcc_values.insert("slt", "SignedLessThan");
    intcc_values.insert("uge", "UnsignedGreaterThanOrEqual");
    intcc_values.insert("ugt", "UnsignedGreaterThan");
    intcc_values.insert("ule", "UnsignedLessThanOrEqual");
    intcc_values.insert("ult", "UnsignedLessThan");
    let intcc = Builder::new_enum("intcc", intcc_values)
        .doc("An integer comparison condition code.")
        .default_member("cond")
        .rust_type("ir::condcodes::IntCC")
        .finish();
    kinds.push(intcc);

    // A condition code for comparing floating point values.  This enumerated operand kind is used
    // for the `fcmp` instruction and corresponds to the `condcodes::FloatCC` Rust type.
    let mut floatcc_values = HashMap::new();
    floatcc_values.insert("ord", "Ordered");
    floatcc_values.insert("uno", "Unordered");
    floatcc_values.insert("eq", "Equal");
    floatcc_values.insert("ne", "NotEqual");
    floatcc_values.insert("one", "OrderedNotEqual");
    floatcc_values.insert("ueq", "UnorderedOrEqual");
    floatcc_values.insert("lt", "LessThan");
    floatcc_values.insert("le", "LessThanOrEqual");
    floatcc_values.insert("gt", "GreaterThan");
    floatcc_values.insert("ge", "GreaterThanOrEqual");
    floatcc_values.insert("ult", "UnorderedOrLessThan");
    floatcc_values.insert("ule", "UnorderedOrLessThanOrEqual");
    floatcc_values.insert("ugt", "UnorderedOrGreaterThan");
    floatcc_values.insert("uge", "UnorderedOrGreaterThanOrEqual");
    let floatcc = Builder::new_enum("floatcc", floatcc_values)
        .doc("A floating point comparison condition code")
        .default_member("cond")
        .rust_type("ir::condcodes::FloatCC")
        .finish();
    kinds.push(floatcc);

    // Flags for memory operations like :clif:inst:`load` and :clif:inst:`store`.
    let memflags = Builder::new_imm("memflags")
        .doc("Memory operation flags")
        .default_member("flags")
        .rust_type("ir::MemFlags")
        .finish();
    kinds.push(memflags);

    // A register unit in the current target ISA.
    let regunit = Builder::new_imm("regunit")
        .doc("A register unit in the target ISA")
        .rust_type("isa::RegUnit")
        .finish();
    kinds.push(regunit);

    // A trap code indicating the reason for trapping.
    //
    // The Rust enum type also has a `User(u16)` variant for user-provided trap
    // codes.
    let mut trapcode_values = HashMap::new();
    trapcode_values.insert("stk_ovf", "StackOverflow");
    trapcode_values.insert("heap_oob", "HeapOutOfBounds");
    trapcode_values.insert("int_ovf", "IntegerOverflow");
    trapcode_values.insert("int_divz", "IntegerDivisionByZero");
    let trapcode = Builder::new_enum("trapcode", trapcode_values)
        .doc("A trap reason code.")
        .default_member("code")
        .rust_type("ir::TrapCode")
        .finish();
    kinds.push(trapcode);

    return kinds;
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A timer thread that gives the painting task a little time to catch up when the user scrolls.

use compositor_task::{CompositorProxy, Msg};
use std::sync::mpsc::{Receiver, Sender, channel};
use std::thread::{Builder, sleep_ms};
use time;

/// The amount of time in nanoseconds that we give to the painting thread to paint new tiles upon
/// processing a scroll event that caused new tiles to be revealed. When this expires, we give up
/// and composite anyway (showing a "checkerboard") to avoid dropping the frame.
static TIMEOUT: i64 = 12_000_000;

pub struct ScrollingTimerProxy {
    sender: Sender<ToScrollingTimerMsg>,
}

pub struct ScrollingTimer {
    compositor_proxy: Box<CompositorProxy>,
    receiver: Receiver<ToScrollingTimerMsg>,
}

enum ToScrollingTimerMsg {
    ExitMsg,
    ScrollEventProcessedMsg(u64),
}

impl ScrollingTimerProxy {
    pub fn new(compositor_proxy: Box<CompositorProxy + Send>) -> ScrollingTimerProxy {
        let (to_scrolling_timer_sender, to_scrolling_timer_receiver) = channel();
        Builder::new().spawn(move || {
            let mut scrolling_timer = ScrollingTimer {
                compositor_proxy: compositor_proxy,
                receiver: to_scrolling_timer_receiver,
            };
            scrolling_timer.run();
        }).unwrap();
        ScrollingTimerProxy {
            sender: to_scrolling_timer_sender,
        }
    }

    pub fn scroll_event_processed(&mut self, timestamp: u64) {
        self.sender.send(ToScrollingTimerMsg::ScrollEventProcessedMsg(timestamp)).unwrap()
    }

    pub fn shutdown(&mut self) {
        self.sender.send(ToScrollingTimerMsg::ExitMsg).unwrap()
    }
}

impl ScrollingTimer {
    pub fn run(&mut self) {
        loop {
            match self.receiver.recv() {
                Ok(ToScrollingTimerMsg::ScrollEventProcessedMsg(timestamp)) => {
                    let target = timestamp as i64 + TIMEOUT;
                    let delta_ns = target - (time::precise_time_ns() as i64);
                    sleep_ms((delta_ns / 1000000) as u32);
                    self.compositor_proxy.send(Msg::ScrollTimeout(timestamp));
                }
                Ok(ToScrollingTimerMsg::ExitMsg) | Err(_) => break,
            }
        }
    }
}

<commit_msg>Use while let{} instead of loop{match{}} in ScrollingTimer::run()<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A timer thread that gives the painting task a little time to catch up when the user scrolls.

use compositor_task::{CompositorProxy, Msg};
use std::sync::mpsc::{Receiver, Sender, channel};
use std::thread::{Builder, sleep_ms};
use time;

/// The amount of time in nanoseconds that we give to the painting thread to paint new tiles upon
/// processing a scroll event that caused new tiles to be revealed. When this expires, we give up
/// and composite anyway (showing a "checkerboard") to avoid dropping the frame.
static TIMEOUT: i64 = 12_000_000;

pub struct ScrollingTimerProxy {
    sender: Sender<ToScrollingTimerMsg>,
}

pub struct ScrollingTimer {
    compositor_proxy: Box<CompositorProxy>,
    receiver: Receiver<ToScrollingTimerMsg>,
}

enum ToScrollingTimerMsg {
    ExitMsg,
    ScrollEventProcessedMsg(u64),
}

impl ScrollingTimerProxy {
    pub fn new(compositor_proxy: Box<CompositorProxy + Send>) -> ScrollingTimerProxy {
        let (to_scrolling_timer_sender, to_scrolling_timer_receiver) = channel();
        Builder::new().spawn(move || {
            let mut scrolling_timer = ScrollingTimer {
                compositor_proxy: compositor_proxy,
                receiver: to_scrolling_timer_receiver,
            };
            scrolling_timer.run();
        }).unwrap();
        ScrollingTimerProxy {
            sender: to_scrolling_timer_sender,
        }
    }

    pub fn scroll_event_processed(&mut self, timestamp: u64) {
        self.sender.send(ToScrollingTimerMsg::ScrollEventProcessedMsg(timestamp)).unwrap()
    }

    pub fn shutdown(&mut self) {
        self.sender.send(ToScrollingTimerMsg::ExitMsg).unwrap()
    }
}

impl ScrollingTimer {
    pub fn run(&mut self) {
        while let Ok(ToScrollingTimerMsg::ScrollEventProcessedMsg(timestamp)) = self.receiver.recv() {
            let target = timestamp as i64 + TIMEOUT;
            let delta_ns = target - (time::precise_time_ns() as i64);
            sleep_ms((delta_ns / 1000000) as u32);
            self.compositor_proxy.send(Msg::ScrollTimeout(timestamp));
        }
    }
}

<|endoftext|>


<commit_before>use base::{
    AbstractCFType,
    AbstractCFTypeRef,
    CFAllocatorRef,
    CFIndex,
    CFRange,
    CFRelease,
    CFTypeRef,
    kCFAllocatorDefault,
};
use libc::c_void;

pub type CFArrayRetainCallBack = *u8;
pub type CFArrayReleaseCallBack = *u8;
pub type CFArrayCopyDescriptionCallBack = *u8;
pub type CFArrayEqualCallBack = *u8;

pub struct CFArrayCallBacks {
    version: CFIndex,
    retain: CFArrayRetainCallBack,
    release: CFArrayReleaseCallBack,
    copyDescription: CFArrayCopyDescriptionCallBack,
    equal: CFArrayEqualCallBack,
}

struct __CFArray { private: () }
pub type CFArrayRef = *__CFArray;

impl CFArrayRef : AbstractCFTypeRef {
    pure fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }
}

struct CFArray<ElemRefType : AbstractCFTypeRef,
               ElemType    : AbstractCFType<ElemRefType>> {
    obj: CFArrayRef,

    drop {
        unsafe {
            CFRelease(cast::transmute(self.obj))
        }
    }
}

pub impl<ElemRefType : AbstractCFTypeRef,
         ElemType    : AbstractCFType<ElemRefType>>
    CFArray<ElemRefType, ElemType> {
    static fn new(elems: &[ElemType]) -> CFArray<ElemRefType, ElemType> {
        let array_ref : CFArrayRef;

        let elems_refs = do vec::map(elems) |e: &ElemType| { e.get_ref().as_type_ref() };

        unsafe {
            array_ref = CFArrayCreate(kCFAllocatorDefault,
                                      cast::transmute(vec::raw::to_ptr(elems_refs)),
                                      elems.len() as CFIndex,
                                      ptr::to_unsafe_ptr(&kCFTypeArrayCallBacks));
        }
        // return CFArray::wrap(array_ref)
        return CFArray { obj: array_ref };
    }

    pub fn each<A>(cb: fn&(ElemRefType) -> A) {
        for uint::range(0, self.len()) |i| {
            cb(self[i]);
        }
    }

    pub fn eachi<A>(cb: fn&(uint, ElemRefType) -> A) {
        for uint::range(0, self.len()) |i| {
            cb(i, self[i]);
        }
    }

    pub pure fn len() -> uint {
        unsafe { return CFArrayGetCount(self.obj) as uint; }
    }
}

pub impl<ElemRefType : AbstractCFTypeRef,
         ElemType    : AbstractCFType<ElemRefType>>
    CFArray<ElemRefType, ElemType> : AbstractCFType<CFArrayRef> {

    pure fn get_ref() -> CFArrayRef { self.obj }

    static fn wrap(obj: CFArrayRef) -> CFArray<ElemRefType, ElemType> {
        CFArray { obj: obj }
    }

    static fn unwrap(wrapper: CFArray<ElemRefType, ElemType>) -> CFArrayRef {
        wrapper.obj
    }
}

pub impl<ElemRefType : AbstractCFTypeRef,
         ElemType    : AbstractCFType<ElemRefType>>
    CFArray<ElemRefType, ElemType> : Index<uint, ElemRefType> {
    pure fn index(idx: uint) -> ElemRefType {
        assert idx < self.len();
        unsafe {
            let elem = CFArrayGetValueAtIndex(self.obj, idx as CFIndex);
            // Don't return a wrapped thing, since we don't know whether
            // it needs base::wrap() or base::wrap_borrowed()
            return cast::transmute(elem);
        }
    }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    /*
     * CFArray.h
     */
    const kCFTypeArrayCallBacks: CFArrayCallBacks;

    fn CFArrayCreate(allocator: CFAllocatorRef, values: **c_void,
                     numValues: CFIndex, callBacks: *CFArrayCallBacks) -> CFArrayRef;

    fn CFArrayGetValueAtIndex(theArray: CFArrayRef, idx: CFIndex) -> *c_void;
    fn CFArrayGetCount(theArray: CFArrayRef) -> CFIndex;
}

#[test]
fn should_box_and_unbox() {
    use number::CFNumber;

    let arr = CFArray::new([
        CFNumber::new(1 as i32),
        CFNumber::new(2 as i32),
        CFNumber::new(3 as i32),
        CFNumber::new(4 as i32),
        CFNumber::new(5 as i32)]);

    let mut sum = 0i32;
    // TODO: not always safe to re-wrap, unless we addref the element
    for arr.each |elem| {
        sum += elem.to_i32();
    }

    assert sum == 15;
}<commit_msg>Add wrapped and ref versions of CFArray.each/eachi(), and fix test.<commit_after>use base::{
    AbstractCFType,
    AbstractCFTypeRef,
    CFAllocatorRef,
    CFIndex,
    CFRange,
    CFRelease,
    CFTypeRef,
    kCFAllocatorDefault,
};
use libc::c_void;

pub type CFArrayRetainCallBack = *u8;
pub type CFArrayReleaseCallBack = *u8;
pub type CFArrayCopyDescriptionCallBack = *u8;
pub type CFArrayEqualCallBack = *u8;

pub struct CFArrayCallBacks {
    version: CFIndex,
    retain: CFArrayRetainCallBack,
    release: CFArrayReleaseCallBack,
    copyDescription: CFArrayCopyDescriptionCallBack,
    equal: CFArrayEqualCallBack,
}

struct __CFArray { private: () }
pub type CFArrayRef = *__CFArray;

impl CFArrayRef : AbstractCFTypeRef {
    pure fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }
}

struct CFArray<ElemRefType : AbstractCFTypeRef,
               ElemType    : AbstractCFType<ElemRefType>> {
    obj: CFArrayRef,

    drop {
        unsafe {
            CFRelease(cast::transmute(self.obj))
        }
    }
}

pub impl<ElemRefType : AbstractCFTypeRef,
         ElemType    : AbstractCFType<ElemRefType>>
    CFArray<ElemRefType, ElemType> {
    static fn new(elems: &[ElemType]) -> CFArray<ElemRefType, ElemType> {
        let array_ref : CFArrayRef;

        let elems_refs = do vec::map(elems) |e: &ElemType| { e.get_ref().as_type_ref() };

        unsafe {
            array_ref = CFArrayCreate(kCFAllocatorDefault,
                                      cast::transmute(vec::raw::to_ptr(elems_refs)),
                                      elems.len() as CFIndex,
                                      ptr::to_unsafe_ptr(&kCFTypeArrayCallBacks));
        }
        // return CFArray::wrap(array_ref)
        return CFArray { obj: array_ref };
    }

    pub fn each_ref<A>(cb: fn&(ElemRefType) -> A) {
        for uint::range(0, self.len()) |i| { cb(self[i]); }
    }

    pub fn eachi_ref<A>(cb: fn&(uint, ElemRefType) -> A) {
        for uint::range(0, self.len()) |i| { cb(i, self[i]); }
    }

    pub fn each<A>(cb: fn&(&ElemType) -> A) {
        for uint::range(0, self.len()) |i| { cb(&base::wrap(self[i])); }
    }

    pub fn eachi<A>(cb: fn&(uint, &ElemType) -> A) {
        for uint::range(0, self.len()) |i| { cb(i, &base::wrap(self[i])); }
    }

    pub pure fn len() -> uint {
        unsafe { return CFArrayGetCount(self.obj) as uint; }
    }
}

pub impl<ElemRefType : AbstractCFTypeRef,
         ElemType    : AbstractCFType<ElemRefType>>
    CFArray<ElemRefType, ElemType> : AbstractCFType<CFArrayRef> {

    pure fn get_ref() -> CFArrayRef { self.obj }

    static fn wrap(obj: CFArrayRef) -> CFArray<ElemRefType, ElemType> {
        CFArray { obj: obj }
    }

    static fn unwrap(wrapper: CFArray<ElemRefType, ElemType>) -> CFArrayRef {
        wrapper.obj
    }
}

pub impl<ElemRefType : AbstractCFTypeRef,
         ElemType    : AbstractCFType<ElemRefType>>
    CFArray<ElemRefType, ElemType> : Index<uint, ElemRefType> {
    pure fn index(idx: uint) -> ElemRefType {
        assert idx < self.len();
        unsafe {
            let elem = CFArrayGetValueAtIndex(self.obj, idx as CFIndex);
            // Don't return a wrapped thing, since we don't know whether
            // it needs base::wrap() or base::wrap_borrowed()
            return cast::transmute(elem);
        }
    }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    /*
     * CFArray.h
     */
    const kCFTypeArrayCallBacks: CFArrayCallBacks;

    fn CFArrayCreate(allocator: CFAllocatorRef, values: **c_void,
                     numValues: CFIndex, callBacks: *CFArrayCallBacks) -> CFArrayRef;

    fn CFArrayGetValueAtIndex(theArray: CFArrayRef, idx: CFIndex) -> *c_void;
    fn CFArrayGetCount(theArray: CFArrayRef) -> CFIndex;
}

#[test]
fn should_box_and_unbox() {
    use number::{CFNumber, CFNumberRef};

    let arr = CFArray::new([
        CFNumber::new(1 as i32),
        CFNumber::new(2 as i32),
        CFNumber::new(3 as i32),
        CFNumber::new(4 as i32),
        CFNumber::new(5 as i32)]);

    let mut sum = 0i32;
    // TODO: not always safe to re-wrap, unless we addref the element
    for arr.each |elem| {
        sum += elem.to_i32();
    }

    assert sum == 15;

    for arr.each_ref |elem: CFNumberRef| {
        let n: CFNumber = base::wrap(elem);
        sum += n.to_i32();
    }

    assert sum == 30;
}<|endoftext|>


<commit_before>#![feature(test, i128_type)]

extern crate test;
use test::Bencher;

extern crate rand;
extern crate speck;

use rand::Rng;
use rand::OsRng;

use speck::Key;

#[bench]
fn encrypt(mut bencher: &mut Bencher) {
    let (key, block) = gen_test();

    bencher.iter(|| test::black_box(key.encrypt_block(block)));
}

#[bench]
fn decrypt(mut bencher: &mut Bencher) {
    let (key, block) = gen_test();

    bencher.iter(|| test::black_box(key.decrypt_block(block)));
}

fn gen_test() -> (Key, u128) {
    let mut rng = OsRng::new().unwrap();

    (Key::new(rng.gen()), rng.gen())
}
<commit_msg>Added test `generate_key`.<commit_after>#![feature(test, i128_type)]

extern crate test;
use test::Bencher;

extern crate rand;
extern crate speck;

use rand::Rng;
use rand::OsRng;

use speck::Key;

#[bench]
fn generate_key(mut bencher: &mut Bencher) {
    let mut rng = OsRng::new().unwrap();

    let key_input = rng.gen();

    bencher.iter(|| test::black_box(Key::new(key_input)));
}

#[bench]
fn encrypt(mut bencher: &mut Bencher) {
    let (key, block) = gen_test();

    bencher.iter(|| test::black_box(key.encrypt_block(block)));
}

#[bench]
fn decrypt(mut bencher: &mut Bencher) {
    let (key, block) = gen_test();

    bencher.iter(|| test::black_box(key.decrypt_block(block)));
}

fn gen_test() -> (Key, u128) {
    let mut rng = OsRng::new().unwrap();

    (Key::new(rng.gen()), rng.gen())
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017-2018 Ben Ashford
 *
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 * option. This file may not be copied, modified, or distributed
 * except according to those terms.
 */

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

use std::env;

use futures::{future, Future, Sink, Stream};

use redis_async::client;

fn main() {
    // TODO - uncomment
    // let addr = env::args()
    //     .nth(1)
    //     .unwrap_or("127.0.0.1:6379".to_string())
    //     .parse()
    //     .unwrap();

    // let monitor = client::connect(&addr)
    //     .map_err(|e| e.into())
    //     .and_then(|connection| {
    //         let client::ClientConnection { sender, receiver } = connection;
    //         sender
    //             .send(resp_array!["MONITOR"])
    //             .map_err(|e| e.into())
    //             .and_then(move |_| {
    //                 receiver.for_each(|incoming| {
    //                     println!("{:?}", incoming);
    //                     future::ok(())
    //                 })
    //             })
    //     });

    // core.run(monitor).unwrap();
}
<commit_msg>Re-enable MONITOR example<commit_after>/*
 * Copyright 2017-2018 Ben Ashford
 *
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 * option. This file may not be copied, modified, or distributed
 * except according to those terms.
 */

extern crate futures;
#[macro_use]
extern crate redis_async;
extern crate tokio;

use std::env;

use futures::{future, Future, Sink, Stream};

use tokio::executor::current_thread;

use redis_async::client;

fn main() {
    let addr = env::args()
        .nth(1)
        .unwrap_or("127.0.0.1:6379".to_string())
        .parse()
        .unwrap();

    let monitor = client::connect(&addr)
        .map_err(|e| e.into())
        .and_then(|connection| {
            let client::ClientConnection { sender, receiver } = connection;
            sender
                .send(resp_array!["MONITOR"])
                .map_err(|e| e.into())
                .and_then(move |_| {
                    receiver.for_each(|incoming| {
                        println!("{:?}", incoming);
                        future::ok(())
                    })
                })
        });

    current_thread::run(|_| current_thread::spawn(monitor.map_err(|e| println!("ERROR: {:?}", e))));
}
<|endoftext|>


<commit_before>extern crate portmidi as pm;

extern crate rustc_serialize;
extern crate docopt;

const USAGE: &'static str = r#"
portmidi-rs: monitor-device example

Usage:
    monitor-device <id>

Options:
    -h --help   Show this screen.

Omitting <id> will list the available devices.
"#;

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_id: u32,
}

fn print_devices(pm: &pm::PortMidi) {
    for dev in pm.devices().unwrap() {
        println!("{}", dev);
    }
}

fn main() {
    let context = pm::PortMidi::new().unwrap();
    let args: Args = docopt::Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|err| {
        print_devices(&context);
        err.exit();
    });
    let info = context.device(args.arg_id as i32).unwrap();
    println!("Listening on: {}) {}", info.id(), info.name());

    let mut in_port = context.input_port(info).unwrap();
    while let Ok(_) = in_port.poll() {
        if let Ok(Some(event)) = in_port.read() {
            println!("{:?}", event);
        }
    }
}
<commit_msg>Change argument type to omit conversion<commit_after>extern crate portmidi as pm;

extern crate rustc_serialize;
extern crate docopt;

const USAGE: &'static str = r#"
portmidi-rs: monitor-device example

Usage:
    monitor-device <id>

Options:
    -h --help   Show this screen.

Omitting <id> will list the available devices.
"#;

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_id: i32,
}

fn print_devices(pm: &pm::PortMidi) {
    for dev in pm.devices().unwrap() {
        println!("{}", dev);
    }
}

fn main() {
    let context = pm::PortMidi::new().unwrap();
    let args: Args = docopt::Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|err| {
        print_devices(&context);
        err.exit();
    });
    let info = context.device(args.arg_id).unwrap();
    println!("Listening on: {}) {}", info.id(), info.name());

    let mut in_port = context.input_port(info).unwrap();
    while let Ok(_) = in_port.poll() {
        if let Ok(Some(event)) = in_port.read() {
            println!("{:?}", event);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.

use std::cmp;
use std::collections::{BinaryHeap, HashMap};
use std::io;
use std::mem;
use std::sync::{atomic, mpsc};
use std::sync::{Arc, Mutex, Weak};
use std::thread;
use std::time;

use futures::future;
use futures::stream::futures_unordered::FuturesUnordered;
use futures::sync::mpsc as futures_mpsc;
use futures::sync::oneshot;
use futures::{Async, Future, Stream};
use tokio::reactor;
use tokio_current_thread;
use tokio_timer::timer;

use glib;
use gst;

lazy_static! {
    static ref CONTEXTS: Mutex<HashMap<String, Weak<IOContextInner>>> = Mutex::new(HashMap::new());
    static ref CONTEXT_CAT: gst::DebugCategory = gst::DebugCategory::new(
        "ts-context",
        gst::DebugColorFlags::empty(),
        Some("Thread-sharing Context"),
    );
}

// Our own simplified implementation of reactor::Background to allow hooking into its internals
const RUNNING: usize = 0;
const SHUTDOWN_NOW: usize = 1;

struct IOContextRunner {
    name: String,
    shutdown: Arc<atomic::AtomicUsize>,
}

impl IOContextRunner {
    fn start(
        name: &str,
        wait: u32,
        reactor: reactor::Reactor,
        timers: Arc<Mutex<BinaryHeap<TimerEntry>>>,
    ) -> (tokio_current_thread::Handle, IOContextShutdown) {
        let handle = reactor.handle().clone();
        let shutdown = Arc::new(atomic::AtomicUsize::new(RUNNING));
        let shutdown_clone = shutdown.clone();
        let name_clone = name.into();

        let mut runner = IOContextRunner {
            shutdown: shutdown_clone,
            name: name_clone,
        };

        let (sender, receiver) = mpsc::channel();

        let join = thread::spawn(move || {
            runner.run(wait, reactor, sender, timers);
        });

        let shutdown = IOContextShutdown {
            name: name.into(),
            shutdown,
            handle,
            join: Some(join),
        };

        let runtime_handle = receiver.recv().unwrap();

        (runtime_handle, shutdown)
    }

    fn run(
        &mut self,
        wait: u32,
        reactor: reactor::Reactor,
        sender: mpsc::Sender<tokio_current_thread::Handle>,
        timers: Arc<Mutex<BinaryHeap<TimerEntry>>>,
    ) {
        let wait = time::Duration::from_millis(wait as u64);

        gst_debug!(CONTEXT_CAT, "Started reactor thread '{}'", self.name);

        let handle = reactor.handle();
        let mut enter = ::tokio_executor::enter().unwrap();
        let timer = timer::Timer::new(reactor);
        let timer_handle = timer.handle();
        let mut current_thread = tokio_current_thread::CurrentThread::new_with_park(timer);

        let _ = sender.send(current_thread.handle());

        let mut now = time::Instant::now();

        ::tokio_timer::with_default(&timer_handle, &mut enter, |mut enter| {
            ::tokio_reactor::with_default(&handle, &mut enter, |enter| loop {
                if self.shutdown.load(atomic::Ordering::SeqCst) > RUNNING {
                    break;
                }

                gst_trace!(CONTEXT_CAT, "Elapsed {:?} since last loop", now.elapsed());

                // Handle timers
                {
                    // Trigger all timers that would be expired before the middle of the loop wait
                    // time
                    let timer_threshold = now + wait / 2;
                    let mut timers = timers.lock().unwrap();
                    while timers
                        .peek()
                        .and_then(|entry| {
                            if entry.time < timer_threshold {
                                Some(())
                            } else {
                                None
                            }
                        })
                        .is_some()
                    {
                        let TimerEntry {
                            time,
                            interval,
                            sender,
                            ..
                        } = timers.pop().unwrap();

                        if sender.is_closed() {
                            continue;
                        }

                        let _ = sender.unbounded_send(());
                        if let Some(interval) = interval {
                            timers.push(TimerEntry {
                                time: time + interval,
                                id: TIMER_ENTRY_ID.fetch_add(1, atomic::Ordering::Relaxed),
                                interval: Some(interval),
                                sender,
                            });
                        }
                    }
                }

                gst_trace!(CONTEXT_CAT, "Turning current thread '{}'", self.name);
                while current_thread
                    .enter(enter)
                    .turn(Some(time::Duration::from_millis(0)))
                    .unwrap()
                    .has_polled()
                {}
                gst_trace!(CONTEXT_CAT, "Turned current thread '{}'", self.name);

                let elapsed = now.elapsed();
                gst_trace!(CONTEXT_CAT, "Elapsed {:?} after handling futures", elapsed);

                if elapsed < wait {
                    gst_trace!(
                        CONTEXT_CAT,
                        "Waiting for {:?} before polling again",
                        wait - elapsed
                    );
                    thread::sleep(wait - elapsed);
                    gst_trace!(CONTEXT_CAT, "Slept for {:?}", now.elapsed());
                }

                if wait > time::Duration::from_millis(0) {
                    now += wait;
                } else {
                    now = time::Instant::now();
                }
            })
        });
    }
}

impl Drop for IOContextRunner {
    fn drop(&mut self) {
        gst_debug!(CONTEXT_CAT, "Shut down reactor thread '{}'", self.name);
    }
}

struct IOContextShutdown {
    name: String,
    shutdown: Arc<atomic::AtomicUsize>,
    handle: reactor::Handle,
    join: Option<thread::JoinHandle<()>>,
}

impl Drop for IOContextShutdown {
    fn drop(&mut self) {
        use tokio_executor::park::Unpark;

        gst_debug!(CONTEXT_CAT, "Shutting down reactor thread '{}'", self.name);
        self.shutdown.store(SHUTDOWN_NOW, atomic::Ordering::SeqCst);
        gst_trace!(CONTEXT_CAT, "Waiting for reactor '{}' shutdown", self.name);
        // After being unparked, the next turn() is guaranteed to finish immediately,
        // as such there is no race condition between checking for shutdown and setting
        // shutdown.
        self.handle.unpark();
        let _ = self.join.take().unwrap().join();
    }
}

#[derive(Clone)]
pub struct IOContext(Arc<IOContextInner>);

impl glib::subclass::boxed::BoxedType for IOContext {
    const NAME: &'static str = "TsIOContext";

    glib_boxed_type!();
}

glib_boxed_derive_traits!(IOContext);

type PendingFutures = Mutex<(
    u64,
    HashMap<u64, FuturesUnordered<Box<dyn Future<Item = (), Error = ()> + Send + 'static>>>,
)>;

struct IOContextInner {
    name: String,
    runtime_handle: Mutex<tokio_current_thread::Handle>,
    reactor_handle: reactor::Handle,
    timers: Arc<Mutex<BinaryHeap<TimerEntry>>>,
    // Only used for dropping
    _shutdown: IOContextShutdown,
    pending_futures: PendingFutures,
}

impl Drop for IOContextInner {
    fn drop(&mut self) {
        let mut contexts = CONTEXTS.lock().unwrap();
        gst_debug!(CONTEXT_CAT, "Finalizing context '{}'", self.name);
        contexts.remove(&self.name);
    }
}

impl IOContext {
    pub fn new(name: &str, wait: u32) -> Result<Self, io::Error> {
        let mut contexts = CONTEXTS.lock().unwrap();
        if let Some(context) = contexts.get(name) {
            if let Some(context) = context.upgrade() {
                gst_debug!(CONTEXT_CAT, "Reusing existing context '{}'", name);
                return Ok(IOContext(context));
            }
        }

        let reactor = reactor::Reactor::new()?;
        let reactor_handle = reactor.handle().clone();

        let timers = Arc::new(Mutex::new(BinaryHeap::new()));

        let (runtime_handle, shutdown) =
            IOContextRunner::start(name, wait, reactor, timers.clone());

        let context = Arc::new(IOContextInner {
            name: name.into(),
            runtime_handle: Mutex::new(runtime_handle),
            reactor_handle,
            timers,
            _shutdown: shutdown,
            pending_futures: Mutex::new((0, HashMap::new())),
        });
        contexts.insert(name.into(), Arc::downgrade(&context));

        gst_debug!(CONTEXT_CAT, "Created new context '{}'", name);
        Ok(IOContext(context))
    }

    pub fn spawn<F>(&self, future: F)
    where
        F: Future<Item = (), Error = ()> + Send + 'static,
    {
        self.0.runtime_handle.lock().unwrap().spawn(future).unwrap();
    }

    pub fn reactor_handle(&self) -> &reactor::Handle {
        &self.0.reactor_handle
    }

    pub fn acquire_pending_future_id(&self) -> PendingFutureId {
        let mut pending_futures = self.0.pending_futures.lock().unwrap();
        let id = pending_futures.0;
        pending_futures.0 += 1;
        pending_futures.1.insert(id, FuturesUnordered::new());

        PendingFutureId(id)
    }

    pub fn release_pending_future_id(&self, id: PendingFutureId) {
        let mut pending_futures = self.0.pending_futures.lock().unwrap();
        if let Some(fs) = pending_futures.1.remove(&id.0) {
            self.spawn(fs.for_each(|_| Ok(())));
        }
    }

    pub fn add_pending_future<F>(&self, id: PendingFutureId, future: F)
    where
        F: Future<Item = (), Error = ()> + Send + 'static,
    {
        let mut pending_futures = self.0.pending_futures.lock().unwrap();
        let fs = pending_futures.1.get_mut(&id.0).unwrap();
        fs.push(Box::new(future))
    }

    pub fn drain_pending_futures<E: Send + 'static>(
        &self,
        id: PendingFutureId,
    ) -> (Option<oneshot::Sender<()>>, PendingFuturesFuture<E>) {
        let mut pending_futures = self.0.pending_futures.lock().unwrap();
        let fs = pending_futures.1.get_mut(&id.0).unwrap();

        let pending_futures = mem::replace(fs, FuturesUnordered::new());

        if !pending_futures.is_empty() {
            gst_log!(
                CONTEXT_CAT,
                "Scheduling {} pending futures for context '{}' with pending future id {:?}",
                pending_futures.len(),
                self.0.name,
                id,
            );

            let (sender, receiver) = oneshot::channel();

            let future = pending_futures
                .for_each(|_| Ok(()))
                .select(receiver.then(|_| Ok(())))
                .then(|_| Ok(()));

            (Some(sender), future::Either::A(Box::new(future)))
        } else {
            (None, future::Either::B(future::ok(())))
        }
    }
}

pub type PendingFuturesFuture<E> = future::Either<
    Box<dyn Future<Item = (), Error = E> + Send + 'static>,
    future::FutureResult<(), E>,
>;

#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub struct PendingFutureId(u64);

impl glib::subclass::boxed::BoxedType for PendingFutureId {
    const NAME: &'static str = "TsPendingFutureId";

    glib_boxed_type!();
}

glib_boxed_derive_traits!(PendingFutureId);

static TIMER_ENTRY_ID: atomic::AtomicUsize = atomic::AtomicUsize::new(0);

// Ad-hoc interval timer implementation for our throttled event loop above
pub struct TimerEntry {
    time: time::Instant,
    id: usize, // for producing a total order
    interval: Option<time::Duration>,
    sender: futures_mpsc::UnboundedSender<()>,
}

impl PartialEq for TimerEntry {
    fn eq(&self, other: &Self) -> bool {
        self.time.eq(&other.time) && self.id.eq(&other.id)
    }
}

impl Eq for TimerEntry {}

impl PartialOrd for TimerEntry {
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        Some(self.cmp(&other))
    }
}

impl Ord for TimerEntry {
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        other
            .time
            .cmp(&self.time)
            .then_with(|| other.id.cmp(&self.id))
    }
}

#[allow(unused)]
pub struct Interval {
    receiver: futures_mpsc::UnboundedReceiver<()>,
}

impl Interval {
    #[allow(unused)]
    pub fn new(context: &IOContext, interval: time::Duration) -> Self {
        let (sender, receiver) = futures_mpsc::unbounded();

        let mut timers = context.0.timers.lock().unwrap();
        let entry = TimerEntry {
            time: time::Instant::now(),
            id: TIMER_ENTRY_ID.fetch_add(1, atomic::Ordering::Relaxed),
            interval: Some(interval),
            sender,
        };
        timers.push(entry);

        Self { receiver }
    }
}

impl Stream for Interval {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> futures::Poll<Option<Self::Item>, Self::Error> {
        self.receiver.poll()
    }
}

pub struct Timeout {
    receiver: futures_mpsc::UnboundedReceiver<()>,
}

impl Timeout {
    pub fn new(context: &IOContext, timeout: time::Duration) -> Self {
        let (sender, receiver) = futures_mpsc::unbounded();

        let mut timers = context.0.timers.lock().unwrap();
        let entry = TimerEntry {
            time: time::Instant::now() + timeout,
            id: TIMER_ENTRY_ID.fetch_add(1, atomic::Ordering::Relaxed),
            interval: None,
            sender,
        };
        timers.push(entry);

        Self { receiver }
    }
}

impl Future for Timeout {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> futures::Poll<Self::Item, Self::Error> {
        let res = self.receiver.poll()?;

        match res {
            Async::NotReady => Ok(Async::NotReady),
            Async::Ready(None) => unreachable!(),
            Async::Ready(Some(_)) => Ok(Async::Ready(())),
        }
    }
}
<commit_msg>threadshare: Handle context-wait==0 by waiting on IO<commit_after>// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.

use std::cmp;
use std::collections::{BinaryHeap, HashMap};
use std::io;
use std::mem;
use std::sync::{atomic, mpsc};
use std::sync::{Arc, Mutex, Weak};
use std::thread;
use std::time;

use futures::future;
use futures::stream::futures_unordered::FuturesUnordered;
use futures::sync::mpsc as futures_mpsc;
use futures::sync::oneshot;
use futures::{Async, Future, Stream};
use tokio::reactor;
use tokio_current_thread;
use tokio_timer::timer;

use glib;
use gst;

lazy_static! {
    static ref CONTEXTS: Mutex<HashMap<String, Weak<IOContextInner>>> = Mutex::new(HashMap::new());
    static ref CONTEXT_CAT: gst::DebugCategory = gst::DebugCategory::new(
        "ts-context",
        gst::DebugColorFlags::empty(),
        Some("Thread-sharing Context"),
    );
}

// Our own simplified implementation of reactor::Background to allow hooking into its internals
const RUNNING: usize = 0;
const SHUTDOWN_NOW: usize = 1;

struct IOContextRunner {
    name: String,
    shutdown: Arc<atomic::AtomicUsize>,
}

impl IOContextRunner {
    fn start(
        name: &str,
        wait: u32,
        reactor: reactor::Reactor,
        timers: Arc<Mutex<BinaryHeap<TimerEntry>>>,
    ) -> (tokio_current_thread::Handle, IOContextShutdown) {
        let handle = reactor.handle().clone();
        let shutdown = Arc::new(atomic::AtomicUsize::new(RUNNING));
        let shutdown_clone = shutdown.clone();
        let name_clone = name.into();

        let mut runner = IOContextRunner {
            shutdown: shutdown_clone,
            name: name_clone,
        };

        let (sender, receiver) = mpsc::channel();

        let join = thread::spawn(move || {
            runner.run(wait, reactor, sender, timers);
        });

        let shutdown = IOContextShutdown {
            name: name.into(),
            shutdown,
            handle,
            join: Some(join),
        };

        let runtime_handle = receiver.recv().unwrap();

        (runtime_handle, shutdown)
    }

    fn run(
        &mut self,
        wait: u32,
        reactor: reactor::Reactor,
        sender: mpsc::Sender<tokio_current_thread::Handle>,
        timers: Arc<Mutex<BinaryHeap<TimerEntry>>>,
    ) {
        let wait = time::Duration::from_millis(wait as u64);

        gst_debug!(CONTEXT_CAT, "Started reactor thread '{}'", self.name);

        let handle = reactor.handle();
        let mut enter = ::tokio_executor::enter().unwrap();
        let timer = timer::Timer::new(reactor);
        let timer_handle = timer.handle();
        let mut current_thread = tokio_current_thread::CurrentThread::new_with_park(timer);

        let _ = sender.send(current_thread.handle());

        let mut now = time::Instant::now();

        ::tokio_timer::with_default(&timer_handle, &mut enter, |mut enter| {
            ::tokio_reactor::with_default(&handle, &mut enter, |enter| loop {
                if self.shutdown.load(atomic::Ordering::SeqCst) > RUNNING {
                    break;
                }

                gst_trace!(CONTEXT_CAT, "Elapsed {:?} since last loop", now.elapsed());

                // Handle timers
                {
                    // Trigger all timers that would be expired before the middle of the loop wait
                    // time
                    let timer_threshold = now + wait / 2;
                    let mut timers = timers.lock().unwrap();
                    while timers
                        .peek()
                        .and_then(|entry| {
                            if entry.time < timer_threshold {
                                Some(())
                            } else {
                                None
                            }
                        })
                        .is_some()
                    {
                        let TimerEntry {
                            time,
                            interval,
                            sender,
                            ..
                        } = timers.pop().unwrap();

                        if sender.is_closed() {
                            continue;
                        }

                        let _ = sender.unbounded_send(());
                        if let Some(interval) = interval {
                            timers.push(TimerEntry {
                                time: time + interval,
                                id: TIMER_ENTRY_ID.fetch_add(1, atomic::Ordering::Relaxed),
                                interval: Some(interval),
                                sender,
                            });
                        }
                    }
                }

                gst_trace!(CONTEXT_CAT, "Turning current thread '{}'", self.name);
                while current_thread
                    .enter(enter)
                    .turn(Some(time::Duration::from_millis(0)))
                    .unwrap()
                    .has_polled()
                {}
                gst_trace!(CONTEXT_CAT, "Turned current thread '{}'", self.name);

                let elapsed = now.elapsed();
                gst_trace!(CONTEXT_CAT, "Elapsed {:?} after handling futures", elapsed);

                if wait == time::Duration::from_millis(0) {
                    let timers = timers.lock().unwrap();
                    let wait = match timers.peek().map(|entry| entry.time) {
                        None => None,
                        Some(time) => Some({
                            let tmp = time::Instant::now();

                            if time < tmp {
                                time::Duration::from_millis(0)
                            } else {
                                time.duration_since(tmp)
                            }
                        }),
                    };

                    gst_trace!(CONTEXT_CAT, "Sleeping for up to {:?}", wait);
                    current_thread.enter(enter).turn(wait).unwrap();
                    gst_trace!(CONTEXT_CAT, "Slept for {:?}", now.elapsed());
                    now = time::Instant::now();
                } else {
                    if elapsed < wait {
                        gst_trace!(
                            CONTEXT_CAT,
                            "Waiting for {:?} before polling again",
                            wait - elapsed
                        );
                        thread::sleep(wait - elapsed);
                        gst_trace!(CONTEXT_CAT, "Slept for {:?}", now.elapsed());
                    }

                    now += wait;
                }
            })
        });
    }
}

impl Drop for IOContextRunner {
    fn drop(&mut self) {
        gst_debug!(CONTEXT_CAT, "Shut down reactor thread '{}'", self.name);
    }
}

struct IOContextShutdown {
    name: String,
    shutdown: Arc<atomic::AtomicUsize>,
    handle: reactor::Handle,
    join: Option<thread::JoinHandle<()>>,
}

impl Drop for IOContextShutdown {
    fn drop(&mut self) {
        use tokio_executor::park::Unpark;

        gst_debug!(CONTEXT_CAT, "Shutting down reactor thread '{}'", self.name);
        self.shutdown.store(SHUTDOWN_NOW, atomic::Ordering::SeqCst);
        gst_trace!(CONTEXT_CAT, "Waiting for reactor '{}' shutdown", self.name);
        // After being unparked, the next turn() is guaranteed to finish immediately,
        // as such there is no race condition between checking for shutdown and setting
        // shutdown.
        self.handle.unpark();
        let _ = self.join.take().unwrap().join();
    }
}

#[derive(Clone)]
pub struct IOContext(Arc<IOContextInner>);

impl glib::subclass::boxed::BoxedType for IOContext {
    const NAME: &'static str = "TsIOContext";

    glib_boxed_type!();
}

glib_boxed_derive_traits!(IOContext);

type PendingFutures = Mutex<(
    u64,
    HashMap<u64, FuturesUnordered<Box<dyn Future<Item = (), Error = ()> + Send + 'static>>>,
)>;

struct IOContextInner {
    name: String,
    runtime_handle: Mutex<tokio_current_thread::Handle>,
    reactor_handle: reactor::Handle,
    timers: Arc<Mutex<BinaryHeap<TimerEntry>>>,
    // Only used for dropping
    _shutdown: IOContextShutdown,
    pending_futures: PendingFutures,
}

impl Drop for IOContextInner {
    fn drop(&mut self) {
        let mut contexts = CONTEXTS.lock().unwrap();
        gst_debug!(CONTEXT_CAT, "Finalizing context '{}'", self.name);
        contexts.remove(&self.name);
    }
}

impl IOContext {
    pub fn new(name: &str, wait: u32) -> Result<Self, io::Error> {
        let mut contexts = CONTEXTS.lock().unwrap();
        if let Some(context) = contexts.get(name) {
            if let Some(context) = context.upgrade() {
                gst_debug!(CONTEXT_CAT, "Reusing existing context '{}'", name);
                return Ok(IOContext(context));
            }
        }

        let reactor = reactor::Reactor::new()?;
        let reactor_handle = reactor.handle().clone();

        let timers = Arc::new(Mutex::new(BinaryHeap::new()));

        let (runtime_handle, shutdown) =
            IOContextRunner::start(name, wait, reactor, timers.clone());

        let context = Arc::new(IOContextInner {
            name: name.into(),
            runtime_handle: Mutex::new(runtime_handle),
            reactor_handle,
            timers,
            _shutdown: shutdown,
            pending_futures: Mutex::new((0, HashMap::new())),
        });
        contexts.insert(name.into(), Arc::downgrade(&context));

        gst_debug!(CONTEXT_CAT, "Created new context '{}'", name);
        Ok(IOContext(context))
    }

    pub fn spawn<F>(&self, future: F)
    where
        F: Future<Item = (), Error = ()> + Send + 'static,
    {
        self.0.runtime_handle.lock().unwrap().spawn(future).unwrap();
    }

    pub fn reactor_handle(&self) -> &reactor::Handle {
        &self.0.reactor_handle
    }

    pub fn acquire_pending_future_id(&self) -> PendingFutureId {
        let mut pending_futures = self.0.pending_futures.lock().unwrap();
        let id = pending_futures.0;
        pending_futures.0 += 1;
        pending_futures.1.insert(id, FuturesUnordered::new());

        PendingFutureId(id)
    }

    pub fn release_pending_future_id(&self, id: PendingFutureId) {
        let mut pending_futures = self.0.pending_futures.lock().unwrap();
        if let Some(fs) = pending_futures.1.remove(&id.0) {
            self.spawn(fs.for_each(|_| Ok(())));
        }
    }

    pub fn add_pending_future<F>(&self, id: PendingFutureId, future: F)
    where
        F: Future<Item = (), Error = ()> + Send + 'static,
    {
        let mut pending_futures = self.0.pending_futures.lock().unwrap();
        let fs = pending_futures.1.get_mut(&id.0).unwrap();
        fs.push(Box::new(future))
    }

    pub fn drain_pending_futures<E: Send + 'static>(
        &self,
        id: PendingFutureId,
    ) -> (Option<oneshot::Sender<()>>, PendingFuturesFuture<E>) {
        let mut pending_futures = self.0.pending_futures.lock().unwrap();
        let fs = pending_futures.1.get_mut(&id.0).unwrap();

        let pending_futures = mem::replace(fs, FuturesUnordered::new());

        if !pending_futures.is_empty() {
            gst_log!(
                CONTEXT_CAT,
                "Scheduling {} pending futures for context '{}' with pending future id {:?}",
                pending_futures.len(),
                self.0.name,
                id,
            );

            let (sender, receiver) = oneshot::channel();

            let future = pending_futures
                .for_each(|_| Ok(()))
                .select(receiver.then(|_| Ok(())))
                .then(|_| Ok(()));

            (Some(sender), future::Either::A(Box::new(future)))
        } else {
            (None, future::Either::B(future::ok(())))
        }
    }
}

pub type PendingFuturesFuture<E> = future::Either<
    Box<dyn Future<Item = (), Error = E> + Send + 'static>,
    future::FutureResult<(), E>,
>;

#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub struct PendingFutureId(u64);

impl glib::subclass::boxed::BoxedType for PendingFutureId {
    const NAME: &'static str = "TsPendingFutureId";

    glib_boxed_type!();
}

glib_boxed_derive_traits!(PendingFutureId);

static TIMER_ENTRY_ID: atomic::AtomicUsize = atomic::AtomicUsize::new(0);

// Ad-hoc interval timer implementation for our throttled event loop above
pub struct TimerEntry {
    time: time::Instant,
    id: usize, // for producing a total order
    interval: Option<time::Duration>,
    sender: futures_mpsc::UnboundedSender<()>,
}

impl PartialEq for TimerEntry {
    fn eq(&self, other: &Self) -> bool {
        self.time.eq(&other.time) && self.id.eq(&other.id)
    }
}

impl Eq for TimerEntry {}

impl PartialOrd for TimerEntry {
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        Some(self.cmp(&other))
    }
}

impl Ord for TimerEntry {
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        other
            .time
            .cmp(&self.time)
            .then_with(|| other.id.cmp(&self.id))
    }
}

#[allow(unused)]
pub struct Interval {
    receiver: futures_mpsc::UnboundedReceiver<()>,
}

impl Interval {
    #[allow(unused)]
    pub fn new(context: &IOContext, interval: time::Duration) -> Self {
        use tokio_executor::park::Unpark;

        let (sender, receiver) = futures_mpsc::unbounded();

        let mut timers = context.0.timers.lock().unwrap();
        let entry = TimerEntry {
            time: time::Instant::now(),
            id: TIMER_ENTRY_ID.fetch_add(1, atomic::Ordering::Relaxed),
            interval: Some(interval),
            sender,
        };
        timers.push(entry);
        context.reactor_handle().unpark();

        Self { receiver }
    }
}

impl Stream for Interval {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> futures::Poll<Option<Self::Item>, Self::Error> {
        self.receiver.poll()
    }
}

pub struct Timeout {
    receiver: futures_mpsc::UnboundedReceiver<()>,
}

impl Timeout {
    pub fn new(context: &IOContext, timeout: time::Duration) -> Self {
        let (sender, receiver) = futures_mpsc::unbounded();

        let mut timers = context.0.timers.lock().unwrap();
        let entry = TimerEntry {
            time: time::Instant::now() + timeout,
            id: TIMER_ENTRY_ID.fetch_add(1, atomic::Ordering::Relaxed),
            interval: None,
            sender,
        };
        timers.push(entry);

        Self { receiver }
    }
}

impl Future for Timeout {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> futures::Poll<Self::Item, Self::Error> {
        let res = self.receiver.poll()?;

        match res {
            Async::NotReady => Ok(Async::NotReady),
            Async::Ready(None) => unreachable!(),
            Async::Ready(Some(_)) => Ok(Async::Ready(())),
        }
    }
}
<|endoftext|>


<commit_before>extern crate cell_gc;
extern crate lisp;

use std::fs;
use std::io::Read;
use std::path::Path;

fn eval_test_file(file: &Path) {
    println!("Opening test file: {}", file.display());
    let mut file = fs::File::open(file).expect("Should open file OK");

    let mut source = String::new();
    file.read_to_string(&mut source)
        .expect("Should read file OK");

    println!("source =");
    println!("{}", source);

    cell_gc::with_heap(|hs| {
        let exprs = lisp::parse::parse(hs, &source).expect("Should parse s-exps OK");
        let env = lisp::vm::Environment::default_env(hs);
        for expr in exprs {
            lisp::vm::eval(hs, expr, env.clone()).expect("Should eval exprs OK");
        }
    });
}

macro_rules! test {
    ( $file:ident ) => {
        #[test]
        fn $file() {
            let file = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/", stringify!($file), ".lisp");
            let file = Path::new(file);
            eval_test_file(file);
        }
    }
}

test!(begin);
test!(booleans);
test!(closure);
test!(cons);
test!(double);
test!(equivalence);
test!(y_combinator);
test!(y_combinator_2);
test!(define);
test!(numerical);
test!(pairs_and_lists);
test!(set);
test!(tail_calls);
test!(vectors);
<commit_msg>lisp: In the test harness, GC after each toplevel form.<commit_after>extern crate cell_gc;
extern crate lisp;

use std::fs;
use std::io::Read;
use std::path::Path;

fn eval_test_file(file: &Path) {
    println!("Opening test file: {}", file.display());
    let mut file = fs::File::open(file).expect("Should open file OK");

    let mut source = String::new();
    file.read_to_string(&mut source)
        .expect("Should read file OK");

    println!("source =");
    println!("{}", source);

    cell_gc::with_heap(|hs| {
        let exprs = lisp::parse::parse(hs, &source).expect("Should parse s-exps OK");
        let env = lisp::vm::Environment::default_env(hs);
        for expr in exprs {
            lisp::vm::eval(hs, expr, env.clone()).expect("Should eval exprs OK");
            hs.force_gc();
        }
    });
}

macro_rules! test {
    ( $file:ident ) => {
        #[test]
        fn $file() {
            let file = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/", stringify!($file), ".lisp");
            let file = Path::new(file);
            eval_test_file(file);
        }
    }
}

test!(begin);
test!(booleans);
test!(closure);
test!(cons);
test!(double);
test!(equivalence);
test!(y_combinator);
test!(y_combinator_2);
test!(define);
test!(numerical);
test!(pairs_and_lists);
test!(set);
test!(tail_calls);
test!(vectors);
<|endoftext|>


<commit_before>// Take a look at the license at the top of the repository in the LICENSE file.

use crate::{DiskExt, DiskType};

use std::ffi::{OsStr, OsString};
use std::path::{Path, PathBuf};

use super::utils::c_buf_to_str;

/// Struct containing a disk information.
pub struct Disk {
    name: OsString,
    c_mount_point: Vec<libc::c_char>,
    mount_point: PathBuf,
    total_space: u64,
    available_space: u64,
    file_system: Vec<u8>,
    is_removable: bool,
}

impl DiskExt for Disk {
    fn type_(&self) -> DiskType {
        DiskType::Unknown(-1)
    }

    fn name(&self) -> &OsStr {
        &self.name
    }

    fn file_system(&self) -> &[u8] {
        &self.file_system
    }

    fn mount_point(&self) -> &Path {
        &self.mount_point
    }

    fn total_space(&self) -> u64 {
        self.total_space
    }

    fn available_space(&self) -> u64 {
        self.available_space
    }

    fn is_removable(&self) -> bool {
        self.is_removable
    }

    fn refresh(&mut self) -> bool {
        unsafe {
            let mut vfs: libc::statvfs = std::mem::zeroed();
            refresh_disk(self, &mut vfs)
        }
    }
}

// FIXME: if you want to get disk I/O usage:
// statfs.[f_syncwrites, f_asyncwrites, f_syncreads, f_asyncreads]

unsafe fn refresh_disk(disk: &mut Disk, vfs: &mut libc::statvfs) -> bool {
    if libc::statvfs(disk.c_mount_point.as_ptr() as *const _, vfs) < 0 {
        return false;
    }
    disk.total_space = vfs.f_blocks * vfs.f_frsize;
    disk.available_space = vfs.f_favail * vfs.f_frsize;
    true
}

pub unsafe fn get_all_disks() -> Vec<Disk> {
    let mut fs_infos: *mut libc::statfs = std::ptr::null_mut();

    let count = libc::getmntinfo(&mut fs_infos, libc::MNT_WAIT);

    if count < 1 {
        return Vec::new();
    }
    let mut vfs: libc::statvfs = std::mem::zeroed();
    let fs_infos: &[libc::statfs] = std::slice::from_raw_parts(fs_infos as _, count as _);
    let mut disks = Vec::new();

    for fs_info in fs_infos {
        if fs_info.f_mntfromname[0] == 0 || fs_info.f_mntonname[0] == 0 {
            // If we have missing information, no need to look any further...
            continue;
        }
        let fs_type: &[libc::c_char] =
            if let Some(pos) = fs_info.f_fstypename.iter().position(|x| *x == 0) {
                &fs_info.f_fstypename[..pos]
            } else {
                &fs_info.f_fstypename
            };
        let fs_type: &[u8] = std::slice::from_raw_parts(fs_type.as_ptr() as _, fs_type.len());
        match fs_type {
            b"autofs" | b"devfs" | b"linprocfs" | b"procfs" | b"fdesckfs" | b"tmpfs"
            | b"linsysfs" => {
                sysinfo_debug!(
                    "Memory filesystem `{:?}`, ignoring it.",
                    c_buf_to_str(&fs_info.f_fstypename).unwrap(),
                );
                continue;
            }
            _ => {}
        }

        if libc::statvfs(fs_info.f_mntonname.as_ptr(), &mut vfs) != 0 {
            continue;
        }

        let mount_point = match c_buf_to_str(&fs_info.f_mntonname) {
            Some(m) => m,
            None => {
                sysinfo_debug!("Cannot get disk mount point, ignoring it.");
                continue;
            }
        };

        let name = if mount_point == "/" {
            OsString::from("root")
        } else {
            OsString::from(mount_point)
        };

        // USB keys and CDs are removable.
        let is_removable =
            [b"USB", b"usb"].iter().any(|b| b == &fs_type) || fs_type.starts_with(b"/dev/cd");

        disks.push(Disk {
            name,
            c_mount_point: fs_info.f_mntonname.to_vec(),
            mount_point: PathBuf::from(mount_point),
            total_space: vfs.f_blocks * vfs.f_frsize,
            available_space: vfs.f_favail * vfs.f_frsize,
            file_system: fs_type.to_vec(),
            is_removable,
        });
    }
    disks
}
<commit_msg>Fix type error for 32-bit freebsd (on i386, armv6, armv7, powerpc)<commit_after>// Take a look at the license at the top of the repository in the LICENSE file.

use crate::{DiskExt, DiskType};

use std::ffi::{OsStr, OsString};
use std::path::{Path, PathBuf};

use super::utils::c_buf_to_str;

/// Struct containing a disk information.
pub struct Disk {
    name: OsString,
    c_mount_point: Vec<libc::c_char>,
    mount_point: PathBuf,
    total_space: u64,
    available_space: u64,
    file_system: Vec<u8>,
    is_removable: bool,
}

impl DiskExt for Disk {
    fn type_(&self) -> DiskType {
        DiskType::Unknown(-1)
    }

    fn name(&self) -> &OsStr {
        &self.name
    }

    fn file_system(&self) -> &[u8] {
        &self.file_system
    }

    fn mount_point(&self) -> &Path {
        &self.mount_point
    }

    fn total_space(&self) -> u64 {
        self.total_space
    }

    fn available_space(&self) -> u64 {
        self.available_space
    }

    fn is_removable(&self) -> bool {
        self.is_removable
    }

    fn refresh(&mut self) -> bool {
        unsafe {
            let mut vfs: libc::statvfs = std::mem::zeroed();
            refresh_disk(self, &mut vfs)
        }
    }
}

// FIXME: if you want to get disk I/O usage:
// statfs.[f_syncwrites, f_asyncwrites, f_syncreads, f_asyncreads]

unsafe fn refresh_disk(disk: &mut Disk, vfs: &mut libc::statvfs) -> bool {
    if libc::statvfs(disk.c_mount_point.as_ptr() as *const _, vfs) < 0 {
        return false;
    }
    let f_frsize: u64 = vfs.f_frsize as _;

    disk.total_space = vfs.f_blocks * f_frsize;
    disk.available_space = vfs.f_favail * f_frsize;
    true
}

pub unsafe fn get_all_disks() -> Vec<Disk> {
    let mut fs_infos: *mut libc::statfs = std::ptr::null_mut();

    let count = libc::getmntinfo(&mut fs_infos, libc::MNT_WAIT);

    if count < 1 {
        return Vec::new();
    }
    let mut vfs: libc::statvfs = std::mem::zeroed();
    let fs_infos: &[libc::statfs] = std::slice::from_raw_parts(fs_infos as _, count as _);
    let mut disks = Vec::new();

    for fs_info in fs_infos {
        if fs_info.f_mntfromname[0] == 0 || fs_info.f_mntonname[0] == 0 {
            // If we have missing information, no need to look any further...
            continue;
        }
        let fs_type: &[libc::c_char] =
            if let Some(pos) = fs_info.f_fstypename.iter().position(|x| *x == 0) {
                &fs_info.f_fstypename[..pos]
            } else {
                &fs_info.f_fstypename
            };
        let fs_type: &[u8] = std::slice::from_raw_parts(fs_type.as_ptr() as _, fs_type.len());
        match fs_type {
            b"autofs" | b"devfs" | b"linprocfs" | b"procfs" | b"fdesckfs" | b"tmpfs"
            | b"linsysfs" => {
                sysinfo_debug!(
                    "Memory filesystem `{:?}`, ignoring it.",
                    c_buf_to_str(&fs_info.f_fstypename).unwrap(),
                );
                continue;
            }
            _ => {}
        }

        if libc::statvfs(fs_info.f_mntonname.as_ptr(), &mut vfs) != 0 {
            continue;
        }

        let mount_point = match c_buf_to_str(&fs_info.f_mntonname) {
            Some(m) => m,
            None => {
                sysinfo_debug!("Cannot get disk mount point, ignoring it.");
                continue;
            }
        };

        let name = if mount_point == "/" {
            OsString::from("root")
        } else {
            OsString::from(mount_point)
        };

        // USB keys and CDs are removable.
        let is_removable =
            [b"USB", b"usb"].iter().any(|b| b == &fs_type) || fs_type.starts_with(b"/dev/cd");

        let f_frsize: u64 = vfs.f_frsize as _;

        disks.push(Disk {
            name,
            c_mount_point: fs_info.f_mntonname.to_vec(),
            mount_point: PathBuf::from(mount_point),
            total_space: vfs.f_blocks * f_frsize,
            available_space: vfs.f_favail * f_frsize,
            file_system: fs_type.to_vec(),
            is_removable,
        });
    }
    disks
}
<|endoftext|>


<commit_before>#![stable(feature = "core_hint", since = "1.27.0")]

//! Hints to compiler that affects how code should be emitted or optimized.

use intrinsics;

/// Informs the compiler that this point in the code is not reachable, enabling
/// further optimizations.
///
/// # Safety
///
/// Reaching this function is completely *undefined behavior* (UB). In
/// particular, the compiler assumes that all UB must never happen, and
/// therefore will eliminate all branches that reach to a call to
/// `unreachable_unchecked()`.
///
/// Like all instances of UB, if this assumption turns out to be wrong, i.e., the
/// `unreachable_unchecked()` call is actually reachable among all possible
/// control flow, the compiler will apply the wrong optimization strategy, and
/// may sometimes even corrupt seemingly unrelated code, causing
/// difficult-to-debug problems.
///
/// Use this function only when you can prove that the code will never call it.
///
/// The [`unreachable!()`] macro is the safe counterpart of this function, which
/// will panic instead when executed.
///
/// [`unreachable!()`]: ../macro.unreachable.html
///
/// # Example
///
/// ```
/// fn div_1(a: u32, b: u32) -> u32 {
///     use std::hint::unreachable_unchecked;
///
///     // `b.saturating_add(1)` is always positive (not zero),
///     // hence `checked_div` will never return `None`.
///     // Therefore, the else branch is unreachable.
///     a.checked_div(b.saturating_add(1))
///         .unwrap_or_else(|| unsafe { unreachable_unchecked() })
/// }
///
/// assert_eq!(div_1(7, 0), 7);
/// assert_eq!(div_1(9, 1), 4);
/// assert_eq!(div_1(11, std::u32::MAX), 0);
/// ```
#[inline]
#[stable(feature = "unreachable", since = "1.27.0")]
pub unsafe fn unreachable_unchecked() -> ! {
    intrinsics::unreachable()
}

/// Save power or switch hyperthreads in a busy-wait spin-loop.
///
/// This function is deliberately more primitive than
/// [`std::thread::yield_now`](../../std/thread/fn.yield_now.html) and
/// does not directly yield to the system's scheduler.
/// In some cases it might be useful to use a combination of both functions.
/// Careful benchmarking is advised.
///
/// On some platforms this function may not do anything at all.
#[inline]
#[unstable(feature = "renamed_spin_loop", issue = "55002")]
pub fn spin_loop() {
    #[cfg(
        all(
            any(target_arch = "x86", target_arch = "x86_64"),
            target_feature = "sse2"
        )
    )] {
        #[cfg(target_arch = "x86")] {
            unsafe { crate::arch::x86::_mm_pause() };
        }

        #[cfg(target_arch = "x86_64")] {
            unsafe { crate::arch::x86_64::_mm_pause() };
        }
    }

    #[cfg(
        any(
            target_arch = "aarch64",
            all(target_arch = "arm", target_feature = "v6")
        )
    )] {
        #[cfg(target_arch = "aarch64")] {
            unsafe { crate::arch::aarch64::__yield() };
        }
        #[cfg(target_arch = "arm")] {
            unsafe { crate::arch::arm::__yield() };
        }
    }
}

/// A function that is opaque to the optimizer, to allow benchmarks to
/// pretend to use outputs to assist in avoiding dead-code
/// elimination.
///
/// This function is a no-op, and does not even read from `dummy`.
#[unstable(feature = "test", issue = "27812")]
pub fn black_box<T>(dummy: T) -> T {
    #[cfg(not(any(target_arch = "asmjs", target_arch = "wasm32")))] {
        // we need to "use" the argument in some way LLVM can't
        // introspect.
        unsafe { asm!("" : : "r"(&dummy)) }
        dummy
    }
    #[cfg(any(target_arch = "asmjs", target_arch = "wasm32"))] {
        unsafe {
            let ret = crate::ptr::read_volatile(&dummy);
            crate::mem::forget(dummy);
            ret
        }
   }
}
<commit_msg>black_box should use inline assembly on wasm32<commit_after>#![stable(feature = "core_hint", since = "1.27.0")]

//! Hints to compiler that affects how code should be emitted or optimized.

use intrinsics;

/// Informs the compiler that this point in the code is not reachable, enabling
/// further optimizations.
///
/// # Safety
///
/// Reaching this function is completely *undefined behavior* (UB). In
/// particular, the compiler assumes that all UB must never happen, and
/// therefore will eliminate all branches that reach to a call to
/// `unreachable_unchecked()`.
///
/// Like all instances of UB, if this assumption turns out to be wrong, i.e., the
/// `unreachable_unchecked()` call is actually reachable among all possible
/// control flow, the compiler will apply the wrong optimization strategy, and
/// may sometimes even corrupt seemingly unrelated code, causing
/// difficult-to-debug problems.
///
/// Use this function only when you can prove that the code will never call it.
///
/// The [`unreachable!()`] macro is the safe counterpart of this function, which
/// will panic instead when executed.
///
/// [`unreachable!()`]: ../macro.unreachable.html
///
/// # Example
///
/// ```
/// fn div_1(a: u32, b: u32) -> u32 {
///     use std::hint::unreachable_unchecked;
///
///     // `b.saturating_add(1)` is always positive (not zero),
///     // hence `checked_div` will never return `None`.
///     // Therefore, the else branch is unreachable.
///     a.checked_div(b.saturating_add(1))
///         .unwrap_or_else(|| unsafe { unreachable_unchecked() })
/// }
///
/// assert_eq!(div_1(7, 0), 7);
/// assert_eq!(div_1(9, 1), 4);
/// assert_eq!(div_1(11, std::u32::MAX), 0);
/// ```
#[inline]
#[stable(feature = "unreachable", since = "1.27.0")]
pub unsafe fn unreachable_unchecked() -> ! {
    intrinsics::unreachable()
}

/// Save power or switch hyperthreads in a busy-wait spin-loop.
///
/// This function is deliberately more primitive than
/// [`std::thread::yield_now`](../../std/thread/fn.yield_now.html) and
/// does not directly yield to the system's scheduler.
/// In some cases it might be useful to use a combination of both functions.
/// Careful benchmarking is advised.
///
/// On some platforms this function may not do anything at all.
#[inline]
#[unstable(feature = "renamed_spin_loop", issue = "55002")]
pub fn spin_loop() {
    #[cfg(
        all(
            any(target_arch = "x86", target_arch = "x86_64"),
            target_feature = "sse2"
        )
    )] {
        #[cfg(target_arch = "x86")] {
            unsafe { crate::arch::x86::_mm_pause() };
        }

        #[cfg(target_arch = "x86_64")] {
            unsafe { crate::arch::x86_64::_mm_pause() };
        }
    }

    #[cfg(
        any(
            target_arch = "aarch64",
            all(target_arch = "arm", target_feature = "v6")
        )
    )] {
        #[cfg(target_arch = "aarch64")] {
            unsafe { crate::arch::aarch64::__yield() };
        }
        #[cfg(target_arch = "arm")] {
            unsafe { crate::arch::arm::__yield() };
        }
    }
}

/// A function that is opaque to the optimizer, to allow benchmarks to
/// pretend to use outputs to assist in avoiding dead-code
/// elimination.
///
/// This function is a no-op, and does not even read from `dummy`.
#[unstable(feature = "test", issue = "27812")]
pub fn black_box<T>(dummy: T) -> T {
    #[cfg(not(target_arch = "asmjs"))] {
        // we need to "use" the argument in some way LLVM can't
        // introspect.
        unsafe { asm!("" : : "r"(&dummy)) }
        dummy
    }
    #[cfg(target_arch = "asmjs")] {
        unsafe {
            let ret = crate::ptr::read_volatile(&dummy);
            crate::mem::forget(dummy);
            ret
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::container::{Container, Mutable};
use core::cmp::Eq;
use core::prelude::*;
use core::uint;
use core::vec;

const initial_capacity: uint = 32u; // 2^5

pub struct Deque<T> {
    priv nelts: uint,
    priv lo: uint,
    priv hi: uint,
    priv elts: ~[Option<T>]
}

impl<T> Container for Deque<T> {
    pure fn len(&self) -> uint { self.nelts }
    pure fn is_empty(&self) -> bool { self.len() == 0 }
}

impl<T> Mutable for Deque<T> {
    fn clear(&mut self) {
        for vec::each_mut(self.elts) |x| { *x = None }
        self.nelts = 0;
        self.lo = 0;
        self.hi = 0;
    }
}

impl<T> Deque<T> {
    static pure fn new() -> Deque<T> {
        Deque{nelts: 0, lo: 0, hi: 0,
              elts: vec::from_fn(initial_capacity, |_| None)}
    }

    fn peek_front(&self) -> &self/T { get(self.elts, self.lo) }
    fn peek_back(&self) -> &self/T { get(self.elts, self.hi - 1u) }
}

impl<T: Copy> Deque<T> {
    fn add_front(&mut self, t: T) {
        let oldlo = self.lo;
        if self.lo == 0u {
            self.lo = self.elts.len() - 1u;
        } else { self.lo -= 1u; }
        if self.lo == self.hi {
            self.elts = grow(self.nelts, oldlo, self.elts);
            self.lo = self.elts.len() - 1u;
            self.hi = self.nelts;
        }
        self.elts[self.lo] = Some(t);
        self.nelts += 1u;
    }

    fn add_back(&mut self, t: T) {
        if self.lo == self.hi && self.nelts != 0u {
            self.elts = grow(self.nelts, self.lo, self.elts);
            self.lo = 0u;
            self.hi = self.nelts;
        }
        self.elts[self.hi] = Some(t);
        self.hi = (self.hi + 1u) % self.elts.len();
        self.nelts += 1u;
    }

    fn pop_front(&mut self) -> T {
        let t = { *get(self.elts, self.lo) };
        self.elts[self.lo] = None;
        self.lo = (self.lo + 1u) % self.elts.len();
        self.nelts -= 1u;
        t
    }

    fn pop_back(&mut self) -> T {
        if self.hi == 0u {
            self.hi = self.elts.len() - 1u;
        } else { self.hi -= 1u; }
        let t = { *get(self.elts, self.hi) };
        self.elts[self.hi] = None;
        self.nelts -= 1u;
        t
    }

    fn get(&self, i: int) -> T {
        let idx = (self.lo + (i as uint)) % self.elts.len();
        *get(self.elts, idx)
    }
}

/// Grow is only called on full elts, so nelts is also len(elts), unlike
/// elsewhere.
fn grow<T: Copy>(nelts: uint, lo: uint, elts: &[Option<T>]) -> ~[Option<T>] {
    assert nelts == elts.len();
    let mut rv = ~[];

    let mut i = 0u;
    let nalloc = uint::next_power_of_two(nelts + 1u);
    while i < nalloc {
        if i < nelts {
            rv.push(elts[(lo + i) % nelts]);
        } else { rv.push(None); }
        i += 1u;
    }

    rv
}

fn get<T>(elts: &r/[Option<T>], i: uint) -> &r/T {
    match elts[i] { Some(ref t) => t, _ => fail!() }
}

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

    #[test]
    fn test_simple() {
        let mut d = Deque::new();
        assert d.len() == 0u;
        d.add_front(17);
        d.add_front(42);
        d.add_back(137);
        assert d.len() == 3u;
        d.add_back(137);
        assert d.len() == 4u;
        log(debug, d.peek_front());
        assert *d.peek_front() == 42;
        log(debug, d.peek_back());
        assert *d.peek_back() == 137;
        let mut i: int = d.pop_front();
        log(debug, i);
        assert i == 42;
        i = d.pop_back();
        log(debug, i);
        assert i == 137;
        i = d.pop_back();
        log(debug, i);
        assert i == 137;
        i = d.pop_back();
        log(debug, i);
        assert i == 17;
        assert d.len() == 0u;
        d.add_back(3);
        assert d.len() == 1u;
        d.add_front(2);
        assert d.len() == 2u;
        d.add_back(4);
        assert d.len() == 3u;
        d.add_front(1);
        assert d.len() == 4u;
        log(debug, d.get(0));
        log(debug, d.get(1));
        log(debug, d.get(2));
        log(debug, d.get(3));
        assert d.get(0) == 1;
        assert d.get(1) == 2;
        assert d.get(2) == 3;
        assert d.get(3) == 4;
    }

    #[test]
    fn test_boxes() {
        let a: @int = @5;
        let b: @int = @72;
        let c: @int = @64;
        let d: @int = @175;

        let mut deq = Deque::new();
        assert deq.len() == 0;
        deq.add_front(a);
        deq.add_front(b);
        deq.add_back(c);
        assert deq.len() == 3;
        deq.add_back(d);
        assert deq.len() == 4;
        assert *deq.peek_front() == b;
        assert *deq.peek_back() == d;
        assert deq.pop_front() == b;
        assert deq.pop_back() == d;
        assert deq.pop_back() == c;
        assert deq.pop_back() == a;
        assert deq.len() == 0;
        deq.add_back(c);
        assert deq.len() == 1;
        deq.add_front(b);
        assert deq.len() == 2;
        deq.add_back(d);
        assert deq.len() == 3;
        deq.add_front(a);
        assert deq.len() == 4;
        assert deq.get(0) == a;
        assert deq.get(1) == b;
        assert deq.get(2) == c;
        assert deq.get(3) == d;
    }

    fn test_parameterized<T: Copy Eq Durable>(a: T, b: T, c: T, d: T) {
        let mut deq = Deque::new();
        assert deq.len() == 0;
        deq.add_front(a);
        deq.add_front(b);
        deq.add_back(c);
        assert deq.len() == 3;
        deq.add_back(d);
        assert deq.len() == 4;
        assert *deq.peek_front() == b;
        assert *deq.peek_back() == d;
        assert deq.pop_front() == b;
        assert deq.pop_back() == d;
        assert deq.pop_back() == c;
        assert deq.pop_back() == a;
        assert deq.len() == 0;
        deq.add_back(c);
        assert deq.len() == 1;
        deq.add_front(b);
        assert deq.len() == 2;
        deq.add_back(d);
        assert deq.len() == 3;
        deq.add_front(a);
        assert deq.len() == 4;
        assert deq.get(0) == a;
        assert deq.get(1) == b;
        assert deq.get(2) == c;
        assert deq.get(3) == d;
    }

    #[deriving_eq]
    enum Taggy { One(int), Two(int, int), Three(int, int, int), }

    #[deriving_eq]
    enum Taggypar<T> {
        Onepar(int), Twopar(int, int), Threepar(int, int, int),
    }

    #[deriving_eq]
    struct RecCy {
        x: int,
        y: int,
        t: Taggy
    }

    #[test]
    fn test_param_int() {
        test_parameterized::<int>(5, 72, 64, 175);
    }

    #[test]
    fn test_param_at_int() {
        test_parameterized::<@int>(@5, @72, @64, @175);
    }

    #[test]
    fn test_param_taggy() {
        test_parameterized::<Taggy>(One(1), Two(1, 2), Three(1, 2, 3),
                                    Two(17, 42));
    }

    #[test]
    fn test_param_taggypar() {
        test_parameterized::<Taggypar<int>>(Onepar::<int>(1),
                                            Twopar::<int>(1, 2),
                                            Threepar::<int>(1, 2, 3),
                                            Twopar::<int>(17, 42));
    }

    #[test]
    fn test_param_reccy() {
        let reccy1 = RecCy { x: 1, y: 2, t: One(1) };
        let reccy2 = RecCy { x: 345, y: 2, t: Two(1, 2) };
        let reccy3 = RecCy { x: 1, y: 777, t: Three(1, 2, 3) };
        let reccy4 = RecCy { x: 19, y: 252, t: Two(17, 42) };
        test_parameterized::<RecCy>(reccy1, reccy2, reccy3, reccy4);
    }
}
<commit_msg>deque: avoid Copy in pop_{front,back}<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::container::{Container, Mutable};
use core::cmp::Eq;
use core::prelude::*;
use core::uint;
use core::vec;

const initial_capacity: uint = 32u; // 2^5

pub struct Deque<T> {
    priv nelts: uint,
    priv lo: uint,
    priv hi: uint,
    priv elts: ~[Option<T>]
}

impl<T> Container for Deque<T> {
    pure fn len(&self) -> uint { self.nelts }
    pure fn is_empty(&self) -> bool { self.len() == 0 }
}

impl<T> Mutable for Deque<T> {
    fn clear(&mut self) {
        for vec::each_mut(self.elts) |x| { *x = None }
        self.nelts = 0;
        self.lo = 0;
        self.hi = 0;
    }
}

impl<T> Deque<T> {
    static pure fn new() -> Deque<T> {
        Deque{nelts: 0, lo: 0, hi: 0,
              elts: vec::from_fn(initial_capacity, |_| None)}
    }

    fn peek_front(&self) -> &self/T { get(self.elts, self.lo) }
    fn peek_back(&self) -> &self/T { get(self.elts, self.hi - 1u) }

    fn pop_front(&mut self) -> T {
        let mut result = self.elts[self.lo].swap_unwrap();
        self.lo = (self.lo + 1u) % self.elts.len();
        self.nelts -= 1u;
        result
    }

    fn pop_back(&mut self) -> T {
        if self.hi == 0u {
            self.hi = self.elts.len() - 1u;
        } else { self.hi -= 1u; }
        let mut result = self.elts[self.hi].swap_unwrap();
        self.elts[self.hi] = None;
        self.nelts -= 1u;
        result
    }
}

impl<T: Copy> Deque<T> {
    fn add_front(&mut self, t: T) {
        let oldlo = self.lo;
        if self.lo == 0u {
            self.lo = self.elts.len() - 1u;
        } else { self.lo -= 1u; }
        if self.lo == self.hi {
            self.elts = grow(self.nelts, oldlo, self.elts);
            self.lo = self.elts.len() - 1u;
            self.hi = self.nelts;
        }
        self.elts[self.lo] = Some(t);
        self.nelts += 1u;
    }

    fn add_back(&mut self, t: T) {
        if self.lo == self.hi && self.nelts != 0u {
            self.elts = grow(self.nelts, self.lo, self.elts);
            self.lo = 0u;
            self.hi = self.nelts;
        }
        self.elts[self.hi] = Some(t);
        self.hi = (self.hi + 1u) % self.elts.len();
        self.nelts += 1u;
    }

    fn get(&self, i: int) -> T {
        let idx = (self.lo + (i as uint)) % self.elts.len();
        *get(self.elts, idx)
    }
}

/// Grow is only called on full elts, so nelts is also len(elts), unlike
/// elsewhere.
fn grow<T: Copy>(nelts: uint, lo: uint, elts: &[Option<T>]) -> ~[Option<T>] {
    assert nelts == elts.len();
    let mut rv = ~[];

    let mut i = 0u;
    let nalloc = uint::next_power_of_two(nelts + 1u);
    while i < nalloc {
        if i < nelts {
            rv.push(elts[(lo + i) % nelts]);
        } else { rv.push(None); }
        i += 1u;
    }

    rv
}

fn get<T>(elts: &r/[Option<T>], i: uint) -> &r/T {
    match elts[i] { Some(ref t) => t, _ => fail!() }
}

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

    #[test]
    fn test_simple() {
        let mut d = Deque::new();
        assert d.len() == 0u;
        d.add_front(17);
        d.add_front(42);
        d.add_back(137);
        assert d.len() == 3u;
        d.add_back(137);
        assert d.len() == 4u;
        log(debug, d.peek_front());
        assert *d.peek_front() == 42;
        log(debug, d.peek_back());
        assert *d.peek_back() == 137;
        let mut i: int = d.pop_front();
        log(debug, i);
        assert i == 42;
        i = d.pop_back();
        log(debug, i);
        assert i == 137;
        i = d.pop_back();
        log(debug, i);
        assert i == 137;
        i = d.pop_back();
        log(debug, i);
        assert i == 17;
        assert d.len() == 0u;
        d.add_back(3);
        assert d.len() == 1u;
        d.add_front(2);
        assert d.len() == 2u;
        d.add_back(4);
        assert d.len() == 3u;
        d.add_front(1);
        assert d.len() == 4u;
        log(debug, d.get(0));
        log(debug, d.get(1));
        log(debug, d.get(2));
        log(debug, d.get(3));
        assert d.get(0) == 1;
        assert d.get(1) == 2;
        assert d.get(2) == 3;
        assert d.get(3) == 4;
    }

    #[test]
    fn test_boxes() {
        let a: @int = @5;
        let b: @int = @72;
        let c: @int = @64;
        let d: @int = @175;

        let mut deq = Deque::new();
        assert deq.len() == 0;
        deq.add_front(a);
        deq.add_front(b);
        deq.add_back(c);
        assert deq.len() == 3;
        deq.add_back(d);
        assert deq.len() == 4;
        assert *deq.peek_front() == b;
        assert *deq.peek_back() == d;
        assert deq.pop_front() == b;
        assert deq.pop_back() == d;
        assert deq.pop_back() == c;
        assert deq.pop_back() == a;
        assert deq.len() == 0;
        deq.add_back(c);
        assert deq.len() == 1;
        deq.add_front(b);
        assert deq.len() == 2;
        deq.add_back(d);
        assert deq.len() == 3;
        deq.add_front(a);
        assert deq.len() == 4;
        assert deq.get(0) == a;
        assert deq.get(1) == b;
        assert deq.get(2) == c;
        assert deq.get(3) == d;
    }

    fn test_parameterized<T: Copy Eq Durable>(a: T, b: T, c: T, d: T) {
        let mut deq = Deque::new();
        assert deq.len() == 0;
        deq.add_front(a);
        deq.add_front(b);
        deq.add_back(c);
        assert deq.len() == 3;
        deq.add_back(d);
        assert deq.len() == 4;
        assert *deq.peek_front() == b;
        assert *deq.peek_back() == d;
        assert deq.pop_front() == b;
        assert deq.pop_back() == d;
        assert deq.pop_back() == c;
        assert deq.pop_back() == a;
        assert deq.len() == 0;
        deq.add_back(c);
        assert deq.len() == 1;
        deq.add_front(b);
        assert deq.len() == 2;
        deq.add_back(d);
        assert deq.len() == 3;
        deq.add_front(a);
        assert deq.len() == 4;
        assert deq.get(0) == a;
        assert deq.get(1) == b;
        assert deq.get(2) == c;
        assert deq.get(3) == d;
    }

    #[deriving_eq]
    enum Taggy { One(int), Two(int, int), Three(int, int, int), }

    #[deriving_eq]
    enum Taggypar<T> {
        Onepar(int), Twopar(int, int), Threepar(int, int, int),
    }

    #[deriving_eq]
    struct RecCy {
        x: int,
        y: int,
        t: Taggy
    }

    #[test]
    fn test_param_int() {
        test_parameterized::<int>(5, 72, 64, 175);
    }

    #[test]
    fn test_param_at_int() {
        test_parameterized::<@int>(@5, @72, @64, @175);
    }

    #[test]
    fn test_param_taggy() {
        test_parameterized::<Taggy>(One(1), Two(1, 2), Three(1, 2, 3),
                                    Two(17, 42));
    }

    #[test]
    fn test_param_taggypar() {
        test_parameterized::<Taggypar<int>>(Onepar::<int>(1),
                                            Twopar::<int>(1, 2),
                                            Threepar::<int>(1, 2, 3),
                                            Twopar::<int>(17, 42));
    }

    #[test]
    fn test_param_reccy() {
        let reccy1 = RecCy { x: 1, y: 2, t: One(1) };
        let reccy2 = RecCy { x: 345, y: 2, t: Two(1, 2) };
        let reccy3 = RecCy { x: 1, y: 777, t: Three(1, 2, 3) };
        let reccy4 = RecCy { x: 19, y: 252, t: Two(17, 42) };
        test_parameterized::<RecCy>(reccy1, reccy2, reccy3, reccy4);
    }
}
<|endoftext|>