<commit_before>use num::bigint::{ToBigUint, BigUint};
use num::traits::{One, ToPrimitive};
use std::mem;

pub trait Max {
    fn max(width: u32) -> Self;
}
impl Max for BigUint {
    fn max(width: u32) -> BigUint {
        (BigUint::one() << width as usize) - BigUint::one()
    }
}

trait AsFixed<T> {
    fn as_fixed(&self) -> T;
}
impl AsFixed<u64> for BigUint {
    #[inline]
    fn as_fixed(&self) -> u64 {
        (self & 0xffFFffFF_ffFFffFFu64.to_biguint().unwrap())
            .to_u64()
            .unwrap()
    }
}
impl AsFixed<f64> for BigUint {
    #[inline]
    fn as_fixed(&self) -> f64 {
        let imm: u64 = self.as_fixed();
        unsafe { mem::transmute(imm) }
    }
}
impl AsFixed<f32> for BigUint {
    #[inline]
    fn as_fixed(&self) -> f32 {
        let imm: u64 = self.as_fixed();
        unsafe { mem::transmute(imm as u32) }
    }
}

/// Implement this trait for Floats to get the raw representation
pub trait AsRaw<T> {
    /// Returns the raw representation of the floating point number
    fn as_raw(&self) -> T;
}

impl AsRaw<u32> for f32 {
    fn as_raw(&self) -> u32 {
        unsafe { mem::transmute(*self) }
    }
}
impl AsRaw<u64> for f64 {
    fn as_raw(&self) -> u64 {
        unsafe { mem::transmute(*self) }
    }
}

use std::collections::VecDeque;
use std::collections::vec_deque;

// Objects
pub struct LastCache<T> {
    stack: VecDeque<T>,
    max: usize
}

impl<T> LastCache<T> {
    pub fn new(max: usize) -> LastCache<T> {
        LastCache {
            stack: VecDeque::with_capacity(max),
            max: max
        }
    }

    pub fn push(&mut self, item: T) {
        if self.stack.len() >= self.max {
            self.stack.pop_back();
            self.stack.remove(self.max - 1);
        }
        self.stack.push_front(item);
    }

    pub fn iter<'a>(&'a mut self) -> vec_deque::Iter<'a, T> {
        self.stack.iter()
    }

    pub fn last<'a>(&'a self) -> &T {
        self.stack.front().unwrap()
    }
}

impl<'a, T> IntoIterator for &'a LastCache<T> {
    type Item = &'a T;
    type IntoIter = vec_deque::Iter<'a, T>;

    fn into_iter(self) -> vec_deque::Iter<'a, T> {
        self.stack.iter()
    }
}

// Arithmetic/binary utils
/// Hamming weight
pub trait Hamming {
    fn hamming_weight(&self) -> u32;
}

impl Hamming for u64 {
    fn hamming_weight(&self) -> u32 {
        // Optimized by rust's intrinsics
        self.count_ones()
    }
}

impl Hamming for BigUint {
    fn hamming_weight(&self) -> u32 {
        let bits = self.bits();
        if bits <= 64 {
            let in64 = self.to_u64().unwrap();
            in64.hamming_weight()
        } else {
            let mut res = 0;
            for i in 0..bits {
                res += ((self >> i) & BigUint::one()).to_u32().unwrap();
            }
            res
        }
    }
}

pub fn flip_bits(num: &BigUint, width: u32) -> BigUint {
    let bits = num.bits();
    ((BigUint::one() << width as usize) - BigUint::one()) ^ num
}

// CloneWeightedChoice
use rand::Rng;
use rand::distributions::{Sample, Weighted, Range, IndependentSample};

pub struct CloneWeightedChoice<T> {
    items: Vec<Weighted<T>>,
    weight_range: Range<u32>
}

impl<T: Clone> CloneWeightedChoice<T> {
    /// Create a new `WeightedChoice`.
    ///
    /// Panics if:
    /// - `v` is empty
    /// - the total weight is 0
    /// - the total weight is larger than a `u32` can contain.
    pub fn new(items: &[Weighted<T>]) -> CloneWeightedChoice<T> {
        // strictly speaking, this is subsumed by the total weight == 0 case
        assert!(!items.is_empty(), "WeightedChoice::new called with no items");
        let mut items = items.to_vec();

        let mut running_total: u32 = 0;

        // we convert the list from individual weights to cumulative
        // weights so we can binary search. This *could* drop elements
        // with weight == 0 as an optimisation.
        for item in items.iter_mut() {
            running_total = match running_total.checked_add(item.weight) {
                Some(n) => n,
                None => panic!("WeightedChoice::new called with a total weight \
                               larger than a u32 can contain")
            };

            item.weight = running_total;
        }
        assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0");

        CloneWeightedChoice {
            items: items,
            // we're likely to be generating numbers in this range
            // relatively often, so might as well cache it
            weight_range: Range::new(0, running_total)
        }
    }
}

impl<T: Clone> Sample<T> for CloneWeightedChoice<T> {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> T { self.ind_sample(rng) }
}

impl<T: Clone> IndependentSample<T> for CloneWeightedChoice<T> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> T {
        // we want to find the first element that has cumulative
        // weight > sample_weight, which we do by binary since the
        // cumulative weights of self.items are sorted.

        // choose a weight in [0, total_weight)
        let sample_weight = self.weight_range.ind_sample(rng);

        // short circuit when it's the first item
        if sample_weight < self.items[0].weight {
            return self.items[0].item.clone();
        }

        let mut idx = 0;
        let mut modifier = self.items.len();

        // now we know that every possibility has an element to the
        // left, so we can just search for the last element that has
        // cumulative weight <= sample_weight, then the next one will
        // be "it". (Note that this greatest element will never be the
        // last element of the vector, since sample_weight is chosen
        // in [0, total_weight) and the cumulative weight of the last
        // one is exactly the total weight.)
        while modifier > 1 {
            let i = idx + modifier / 2;
            if self.items[i].weight <= sample_weight {
                // we're small, so look to the right, but allow this
                // exact element still.
                idx = i;
                // we need the `/ 2` to round up otherwise we'll drop
                // the trailing elements when `modifier` is odd.
                modifier += 1;
            } else {
                // otherwise we're too big, so go left. (i.e. do
                // nothing)
            }
            modifier /= 2;
        }
        return self.items[idx + 1].item.clone();
    }
}
// Macro utils
macro_rules! for_one {
    ($x:ident) => (1)
}
macro_rules! enum_and_list{
    ($e_name:ident, $c_name:ident, $($m:ident),+) => {
        #[derive(Copy,Clone,Debug,PartialEq,Eq,Hash,PartialOrd,Ord)]
        pub enum $e_name {
            $(
                $m,
            )+
        }
        pub const $c_name: [$e_name; 0 $( + for_one!($m) )+ ] =
            [ $($e_name::$m,)+ ];
        impl Rand for $e_name {
            fn rand<R: Rng>(rng: &mut R) -> Self {
                let val = rng.gen_range(0, $c_name.len());
                $c_name[val]
            }
        }
    }
}

#[cfg(test)]
mod test_util {
    use num::bigint::{BigUint, ToBigUint};
    use num::traits::{One, Zero};
    use utils::AsRaw;
    use utils::Hamming;
    use utils::LastCache;

    #[test]
    fn test_hamming() {
        let full_128_bu = {
            let mut res = BigUint::zero();
            for i in 0..128 {
                res = res | BigUint::one() << i;
            }
            res
        };
        assert_eq!(full_128_bu.hamming_weight(), 128);

        let full_64_u64 = 0xffFF_ffFF_ffFF_ffFFu64;
        assert_eq!(full_64_u64.hamming_weight(), 64);

        let full_64_bu = 0xffFF_ffFF_ffFF_ffFFu64.to_biguint().unwrap();
        assert_eq!(full_64_bu.hamming_weight(), 64);
    }

    #[test]
    fn test_biguint() {
        assert_eq!(0xaabbccddu32.to_biguint().unwrap().to_string(),
                   "2864434397");
    }

    #[test]
    fn test_lastcache() {
        let mut lc = LastCache::new(10);
        for i in 0 .. 10 {
            lc.push(1);
        }
        assert_eq!(lc.iter().all(|i| *i == 1), true);
        lc.push(2);
        lc.push(2);
        let mut i = 0;
        for item in &lc {
            if i == 0 || i == 1 {
                assert_eq!(*item, 2);
            } else {
                assert_eq!(*item, 1);
            }
            i += 1;
        }
    }

    #[test]
    fn test_as_raw_f32() {
        use std::f32::INFINITY;
        assert_eq!(2.8411367E-29f32.as_raw(), 0x10101010);
        assert_eq!((-4.99999998E11f32).as_raw(), 0xd2e8d4a5);
        assert_eq!(100.0f32.as_raw(), 0x42c80000);
        assert_eq!(0.0f32.as_raw(), 0);
        assert_eq!((-0.0f32).as_raw(), 0x80000000);
        assert_eq!(INFINITY.as_raw(), 0x7f800000);
    }

    #[test]
    fn test_as_raw_f64() {
        use std::f64::INFINITY;
        assert_eq!(2.8411367E-29f64.as_raw(), 0x3A0202020351C16B);
        assert_eq!((-4.99999998E11f64).as_raw(), 0xC25D1A94A00C0000);
        assert_eq!(100.0f64.as_raw(), 0x4059000000000000);
        assert_eq!(0.0f64.as_raw(), 0);
        assert_eq!((-0.0f64).as_raw(), 0x8000000000000000);
        assert_eq!(INFINITY.as_raw(), 0x7ff0000000000000);
    }

}
<commit_msg>adding debugln for making println write to stderr<commit_after>use num::bigint::{ToBigUint, BigUint};
use num::traits::{One, ToPrimitive};
use std::mem;

pub trait Max {
    fn max(width: u32) -> Self;
}
impl Max for BigUint {
    fn max(width: u32) -> BigUint {
        (BigUint::one() << width as usize) - BigUint::one()
    }
}

trait AsFixed<T> {
    fn as_fixed(&self) -> T;
}
impl AsFixed<u64> for BigUint {
    #[inline]
    fn as_fixed(&self) -> u64 {
        (self & 0xffFFffFF_ffFFffFFu64.to_biguint().unwrap())
            .to_u64()
            .unwrap()
    }
}
impl AsFixed<f64> for BigUint {
    #[inline]
    fn as_fixed(&self) -> f64 {
        let imm: u64 = self.as_fixed();
        unsafe { mem::transmute(imm) }
    }
}
impl AsFixed<f32> for BigUint {
    #[inline]
    fn as_fixed(&self) -> f32 {
        let imm: u64 = self.as_fixed();
        unsafe { mem::transmute(imm as u32) }
    }
}

/// Implement this trait for Floats to get the raw representation
pub trait AsRaw<T> {
    /// Returns the raw representation of the floating point number
    fn as_raw(&self) -> T;
}

impl AsRaw<u32> for f32 {
    fn as_raw(&self) -> u32 {
        unsafe { mem::transmute(*self) }
    }
}
impl AsRaw<u64> for f64 {
    fn as_raw(&self) -> u64 {
        unsafe { mem::transmute(*self) }
    }
}

use std::collections::VecDeque;
use std::collections::vec_deque;

// Objects
pub struct LastCache<T> {
    stack: VecDeque<T>,
    max: usize
}

impl<T> LastCache<T> {
    pub fn new(max: usize) -> LastCache<T> {
        LastCache {
            stack: VecDeque::with_capacity(max),
            max: max
        }
    }

    pub fn push(&mut self, item: T) {
        if self.stack.len() >= self.max {
            self.stack.pop_back();
            self.stack.remove(self.max - 1);
        }
        self.stack.push_front(item);
    }

    pub fn iter<'a>(&'a mut self) -> vec_deque::Iter<'a, T> {
        self.stack.iter()
    }

    pub fn last<'a>(&'a self) -> &T {
        self.stack.front().unwrap()
    }
}

impl<'a, T> IntoIterator for &'a LastCache<T> {
    type Item = &'a T;
    type IntoIter = vec_deque::Iter<'a, T>;

    fn into_iter(self) -> vec_deque::Iter<'a, T> {
        self.stack.iter()
    }
}

// Arithmetic/binary utils
/// Hamming weight
pub trait Hamming {
    fn hamming_weight(&self) -> u32;
}

impl Hamming for u64 {
    fn hamming_weight(&self) -> u32 {
        // Optimized by rust's intrinsics
        self.count_ones()
    }
}

impl Hamming for BigUint {
    fn hamming_weight(&self) -> u32 {
        let bits = self.bits();
        if bits <= 64 {
            let in64 = self.to_u64().unwrap();
            in64.hamming_weight()
        } else {
            let mut res = 0;
            for i in 0..bits {
                res += ((self >> i) & BigUint::one()).to_u32().unwrap();
            }
            res
        }
    }
}

pub fn flip_bits(num: &BigUint, width: u32) -> BigUint {
    let bits = num.bits();
    ((BigUint::one() << width as usize) - BigUint::one()) ^ num
}

// CloneWeightedChoice
use rand::Rng;
use rand::distributions::{Sample, Weighted, Range, IndependentSample};

pub struct CloneWeightedChoice<T> {
    items: Vec<Weighted<T>>,
    weight_range: Range<u32>
}

impl<T: Clone> CloneWeightedChoice<T> {
    /// Create a new `WeightedChoice`.
    ///
    /// Panics if:
    /// - `v` is empty
    /// - the total weight is 0
    /// - the total weight is larger than a `u32` can contain.
    pub fn new(items: &[Weighted<T>]) -> CloneWeightedChoice<T> {
        // strictly speaking, this is subsumed by the total weight == 0 case
        assert!(!items.is_empty(), "WeightedChoice::new called with no items");
        let mut items = items.to_vec();

        let mut running_total: u32 = 0;

        // we convert the list from individual weights to cumulative
        // weights so we can binary search. This *could* drop elements
        // with weight == 0 as an optimisation.
        for item in items.iter_mut() {
            running_total = match running_total.checked_add(item.weight) {
                Some(n) => n,
                None => panic!("WeightedChoice::new called with a total weight \
                               larger than a u32 can contain")
            };

            item.weight = running_total;
        }
        assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0");

        CloneWeightedChoice {
            items: items,
            // we're likely to be generating numbers in this range
            // relatively often, so might as well cache it
            weight_range: Range::new(0, running_total)
        }
    }
}

impl<T: Clone> Sample<T> for CloneWeightedChoice<T> {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> T { self.ind_sample(rng) }
}

impl<T: Clone> IndependentSample<T> for CloneWeightedChoice<T> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> T {
        // we want to find the first element that has cumulative
        // weight > sample_weight, which we do by binary since the
        // cumulative weights of self.items are sorted.

        // choose a weight in [0, total_weight)
        let sample_weight = self.weight_range.ind_sample(rng);

        // short circuit when it's the first item
        if sample_weight < self.items[0].weight {
            return self.items[0].item.clone();
        }

        let mut idx = 0;
        let mut modifier = self.items.len();

        // now we know that every possibility has an element to the
        // left, so we can just search for the last element that has
        // cumulative weight <= sample_weight, then the next one will
        // be "it". (Note that this greatest element will never be the
        // last element of the vector, since sample_weight is chosen
        // in [0, total_weight) and the cumulative weight of the last
        // one is exactly the total weight.)
        while modifier > 1 {
            let i = idx + modifier / 2;
            if self.items[i].weight <= sample_weight {
                // we're small, so look to the right, but allow this
                // exact element still.
                idx = i;
                // we need the `/ 2` to round up otherwise we'll drop
                // the trailing elements when `modifier` is odd.
                modifier += 1;
            } else {
                // otherwise we're too big, so go left. (i.e. do
                // nothing)
            }
            modifier /= 2;
        }
        return self.items[idx + 1].item.clone();
    }
}

// Macro utils
macro_rules! for_one {
    ($x:ident) => (1)
}
macro_rules! enum_and_list{
    ($e_name:ident, $c_name:ident, $($m:ident),+) => {
        #[derive(Copy,Clone,Debug,PartialEq,Eq,Hash,PartialOrd,Ord)]
        pub enum $e_name {
            $(
                $m,
            )+
        }
        pub const $c_name: [$e_name; 0 $( + for_one!($m) )+ ] =
            [ $($e_name::$m,)+ ];
        impl Rand for $e_name {
            fn rand<R: Rng>(rng: &mut R) -> Self {
                let val = rng.gen_range(0, $c_name.len());
                $c_name[val]
            }
        }
    }
}

macro_rules! debugln{
    ($($arg:tt)*) => (
        {
            use std::io::Write;
            match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
                Ok(_) => {},
                Err(x) => panic!("Unable to write to stderr: {}", x),
            }
        }
     )
}

#[cfg(test)]
mod test_util {
    use num::bigint::{BigUint, ToBigUint};
    use num::traits::{One, Zero};
    use utils::AsRaw;
    use utils::Hamming;
    use utils::LastCache;

    #[test]
    fn test_hamming() {
        let full_128_bu = {
            let mut res = BigUint::zero();
            for i in 0..128 {
                res = res | BigUint::one() << i;
            }
            res
        };
        assert_eq!(full_128_bu.hamming_weight(), 128);

        let full_64_u64 = 0xffFF_ffFF_ffFF_ffFFu64;
        assert_eq!(full_64_u64.hamming_weight(), 64);

        let full_64_bu = 0xffFF_ffFF_ffFF_ffFFu64.to_biguint().unwrap();
        assert_eq!(full_64_bu.hamming_weight(), 64);
    }

    #[test]
    fn test_biguint() {
        assert_eq!(0xaabbccddu32.to_biguint().unwrap().to_string(),
                   "2864434397");
    }

    #[test]
    fn test_lastcache() {
        let mut lc = LastCache::new(10);
        for i in 0 .. 10 {
            lc.push(1);
        }
        assert_eq!(lc.iter().all(|i| *i == 1), true);
        lc.push(2);
        lc.push(2);
        let mut i = 0;
        for item in &lc {
            if i == 0 || i == 1 {
                assert_eq!(*item, 2);
            } else {
                assert_eq!(*item, 1);
            }
            i += 1;
        }
    }

    #[test]
    fn test_as_raw_f32() {
        use std::f32::INFINITY;
        assert_eq!(2.8411367E-29f32.as_raw(), 0x10101010);
        assert_eq!((-4.99999998E11f32).as_raw(), 0xd2e8d4a5);
        assert_eq!(100.0f32.as_raw(), 0x42c80000);
        assert_eq!(0.0f32.as_raw(), 0);
        assert_eq!((-0.0f32).as_raw(), 0x80000000);
        assert_eq!(INFINITY.as_raw(), 0x7f800000);
    }

    #[test]
    fn test_as_raw_f64() {
        use std::f64::INFINITY;
        assert_eq!(2.8411367E-29f64.as_raw(), 0x3A0202020351C16B);
        assert_eq!((-4.99999998E11f64).as_raw(), 0xC25D1A94A00C0000);
        assert_eq!(100.0f64.as_raw(), 0x4059000000000000);
        assert_eq!(0.0f64.as_raw(), 0);
        assert_eq!((-0.0f64).as_raw(), 0x8000000000000000);
        assert_eq!(INFINITY.as_raw(), 0x7ff0000000000000);
    }

}
<|endoftext|>


<commit_before>//! Utils for testing and debugging.

use image::{
    DynamicImage,
    GenericImage,
    GrayImage,
    Luma,
    open,
    Pixel,
    Rgb,
    RgbImage
};

use quickcheck::{
    Arbitrary,
    Gen
};

use std::fmt::Debug;
use std::path::Path;

/// Panics if any pixels differ between the two input images.
#[macro_export]
macro_rules! assert_pixels_eq {
    ($actual:expr, $expected:expr) => ({
        assert_dimensions_match!($actual, $expected);
        let diffs = $crate::utils::pixel_diffs(&$actual, &$expected, |p, q| p != q);
        if !diffs.is_empty() {
            panic!($crate::utils::describe_pixel_diffs(diffs.into_iter()))
        }
     })
}

/// Panics if any pixels differ between the two images by more than the
/// given tolerance in a single channel.
#[macro_export]
macro_rules! assert_pixels_eq_within {
    ($actual:expr, $expected:expr, $channel_tolerance:expr) => ({

        assert_dimensions_match!($actual, $expected);
        let diffs = $crate::utils::pixel_diffs(&$actual, &$expected, |p, q| {

            use image::Pixel;
            let cp = p.2.channels();
            let cq = q.2.channels();
            if cp.len() != cq.len() {
                panic!("pixels have different channel counts. \
                    actual: {:?}, expected: {:?}", cp.len(), cq.len())
            }

            let mut large_diff = false;
            for i in 0..cp.len() {
                let sp = cp[i];
                let sq = cq[i];
                // Handle unsigned subpixels
                let diff = if sp > sq {sp - sq} else {sq - sp};
                if diff > $channel_tolerance {
                    large_diff = true;
                    break;
                }
            }

            large_diff
        });
        if !diffs.is_empty() {
            panic!($crate::utils::describe_pixel_diffs(diffs.into_iter()))
        }
    })
}

/// Panics if image dimensions do not match.
#[macro_export]
macro_rules! assert_dimensions_match {
    ($actual:expr, $expected:expr) => ({

        let actual_dim = $actual.dimensions();
        let expected_dim = $expected.dimensions();

        if actual_dim != expected_dim {
            panic!("dimensions do not match. \
                actual: {:?}, expected: {:?}", actual_dim, expected_dim)
        }
     })
}

/// Lists pixels that differ between left and right images.
pub fn pixel_diffs<I, F>(left: &I, right: &I, is_diff: F)
        -> Vec<((u32, u32, I::Pixel), (u32, u32, I::Pixel))>
    where I: GenericImage,
          I::Pixel: PartialEq,
          F: Fn((u32, u32, I::Pixel), (u32, u32, I::Pixel)) -> bool {

    // Can't just call $image.pixels(), as that needn't hit the
    // trait pixels method - ImageBuffer defines its own pixels
    // method with a different signature
    GenericImage::pixels(left)
        .zip(GenericImage::pixels(right))
        .filter(|&(p, q)| is_diff(p, q))//p != q)
        .collect::<Vec<_>>()
}

/// Gives a summary description of a list of pixel diffs for use in error messages.
pub fn describe_pixel_diffs<I, P>(diffs: I) -> String
    where I: Iterator<Item=(P, P)>,
          P: Debug {

    let mut err = "pixels do not match. ".to_string();
    err.push_str(&(diffs
        .take(5)
        .map(|d| format!("\nactual: {:?}, expected {:?} ", d.0, d.1))
        .collect::<Vec<_>>()
        .join("")));
    err
}

/// Loads image at given path, panicking on failure.
pub fn load_image_or_panic(path: &Path) -> DynamicImage {
     open(path)
         .ok()
         .expect(&format!("Could not load image at {:?}", path))
}

/// Gray image to use in benchmarks. This is neither noise nor
/// similar to natural images - it's just a convenience method
/// to produce an image that's not constant.
pub fn gray_bench_image(width: u32, height: u32) -> GrayImage {
    let mut image = GrayImage::new(width, height);
    for y in 0..image.height() {
        for x in 0..image.width() {
            let intensity = (x % 7 + y % 6) as u8;
            image.put_pixel(x, y, Luma([intensity]));
        }
    }
    image
}

/// RGB image to use in benchmarks. See comment on gray_bench_image.
pub fn rgb_bench_image(width: u32, height: u32) -> RgbImage {
    use std::cmp;
    let mut image = RgbImage::new(width, height);
    for y in 0..image.height() {
        for x in 0..image.width() {
            let r = (x % 7 + y % 6) as u8;
            let g = 255u8 - r;
            let b = cmp::min(r, g);
            image.put_pixel(x, y, Rgb([r, g, b]));
        }
    }
    image
}

/// Wrapper for GrayImage to allow us to write an Arbitrary instance.
pub struct GrayTestImage(GrayImage);

impl Clone for GrayTestImage {
    fn clone(&self) -> Self {
        let mut out = GrayImage::new(self.0.width(), self.0.height());
        out.copy_from(&self.0, 0, 0);
        GrayTestImage(out)
    }
}

impl Arbitrary for GrayTestImage {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        let (width, height) = small_image_dimensions(g);
        let mut image = GrayImage::new(width, height);
        for y in 0..height {
            for x in 0..width {
                let val: u8 = g.gen();
                image.put_pixel(x, y, Luma([val]));
            }
        }
        GrayTestImage(image)
    }
}

fn small_image_dimensions<G: Gen>(g: &mut G) -> (u32, u32) {
    let dims: (u8, u8) = Arbitrary::arbitrary(g);
    (dims.0 as u32, dims.1 as u32)
}

pub struct RgbTestImage(RgbImage);

impl Clone for RgbTestImage {
    fn clone(&self) -> Self {
        let mut out = RgbImage::new(self.0.width(), self.0.height());
        out.copy_from(&self.0, 0, 0);
        RgbTestImage(out)
    }
}

impl Arbitrary for RgbTestImage {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        let (width, height) = small_image_dimensions(g);
        let mut image = RgbImage::new(width, height);
        for y in 0..height {
            for x in 0..width {
                let red: u8 = g.gen();
                let green: u8 = g.gen();
                let blue: u8 = g.gen();
                image.put_pixel(x, y, Rgb([red, green, blue]));
            }
        }
        RgbTestImage(image)
    }
}

#[cfg(test)]
mod test {

    use image::{
        GrayImage,
        ImageBuffer
    };

    #[test]
    fn test_assert_pixels_eq_passes() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq!(image, image);
    }

    #[test]
    #[should_panic]
    fn test_assert_pixels_eq_fails() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 11, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq!(diff, image);
    }

    #[test]
    fn test_assert_pixels_eq_within_passes() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 02, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq_within!(diff, image, 1);
    }

    #[test]
    #[should_panic]
    fn test_assert_pixels_eq_within_fails() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 03, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq_within!(diff, image, 1);
    }
}
<commit_msg>Add comment<commit_after>//! Utils for testing and debugging.

use image::{
    DynamicImage,
    GenericImage,
    GrayImage,
    Luma,
    open,
    Pixel,
    Rgb,
    RgbImage
};

use quickcheck::{
    Arbitrary,
    Gen
};

use std::fmt::Debug;
use std::path::Path;

/// Panics if any pixels differ between the two input images.
#[macro_export]
macro_rules! assert_pixels_eq {
    ($actual:expr, $expected:expr) => ({
        assert_dimensions_match!($actual, $expected);
        let diffs = $crate::utils::pixel_diffs(&$actual, &$expected, |p, q| p != q);
        if !diffs.is_empty() {
            panic!($crate::utils::describe_pixel_diffs(diffs.into_iter()))
        }
     })
}

/// Panics if any pixels differ between the two images by more than the
/// given tolerance in a single channel.
#[macro_export]
macro_rules! assert_pixels_eq_within {
    ($actual:expr, $expected:expr, $channel_tolerance:expr) => ({

        assert_dimensions_match!($actual, $expected);
        let diffs = $crate::utils::pixel_diffs(&$actual, &$expected, |p, q| {

            use image::Pixel;
            let cp = p.2.channels();
            let cq = q.2.channels();
            if cp.len() != cq.len() {
                panic!("pixels have different channel counts. \
                    actual: {:?}, expected: {:?}", cp.len(), cq.len())
            }

            let mut large_diff = false;
            for i in 0..cp.len() {
                let sp = cp[i];
                let sq = cq[i];
                // Handle unsigned subpixels
                let diff = if sp > sq {sp - sq} else {sq - sp};
                if diff > $channel_tolerance {
                    large_diff = true;
                    break;
                }
            }

            large_diff
        });
        if !diffs.is_empty() {
            panic!($crate::utils::describe_pixel_diffs(diffs.into_iter()))
        }
    })
}

/// Panics if image dimensions do not match.
#[macro_export]
macro_rules! assert_dimensions_match {
    ($actual:expr, $expected:expr) => ({

        let actual_dim = $actual.dimensions();
        let expected_dim = $expected.dimensions();

        if actual_dim != expected_dim {
            panic!("dimensions do not match. \
                actual: {:?}, expected: {:?}", actual_dim, expected_dim)
        }
     })
}

/// Lists pixels that differ between left and right images.
pub fn pixel_diffs<I, F>(left: &I, right: &I, is_diff: F)
        -> Vec<((u32, u32, I::Pixel), (u32, u32, I::Pixel))>
    where I: GenericImage,
          I::Pixel: PartialEq,
          F: Fn((u32, u32, I::Pixel), (u32, u32, I::Pixel)) -> bool {

    // Can't just call $image.pixels(), as that needn't hit the
    // trait pixels method - ImageBuffer defines its own pixels
    // method with a different signature
    GenericImage::pixels(left)
        .zip(GenericImage::pixels(right))
        .filter(|&(p, q)| is_diff(p, q))//p != q)
        .collect::<Vec<_>>()
}

/// Gives a summary description of a list of pixel diffs for use in error messages.
pub fn describe_pixel_diffs<I, P>(diffs: I) -> String
    where I: Iterator<Item=(P, P)>,
          P: Debug {

    let mut err = "pixels do not match. ".to_string();
    err.push_str(&(diffs
        .take(5)
        .map(|d| format!("\nactual: {:?}, expected {:?} ", d.0, d.1))
        .collect::<Vec<_>>()
        .join("")));
    err
}

/// Loads image at given path, panicking on failure.
pub fn load_image_or_panic(path: &Path) -> DynamicImage {
     open(path)
         .ok()
         .expect(&format!("Could not load image at {:?}", path))
}

/// Gray image to use in benchmarks. This is neither noise nor
/// similar to natural images - it's just a convenience method
/// to produce an image that's not constant.
pub fn gray_bench_image(width: u32, height: u32) -> GrayImage {
    let mut image = GrayImage::new(width, height);
    for y in 0..image.height() {
        for x in 0..image.width() {
            let intensity = (x % 7 + y % 6) as u8;
            image.put_pixel(x, y, Luma([intensity]));
        }
    }
    image
}

/// RGB image to use in benchmarks. See comment on gray_bench_image.
pub fn rgb_bench_image(width: u32, height: u32) -> RgbImage {
    use std::cmp;
    let mut image = RgbImage::new(width, height);
    for y in 0..image.height() {
        for x in 0..image.width() {
            let r = (x % 7 + y % 6) as u8;
            let g = 255u8 - r;
            let b = cmp::min(r, g);
            image.put_pixel(x, y, Rgb([r, g, b]));
        }
    }
    image
}

/// Wrapper for GrayImage to allow us to write an Arbitrary instance.
pub struct GrayTestImage(GrayImage);

impl Clone for GrayTestImage {
    fn clone(&self) -> Self {
        let mut out = GrayImage::new(self.0.width(), self.0.height());
        out.copy_from(&self.0, 0, 0);
        GrayTestImage(out)
    }
}

impl Arbitrary for GrayTestImage {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        let (width, height) = small_image_dimensions(g);
        let mut image = GrayImage::new(width, height);
        for y in 0..height {
            for x in 0..width {
                let val: u8 = g.gen();
                image.put_pixel(x, y, Luma([val]));
            }
        }
        GrayTestImage(image)
    }
}

fn small_image_dimensions<G: Gen>(g: &mut G) -> (u32, u32) {
    let dims: (u8, u8) = Arbitrary::arbitrary(g);
    (dims.0 as u32, dims.1 as u32)
}

/// Wrapper for RgbImage to allow us to write an Arbitrary instance.
pub struct RgbTestImage(RgbImage);

impl Clone for RgbTestImage {
    fn clone(&self) -> Self {
        let mut out = RgbImage::new(self.0.width(), self.0.height());
        out.copy_from(&self.0, 0, 0);
        RgbTestImage(out)
    }
}

impl Arbitrary for RgbTestImage {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        let (width, height) = small_image_dimensions(g);
        let mut image = RgbImage::new(width, height);
        for y in 0..height {
            for x in 0..width {
                let red: u8 = g.gen();
                let green: u8 = g.gen();
                let blue: u8 = g.gen();
                image.put_pixel(x, y, Rgb([red, green, blue]));
            }
        }
        RgbTestImage(image)
    }
}

#[cfg(test)]
mod test {

    use image::{
        GrayImage,
        ImageBuffer
    };

    #[test]
    fn test_assert_pixels_eq_passes() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq!(image, image);
    }

    #[test]
    #[should_panic]
    fn test_assert_pixels_eq_fails() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 11, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq!(diff, image);
    }

    #[test]
    fn test_assert_pixels_eq_within_passes() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 02, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq_within!(diff, image, 1);
    }

    #[test]
    #[should_panic]
    fn test_assert_pixels_eq_within_fails() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 03, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq_within!(diff, image, 1);
    }
}
<|endoftext|>


<commit_before>use super::{Result, Error};

use std::sync::mpsc;
use std::net::UdpSocket;

use websocket::ws::sender::Sender as SenderTrait;
use websocket::client::{Client, Sender, Receiver};
use websocket::stream::WebSocketStream;
use websocket::message::{Message as WsMessage, Type as MessageType};

use serde_json;
use serde_json::builder::ObjectBuilder;

use super::model::*;

/// A websocket connection to the voice servers.
///
/// A VoiceConnection may be active or inactive. Use `voice_connect` and
/// `voice_disconnect` on the `Connection` you are feeding it events from to
/// change what channel it is connected to.
pub struct VoiceConnection {
	user_id: UserId,
	session_id: Option<String>,
	channel: Option<mpsc::Sender<serde_json::Value>>,
}

impl VoiceConnection {
	/// Prepare a VoiceConnection for later use.
	pub fn new(user_id: UserId) -> VoiceConnection {
		VoiceConnection {
			user_id: user_id,
			session_id: None,
			channel: None,
		}
	}

	/// Update the voice state based on an event.
	pub fn update(&mut self, event: &Event) {
		match *event {
			Event::VoiceStateUpdate(_, ref voice_state) => {
				if voice_state.user_id == self.user_id {
					println!("[Voice] Session id: {}", voice_state.session_id);
					self.session_id = Some(voice_state.session_id.clone());
					if !voice_state.channel_id.is_some() {
						self.channel.take(); // drop the connection
					}
				}
			}
			Event::VoiceServerUpdate { ref server_id, ref endpoint, ref token } => {
				println!("[Voice] Connecting to: {}", endpoint);
				self.connect(server_id, endpoint.clone(), token).expect("Voice::connect failure")
			}
			_ => {}
		}
	}

	fn connect(&mut self, server_id: &ServerId, mut endpoint: String, token: &str) -> Result<()> {
		self.channel.take(); // drop any previous connection

		// prepare the URL: drop the :80 and prepend wss://
		if endpoint.ends_with(":80") {
			let len = endpoint.len();
			endpoint.truncate(len - 3);
		}
		// establish the websocket connection
		let url = match ::websocket::client::request::Url::parse(&format!("wss://{}", endpoint)) {
			Ok(url) => url,
			Err(_) => return Err(Error::Other("Invalid URL in Voice::connect()"))
		};
		let response = try!(try!(Client::connect(url)).send());
		try!(response.validate());
		let (mut sender, receiver) = response.begin().split();

		// send the handshake
		let map = ObjectBuilder::new()
			.insert("op", 0)
			.insert_object("d", |object| object
				.insert("server_id", &server_id.0)
				.insert("user_id", &self.user_id.0)
				.insert("session_id", self.session_id.as_ref().expect("no session id"))
				.insert("token", token)
			)
			.unwrap();
		try!(sender.send_message(&WsMessage::text(try!(serde_json::to_string(&map)))));

		// spin up the voice thread, where most of the action will take place
		let (tx, rx) = mpsc::channel();
		try!(::std::thread::Builder::new()
			.name("Discord Voice Thread".into())
			.spawn(move || voice_thread(endpoint, sender, receiver, rx).unwrap()));
		self.channel = Some(tx);
		Ok(())
	}
}

fn recv_message(receiver: &mut Receiver<WebSocketStream>) -> Result<VoiceEvent> {
	use websocket::ws::receiver::Receiver;
	let message: WsMessage = try!(receiver.recv_message());
	if message.opcode != MessageType::Text {
		return Err(Error::Other("Got an non-Text frame as voice handshake response"))
	}
	let json: serde_json::Value = try!(serde_json::from_reader(&message.payload[..]));
	let original = format!("{:?}", json);
	VoiceEvent::decode(json).map_err(|err| {
		// If there was a decode failure, print the original json for debugging
		println!("[Warning] Error vdecoding: {}", original);
		err
	})
}

fn voice_thread(
	endpoint: String,
	mut sender: Sender<WebSocketStream>,
	mut receiver: Receiver<WebSocketStream>,
	channel: mpsc::Receiver<serde_json::Value>,
) -> Result<()> {
	use std::io::{Cursor, Read, Write};
	use byteorder::{LittleEndian, BigEndian, WriteBytesExt, ReadBytesExt};

	// read the first websocket message
	let (interval, port, ssrc, modes) = match try!(recv_message(&mut receiver)) {
		VoiceEvent::Handshake { heartbeat_interval, port, ssrc, modes } => (heartbeat_interval, port, ssrc, modes),
		_ => return Err(Error::Other("First voice message was not 4/handshake"))
	};
	if !modes.iter().find(|&s| s == "plain").is_some() {
		return Err(Error::Other("Plain voice mode is unavailable"))
	}

	// bind a UDP socket and send the ssrc value in a packet as identification
	let udp = try!(UdpSocket::bind("0.0.0.0:0"));
	let mut bytes = [0; 4];
	try!(Cursor::new(&mut bytes[..]).write_u32::<BigEndian>(ssrc));
	try!(udp.send_to(&bytes, (&endpoint[..], port)));

	// receive the response to the identification to get port and address info
	let mut bytes = [0; 256];
	let (len, _remote_addr) = try!(udp.recv_from(&mut bytes));
	let mut cursor = Cursor::new(&bytes[..len]);
	let _ = try!(cursor.read_u32::<LittleEndian>()); // discard padding
	let port_number = try!(cursor.read_u16::<LittleEndian>());

	// send the acknowledgement websocket message
	let map = ObjectBuilder::new()
		.insert("op", 1)
		.insert_object("d", |object| object
			.insert("protocol", "udp")
			.insert_object("data", |object| object
				.insert("address", "")
				.insert("port", port_number)
				.insert("mode", "plain")
			)
		)
		.unwrap();
	try!(sender.send_message(&WsMessage::text(try!(serde_json::to_string(&map)))));

	// discard websocket messages until we get the Ready
	loop {
		match try!(recv_message(&mut receiver)) {
			VoiceEvent::Ready { mode, secret_key } => {
				if secret_key.len() != 0 {
					println!("[Voice] Got secret key: {:?}", secret_key);
				}
				if mode != "plain" {
					return Err(Error::Other("Voice mode in Ready was not 'plain'"))
				}
				break
			}
			VoiceEvent::Unknown(op, value) => println!("[Voice] Unknown {}/{:?}", op, value),
			_ => {},
		}
	}

	// prepare buffers for later use
	let mut opus = ::utils::OpusEncoder::new().expect("failed new");
	let mut file = try!(::std::fs::File::open("../res/discord-swing.pcm"));
	let mut test_data = Vec::with_capacity(960);
	let mut packet = Vec::with_capacity(256);
	let mut sequence = 0;
	let mut timestamp = 0;

	// tell 'em that we're speaking
	let map = ObjectBuilder::new()
		.insert("op", 5)
		.insert_object("d", |object| object
			.insert("speaking", true)
			.insert("delay", 0)
		)
		.unwrap();
	try!(sender.send_message(&WsMessage::text(try!(serde_json::to_string(&map)))));

	let audio_duration = ::time::Duration::milliseconds(20);
	let keepalive_duration = ::time::Duration::milliseconds(interval as i64);
	let mut audio_timer = ::utils::Timer::new(::time::Duration::zero());
	let mut keepalive_timer = ::utils::Timer::new(keepalive_duration);

	// start the main loop
	println!("[Voice] Ready");
	'outer: loop {
		::std::thread::sleep_ms(3);

		loop {
			match channel.try_recv() {
				Ok(val) => {
					let json = try!(serde_json::to_string(&val));
					try!(sender.send_message(&WsMessage::text(json)));
				},
				Err(mpsc::TryRecvError::Empty) => break,
				Err(mpsc::TryRecvError::Disconnected) => break 'outer,
			}
		}

		if keepalive_timer.check_and_add(keepalive_duration) {
			let map = ObjectBuilder::new()
				.insert("op", 3)
				.insert("d", serde_json::Value::Null)
				.unwrap();
			let json = try!(serde_json::to_string(&map));
			try!(sender.send_message(&WsMessage::text(json)));
		}

		if audio_timer.check_and_add(audio_duration) {
			const HEADER_LEN: usize = 12;
			// prepare the packet header
			packet.clear();
			try!(packet.write_all(&[0x80, 0x78]));
			try!(packet.write_u16::<BigEndian>(sequence));
			try!(packet.write_u32::<BigEndian>(timestamp));
			try!(packet.write_u32::<BigEndian>(ssrc));
			let zeroes = packet.capacity() - HEADER_LEN;
			packet.extend(::std::iter::repeat(0).take(zeroes));

			// read the test data
			test_data.clear();
			for _ in 0..test_data.capacity() {
				test_data.push(try!(file.read_i16::<LittleEndian>()) / 6);
			}

			// encode the audio data and transmit it
			let len = opus.encode(&test_data, &mut packet[HEADER_LEN..]).expect("failed encode");
			try!(udp.send_to(&packet[..len + HEADER_LEN], (&endpoint[..], port)));

			sequence = sequence.wrapping_add(1);
			timestamp = timestamp.wrapping_add(960);
		}
	}

	// stop speaking
	::std::thread::sleep_ms(500);
	let map = ObjectBuilder::new()
		.insert("op", 5)
		.insert_object("d", |object| object
			.insert("speaking", false)
			.insert("delay", 0)
		)
		.unwrap();
	try!(sender.send_message(&WsMessage::text(try!(serde_json::to_string(&map)))));

	try!(receiver.get_mut().get_mut().shutdown(::std::net::Shutdown::Both));
	try!(sender.get_mut().shutdown(::std::net::Shutdown::Both));
	Ok(())
}
<commit_msg>Add interface for queueing upcoming audio<commit_after>use super::{Result, Error};

use std::io::{Read, Write};
use std::sync::mpsc;
use std::net::UdpSocket;

use websocket::ws::sender::Sender as SenderTrait;
use websocket::client::{Client, Sender, Receiver};
use websocket::stream::WebSocketStream;
use websocket::message::{Message as WsMessage, Type as MessageType};

use serde_json;
use serde_json::builder::ObjectBuilder;

use byteorder::{LittleEndian, BigEndian, WriteBytesExt, ReadBytesExt};

use super::model::*;

/// A websocket connection to the voice servers.
///
/// A VoiceConnection may be active or inactive. Use `voice_connect` and
/// `voice_disconnect` on the `Connection` you are feeding it events from to
/// change what channel it is connected to.
pub struct VoiceConnection {
	user_id: UserId,
	session_id: Option<String>,
	channel: Option<mpsc::Sender<Status>>,
	queue: Vec<AudioSource>,
}

impl VoiceConnection {
	/// Prepare a VoiceConnection for later use.
	pub fn new(user_id: UserId) -> VoiceConnection {
		VoiceConnection {
			user_id: user_id,
			session_id: None,
			channel: None,
			queue: Vec::new(),
		}
	}

	/// Update the voice state based on an event.
	pub fn update(&mut self, event: &Event) {
		match *event {
			Event::VoiceStateUpdate(_, ref voice_state) => {
				if voice_state.user_id == self.user_id {
					println!("[Voice] Session id: {}", voice_state.session_id);
					self.session_id = Some(voice_state.session_id.clone());
					if !voice_state.channel_id.is_some() {
						self.channel.take(); // drop the connection
					}
				}
			}
			Event::VoiceServerUpdate { ref server_id, ref endpoint, ref token } => {
				println!("[Voice] Connecting to: {}", endpoint);
				self.connect(server_id, endpoint.clone(), token).expect("Voice::connect failure")
			}
			_ => {}
		}
	}

	/// Check whether the voice thread is currently running.
	pub fn is_running(&self) -> bool {
		match self.channel {
			None => false,
			Some(ref channel) => channel.send(Status::NoOp).is_ok(),
		}
	}

	/// Push the raw PCM file at the given path to the queue.
	pub fn push_pcm_file<R: Read + Send + 'static>(&mut self, read: R) {
		self.push_internal(AudioSource::Pcm(Box::new(read)));
	}

	/// Stop any currently playing audio and clear the queue.
	pub fn stop_audio(&mut self) {
		self.channel.as_ref().map(|ch| ch.send(Status::Clear));
		self.queue.clear();
	}

	fn push_internal(&mut self, source: AudioSource) {
		match self.channel {
			None => self.queue.push(source),
			Some(ref channel) => match channel.send(Status::Push(source)) {
				Ok(()) => {},
				Err(mpsc::SendError(Status::Push(source))) => self.queue.push(source),
				Err(_) => unreachable!()
			}
		}
	}

	fn connect(&mut self, server_id: &ServerId, mut endpoint: String, token: &str) -> Result<()> {
		self.channel.take(); // drop any previous connection

		// prepare the URL: drop the :80 and prepend wss://
		if endpoint.ends_with(":80") {
			let len = endpoint.len();
			endpoint.truncate(len - 3);
		}
		// establish the websocket connection
		let url = match ::websocket::client::request::Url::parse(&format!("wss://{}", endpoint)) {
			Ok(url) => url,
			Err(_) => return Err(Error::Other("Invalid URL in Voice::connect()"))
		};
		let response = try!(try!(Client::connect(url)).send());
		try!(response.validate());
		let (mut sender, receiver) = response.begin().split();

		// send the handshake
		let map = ObjectBuilder::new()
			.insert("op", 0)
			.insert_object("d", |object| object
				.insert("server_id", &server_id.0)
				.insert("user_id", &self.user_id.0)
				.insert("session_id", self.session_id.as_ref().expect("no session id"))
				.insert("token", token)
			)
			.unwrap();
		try!(sender.send_message(&WsMessage::text(try!(serde_json::to_string(&map)))));

		// spin up the voice thread, where most of the action will take place
		let (tx, rx) = mpsc::channel();
		try!(::std::thread::Builder::new()
			.name("Discord Voice Thread".into())
			.spawn(move || voice_thread(endpoint, sender, receiver, rx).unwrap()));
		for source in ::std::mem::replace(&mut self.queue, Vec::new()) {
			let _ = tx.send(Status::Push(source));
		}
		self.channel = Some(tx);
		Ok(())
	}
}

enum Status {
	Push(AudioSource),
	Clear,
	NoOp,
}

fn recv_message(receiver: &mut Receiver<WebSocketStream>) -> Result<VoiceEvent> {
	use websocket::ws::receiver::Receiver;
	let message: WsMessage = try!(receiver.recv_message());
	if message.opcode != MessageType::Text {
		return Err(Error::Other("Got an non-Text frame as voice handshake response"))
	}
	let json: serde_json::Value = try!(serde_json::from_reader(&message.payload[..]));
	let original = format!("{:?}", json);
	VoiceEvent::decode(json).map_err(|err| {
		// If there was a decode failure, print the original json for debugging
		println!("[Warning] Error vdecoding: {}", original);
		err
	})
}

fn voice_thread(
	endpoint: String,
	mut sender: Sender<WebSocketStream>,
	mut receiver: Receiver<WebSocketStream>,
	channel: mpsc::Receiver<Status>,
) -> Result<()> {
	use std::io::Cursor;

	// read the first websocket message
	let (interval, port, ssrc, modes) = match try!(recv_message(&mut receiver)) {
		VoiceEvent::Handshake { heartbeat_interval, port, ssrc, modes } => (heartbeat_interval, port, ssrc, modes),
		_ => return Err(Error::Other("First voice message was not 4/handshake"))
	};
	if !modes.iter().find(|&s| s == "plain").is_some() {
		return Err(Error::Other("Plain voice mode is unavailable"))
	}

	// bind a UDP socket and send the ssrc value in a packet as identification
	let udp = try!(UdpSocket::bind("0.0.0.0:0"));
	let mut bytes = [0; 4];
	try!(Cursor::new(&mut bytes[..]).write_u32::<BigEndian>(ssrc));
	try!(udp.send_to(&bytes, (&endpoint[..], port)));

	// receive the response to the identification to get port and address info
	let mut bytes = [0; 256];
	let (len, _remote_addr) = try!(udp.recv_from(&mut bytes));
	let mut cursor = Cursor::new(&bytes[..len]);
	let _ = try!(cursor.read_u32::<LittleEndian>()); // discard padding
	let port_number = try!(cursor.read_u16::<LittleEndian>());

	// send the acknowledgement websocket message
	let map = ObjectBuilder::new()
		.insert("op", 1)
		.insert_object("d", |object| object
			.insert("protocol", "udp")
			.insert_object("data", |object| object
				.insert("address", "")
				.insert("port", port_number)
				.insert("mode", "plain")
			)
		)
		.unwrap();
	try!(sender.send_message(&WsMessage::text(try!(serde_json::to_string(&map)))));

	// discard websocket messages until we get the Ready
	loop {
		match try!(recv_message(&mut receiver)) {
			VoiceEvent::Ready { mode, secret_key } => {
				if secret_key.len() != 0 {
					println!("[Voice] Got secret key: {:?}", secret_key);
				}
				if mode != "plain" {
					return Err(Error::Other("Voice mode in Ready was not 'plain'"))
				}
				break
			}
			VoiceEvent::Unknown(op, value) => println!("[Voice] Unknown {}/{:?}", op, value),
			_ => {},
		}
	}

	// prepare buffers for later use
	let mut opus = ::utils::OpusEncoder::new().expect("failed new");
	let mut audio_queue = ::std::collections::VecDeque::new();
	let mut audio_buffer = vec![0; 960];
	let mut packet = Vec::with_capacity(256);
	let mut sequence = 0;
	let mut timestamp = 0;

	// tell 'em that we're speaking
	let map = ObjectBuilder::new()
		.insert("op", 5)
		.insert_object("d", |object| object
			.insert("speaking", true)
			.insert("delay", 0)
		)
		.unwrap();
	try!(sender.send_message(&WsMessage::text(try!(serde_json::to_string(&map)))));

	let audio_duration = ::time::Duration::milliseconds(20);
	let keepalive_duration = ::time::Duration::milliseconds(interval as i64);
	let mut audio_timer = ::utils::Timer::new(::time::Duration::zero());
	let mut keepalive_timer = ::utils::Timer::new(keepalive_duration);

	// start the main loop
	println!("[Voice] Ready");
	'outer: loop {
		::std::thread::sleep_ms(3);

		loop {
			match channel.try_recv() {
				Ok(Status::Push(source)) => {
					audio_queue.push_back(source)
				},
				Ok(Status::Clear) => audio_queue.clear(),
				Ok(Status::NoOp) => {},
				Err(mpsc::TryRecvError::Empty) => break,
				Err(mpsc::TryRecvError::Disconnected) => break 'outer,
			}
		}

		if keepalive_timer.check_and_add(keepalive_duration) {
			let map = ObjectBuilder::new()
				.insert("op", 3)
				.insert("d", serde_json::Value::Null)
				.unwrap();
			let json = try!(serde_json::to_string(&map));
			try!(sender.send_message(&WsMessage::text(json)));
		}

		if audio_timer.check_and_add(audio_duration) && audio_queue.len() > 0 {
			const HEADER_LEN: usize = 12;
			// prepare the packet header
			packet.clear();
			try!(packet.write_all(&[0x80, 0x78]));
			try!(packet.write_u16::<BigEndian>(sequence));
			try!(packet.write_u32::<BigEndian>(timestamp));
			try!(packet.write_u32::<BigEndian>(ssrc));
			let zeroes = packet.capacity() - HEADER_LEN;
			packet.extend(::std::iter::repeat(0).take(zeroes));

			// read the audio from the source and zero-fill any leftovers
			let len = try!(audio_queue[0].next(&mut audio_buffer[..]));
			if len < audio_buffer.len() {
				// zero-fill the buffer and advance to the next audio source
				for value in &mut audio_buffer[len..] {
					*value = 0;
				}
				audio_queue.pop_front();
			}

			// encode the audio data and transmit it
			let len = opus.encode(&audio_buffer, &mut packet[HEADER_LEN..]).expect("failed encode");
			try!(udp.send_to(&packet[..len + HEADER_LEN], (&endpoint[..], port)));

			sequence = sequence.wrapping_add(1);
			timestamp = timestamp.wrapping_add(960);
		}
	}

	// stop speaking
	::std::thread::sleep_ms(500);
	let map = ObjectBuilder::new()
		.insert("op", 5)
		.insert_object("d", |object| object
			.insert("speaking", false)
			.insert("delay", 0)
		)
		.unwrap();
	try!(sender.send_message(&WsMessage::text(try!(serde_json::to_string(&map)))));

	try!(receiver.get_mut().get_mut().shutdown(::std::net::Shutdown::Both));
	try!(sender.get_mut().shutdown(::std::net::Shutdown::Both));
	Ok(())
}

enum AudioSource {
	Pcm(Box<::std::io::Read + Send>),
}

impl AudioSource {
	fn next(&mut self, buffer: &mut [i16]) -> Result<usize> {
		match *self {
			AudioSource::Pcm(ref mut read) => {
				for (i, val) in buffer.iter_mut().enumerate() {
					*val = match read.read_i16::<LittleEndian>() {
						Ok(val) => val / 6,
						Err(::byteorder::Error::UnexpectedEOF) => return Ok(i),
						Err(::byteorder::Error::Io(e)) => return Err(From::from(e))
					};
				}
				Ok(buffer.len())
			}
		}
	}
}
<|endoftext|>


<commit_before>use chrono;
use chrono::TimeZone;
use futures_cpupool::CpuPool;
use futures::{BoxFuture, Future};
use r2d2;
use r2d2_sqlite::SqliteConnectionManager;
use rusqlite;
use rand::{Rng, thread_rng};
use serde;
use linear_map::LinearMap;

use std::sync::Arc;
use std::path::Path;

#[derive(Clone, Debug, Serialize)]
pub struct Transaction {
    pub shafter: String,
    pub shaftee: String,
    pub amount: i64,
    #[serde(serialize_with = "serialize_time")]
    pub datetime: chrono::DateTime<chrono::Utc>,
    pub reason: String,
}

#[derive(Debug, Clone, Serialize)]
pub struct User {
    pub user_id: String,
    pub display_name: String,
    pub balance: i64,
}

pub trait Database: Send + Sync {
    fn get_user_by_github_id(&self, github_user_id: String)
        -> BoxFuture<Option<String>, DatabaseError>;

    fn add_user_by_github_id(&self, github_user_id: String, display_name: String)
        -> BoxFuture<String, DatabaseError>;

    fn create_token_for_user(&self, user_id: String)
        -> BoxFuture<String, DatabaseError>;

    fn delete_token(&self, token: String)
        -> BoxFuture<(), DatabaseError>;

    fn get_user_from_token(&self, token: String)
        -> BoxFuture<Option<User>, DatabaseError>;

    fn get_balance_for_user(&self, user: String)
        -> BoxFuture<i64, DatabaseError>;

    fn get_all_users(&self)
        -> BoxFuture<LinearMap<String, User>, DatabaseError>;

    fn shaft_user(&self, transaction: Transaction)
        -> BoxFuture<(), ShaftUserError>;

    fn get_last_transactions(&self, limit: u32)
        -> BoxFuture<Vec<Transaction>, DatabaseError>;
}

#[derive(Clone)]
pub struct SqliteDatabase {
    cpu_pool: CpuPool,
    db_pool: Arc<r2d2::Pool<SqliteConnectionManager>>,
}

impl SqliteDatabase {
    pub fn with_path<P: AsRef<Path>>(path: P) -> SqliteDatabase {
        let config = r2d2::Config::default();
        let manager = SqliteConnectionManager::new(path);
        let pool = r2d2::Pool::new(config, manager).unwrap();

        SqliteDatabase {
            cpu_pool: CpuPool::new_num_cpus(),
            db_pool: Arc::new(pool),
        }
    }
}

impl Database for SqliteDatabase {
    fn get_user_by_github_id(&self, github_user_id: String)
        -> BoxFuture<Option<String>, DatabaseError>
    {
        let db_pool = self.db_pool.clone();

        self.cpu_pool.spawn_fn(move || -> Result<_, DatabaseError>  {
            let conn = db_pool.get()?;

            let row = conn.query_row(
                "SELECT user_id FROM github_users WHERE github_id = $1",
                &[&github_user_id],
                |row| -> String {
                    row.get(0)
                }
            )
            .map(|row| Some(row))
            .or_else(|err| {
                if let rusqlite::Error::QueryReturnedNoRows = err {
                    Ok(None)
                } else {
                    Err(err)
                }
            })?;

            Ok(row)
        }).boxed()
    }

    fn add_user_by_github_id(&self, github_user_id: String, display_name: String)
        -> BoxFuture<String, DatabaseError>
    {
        let db_pool = self.db_pool.clone();

        self.cpu_pool.spawn_fn(move || -> Result<_, DatabaseError>  {
            let conn = db_pool.get()?;

            conn.execute(
                "INSERT INTO github_users (user_id, github_id)
                VALUES ($1, $1, $2)",
                &[&github_user_id],
            )?;

             conn.execute(
                "INSERT INTO users (user_id, display_name)
                VALUES ($1, $1, $2)",
                &[&github_user_id, &display_name],
            )?;

            Ok(github_user_id)
        }).boxed()
    }

    fn create_token_for_user(&self, user_id: String)
        -> BoxFuture<String, DatabaseError>
    {
        let db_pool = self.db_pool.clone();

        self.cpu_pool.spawn_fn(move || -> Result<_, DatabaseError>  {
            let conn = db_pool.get()?;

            let token: String = thread_rng().gen_ascii_chars().take(32).collect();

            conn.execute(
                "INSERT INTO tokens (user_id, token) VALUES ($1, $2)",
                &[&user_id, &token],
            )?;

            Ok(token)
        }).boxed()
    }

    fn delete_token(&self, token: String)
        -> BoxFuture<(), DatabaseError>
    {
        let db_pool = self.db_pool.clone();

        self.cpu_pool.spawn_fn(move || -> Result<_, DatabaseError>  {
            let conn = db_pool.get()?;

            conn.execute(
                "DELETE FROM tokens WHERE token = $1",
                &[&token],
            )?;

            Ok(())
        }).boxed()
    }

    fn get_user_from_token(&self, token: String)
        -> BoxFuture<Option<User>, DatabaseError>
    {
        let db_pool = self.db_pool.clone();

        self.cpu_pool.spawn_fn(move || -> Result<_, DatabaseError>  {
            let conn = db_pool.get()?;

            let row = conn.query_row(
                r#"
                SELECT user_id, display_name, COALESCE(balance, 0)
                FROM tokens
                INNER JOIN users USING (user_id)
                LEFT JOIN (
                    SELECT user_id, SUM(amount) as balance
                    FROM (
                        SELECT shafter AS user_id, SUM(amount) AS amount
                        FROM transactions GROUP BY shafter
                        UNION ALL
                        SELECT shaftee AS user_id, -SUM(amount) AS amount
                        FROM transactions GROUP BY shaftee
                    ) t GROUP BY user_id
                )
                USING (user_id)
                WHERE token = $1
                "#,
                &[&token],
                |row| -> User {
                    User {
                        user_id: row.get(0),
                        display_name: row.get(1),
                        balance: row.get(2),
                    }
                }
            )
            .map(|row| Some(row))
            .or_else(|err| {
                if let rusqlite::Error::QueryReturnedNoRows = err {
                    Ok(None)
                } else {
                    Err(err)
                }
            })?;

            Ok(row)
        }).boxed()
    }

    fn get_balance_for_user(&self, user: String)
        -> BoxFuture<i64, DatabaseError>
    {
        let db_pool = self.db_pool.clone();

        self.cpu_pool.spawn_fn(move || -> Result<_, DatabaseError>  {
            let conn = db_pool.get()?;

            let row = conn.query_row(
                r#"SELECT (
                    SELECT COALESCE(SUM(amount), 0)
                    FROM transactions
                    WHERE shafter = $1
                ) - (
                    SELECT COALESCE(SUM(amount), 0)
                    FROM transactions
                    WHERE shaftee = $1
                )"#,
                &[&user],
                |row| -> i64 {
                    row.get(0)
                }
            )?;

            Ok(row)
        }).boxed()
    }

    fn get_all_users(&self)
        -> BoxFuture<LinearMap<String, User>, DatabaseError>
    {
        let db_pool = self.db_pool.clone();

        self.cpu_pool.spawn_fn(move || -> Result<_, DatabaseError>  {
            let conn = db_pool.get()?;

            let mut stmt = conn.prepare(
                r#"
                SELECT user_id, display_name, COALESCE(balance, 0) AS balance
                FROM users
                LEFT JOIN (
                    SELECT user_id, SUM(amount) as balance
                    FROM (
                        SELECT shafter AS user_id, SUM(amount) AS amount
                        FROM transactions GROUP BY shafter
                        UNION ALL
                        SELECT shaftee AS user_id, -SUM(amount) AS amount
                        FROM transactions GROUP BY shaftee
                    ) t GROUP BY user_id
                )
                USING (user_id)
                ORDER BY balance ASC
                "#
            )?;

            let rows: Result<LinearMap<String, User>, _> = stmt.query_map(
                &[],
                |row| -> (String, User) {
                    (row.get(0), User {
                        user_id: row.get(0),
                        display_name: row.get(1),
                        balance: row.get(2),
                    })
                }
            )?.collect();

            Ok(rows?)
        }).boxed()
    }

    fn shaft_user(&self, transaction: Transaction)
        -> BoxFuture<(), ShaftUserError>
    {
        let db_pool = self.db_pool.clone();

        self.cpu_pool.spawn_fn(move || -> Result<_, ShaftUserError>  {
            let conn = db_pool.get()?;

            match conn.query_row(
                "SELECT user_id FROM users WHERE user_id = $1",
                &[&transaction.shaftee],
                |_row| {}
            ) {
                Ok(_) => (),
                Err(rusqlite::Error::QueryReturnedNoRows) => {
                    return Err(ShaftUserError::UnknownUser(transaction.shaftee))
                }
                Err(err) => {
                    return Err(ShaftUserError::Database(err.into()))
                }
            }

            let mut stmt = conn.prepare(
                "INSERT INTO transactions (shafter, shaftee, amount, time_sec, reason)\
                VALUES ($1, $2, $3, $4, $5)"
            )?;

            stmt.execute(&[
                &transaction.shafter,
                &transaction.shaftee,
                &transaction.amount,
                &transaction.datetime.timestamp(),
                &transaction.reason,
            ])?;

            Ok(())
        }).boxed()
    }

    fn get_last_transactions(&self, limit: u32)
        -> BoxFuture<Vec<Transaction>, DatabaseError>
    {
        let db_pool = self.db_pool.clone();

        self.cpu_pool.spawn_fn(move || -> Result<_, DatabaseError>  {
            let conn = db_pool.get()?;

            let mut stmt = conn.prepare(
                r#"SELECT shafter, shaftee, amount, time_sec, reason
                FROM transactions
                ORDER BY id DESC
                LIMIT $1
                "#
            )?;

            let rows: Result<Vec<_>, _> = stmt.query_map(
                &[&limit],
                |row| {
                    Transaction {
                        shafter: row.get(0),
                        shaftee: row.get(1),
                        amount: row.get(2),
                        datetime: chrono::Utc.timestamp(row.get(3), 0),
                        reason: row.get(4),
                    }
                }
            )?.collect();

            Ok(rows?)
        }).boxed()
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum DatabaseError {
        ConnectionPool(err: r2d2::GetTimeout) {
            from()
            display("DB Pool error: {}", err)
        }
        SqliteError(err: rusqlite::Error) {
            from()
            display("Sqlite Pool error: {}", err)
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum ShaftUserError {
        Database(err: DatabaseError) {
            from()
            from(e: r2d2::GetTimeout) -> (DatabaseError::from(e))
            from(e: rusqlite::Error) -> (DatabaseError::from(e))
            display("{}", err)
        }
        UnknownUser(user_id: String) {
            from()
            display("Unknown user: {}", user_id)
        }
    }
}

fn serialize_time<S>(date: &chrono::DateTime<chrono::Utc>, serializer: S)
    -> Result<S::Ok, S::Error>
where S: serde::Serializer
{
    serializer.serialize_i64(date.timestamp())
}<commit_msg>Fix sql<commit_after>use chrono;
use chrono::TimeZone;
use futures_cpupool::CpuPool;
use futures::{BoxFuture, Future};
use r2d2;
use r2d2_sqlite::SqliteConnectionManager;
use rusqlite;
use rand::{Rng, thread_rng};
use serde;
use linear_map::LinearMap;

use std::sync::Arc;
use std::path::Path;

#[derive(Clone, Debug, Serialize)]
pub struct Transaction {
    pub shafter: String,
    pub shaftee: String,
    pub amount: i64,
    #[serde(serialize_with = "serialize_time")]
    pub datetime: chrono::DateTime<chrono::Utc>,
    pub reason: String,
}

#[derive(Debug, Clone, Serialize)]
pub struct User {
    pub user_id: String,
    pub display_name: String,
    pub balance: i64,
}

pub trait Database: Send + Sync {
    fn get_user_by_github_id(&self, github_user_id: String)
        -> BoxFuture<Option<String>, DatabaseError>;

    fn add_user_by_github_id(&self, github_user_id: String, display_name: String)
        -> BoxFuture<String, DatabaseError>;

    fn create_token_for_user(&self, user_id: String)
        -> BoxFuture<String, DatabaseError>;

    fn delete_token(&self, token: String)
        -> BoxFuture<(), DatabaseError>;

    fn get_user_from_token(&self, token: String)
        -> BoxFuture<Option<User>, DatabaseError>;

    fn get_balance_for_user(&self, user: String)
        -> BoxFuture<i64, DatabaseError>;

    fn get_all_users(&self)
        -> BoxFuture<LinearMap<String, User>, DatabaseError>;

    fn shaft_user(&self, transaction: Transaction)
        -> BoxFuture<(), ShaftUserError>;

    fn get_last_transactions(&self, limit: u32)
        -> BoxFuture<Vec<Transaction>, DatabaseError>;
}

#[derive(Clone)]
pub struct SqliteDatabase {
    cpu_pool: CpuPool,
    db_pool: Arc<r2d2::Pool<SqliteConnectionManager>>,
}

impl SqliteDatabase {
    pub fn with_path<P: AsRef<Path>>(path: P) -> SqliteDatabase {
        let config = r2d2::Config::default();
        let manager = SqliteConnectionManager::new(path);
        let pool = r2d2::Pool::new(config, manager).unwrap();

        SqliteDatabase {
            cpu_pool: CpuPool::new_num_cpus(),
            db_pool: Arc::new(pool),
        }
    }
}

impl Database for SqliteDatabase {
    fn get_user_by_github_id(&self, github_user_id: String)
        -> BoxFuture<Option<String>, DatabaseError>
    {
        let db_pool = self.db_pool.clone();

        self.cpu_pool.spawn_fn(move || -> Result<_, DatabaseError>  {
            let conn = db_pool.get()?;

            let row = conn.query_row(
                "SELECT user_id FROM github_users WHERE github_id = $1",
                &[&github_user_id],
                |row| -> String {
                    row.get(0)
                }
            )
            .map(|row| Some(row))
            .or_else(|err| {
                if let rusqlite::Error::QueryReturnedNoRows = err {
                    Ok(None)
                } else {
                    Err(err)
                }
            })?;

            Ok(row)
        }).boxed()
    }

    fn add_user_by_github_id(&self, github_user_id: String, display_name: String)
        -> BoxFuture<String, DatabaseError>
    {
        let db_pool = self.db_pool.clone();

        self.cpu_pool.spawn_fn(move || -> Result<_, DatabaseError>  {
            let conn = db_pool.get()?;

            conn.execute(
                "INSERT INTO github_users (user_id, github_id)
                VALUES ($1, $1)",
                &[&github_user_id],
            )?;

             conn.execute(
                "INSERT INTO users (user_id, display_name)
                VALUES ($1, $2)",
                &[&github_user_id, &display_name],
            )?;

            Ok(github_user_id)
        }).boxed()
    }

    fn create_token_for_user(&self, user_id: String)
        -> BoxFuture<String, DatabaseError>
    {
        let db_pool = self.db_pool.clone();

        self.cpu_pool.spawn_fn(move || -> Result<_, DatabaseError>  {
            let conn = db_pool.get()?;

            let token: String = thread_rng().gen_ascii_chars().take(32).collect();

            conn.execute(
                "INSERT INTO tokens (user_id, token) VALUES ($1, $2)",
                &[&user_id, &token],
            )?;

            Ok(token)
        }).boxed()
    }

    fn delete_token(&self, token: String)
        -> BoxFuture<(), DatabaseError>
    {
        let db_pool = self.db_pool.clone();

        self.cpu_pool.spawn_fn(move || -> Result<_, DatabaseError>  {
            let conn = db_pool.get()?;

            conn.execute(
                "DELETE FROM tokens WHERE token = $1",
                &[&token],
            )?;

            Ok(())
        }).boxed()
    }

    fn get_user_from_token(&self, token: String)
        -> BoxFuture<Option<User>, DatabaseError>
    {
        let db_pool = self.db_pool.clone();

        self.cpu_pool.spawn_fn(move || -> Result<_, DatabaseError>  {
            let conn = db_pool.get()?;

            let row = conn.query_row(
                r#"
                SELECT user_id, display_name, COALESCE(balance, 0)
                FROM tokens
                INNER JOIN users USING (user_id)
                LEFT JOIN (
                    SELECT user_id, SUM(amount) as balance
                    FROM (
                        SELECT shafter AS user_id, SUM(amount) AS amount
                        FROM transactions GROUP BY shafter
                        UNION ALL
                        SELECT shaftee AS user_id, -SUM(amount) AS amount
                        FROM transactions GROUP BY shaftee
                    ) t GROUP BY user_id
                )
                USING (user_id)
                WHERE token = $1
                "#,
                &[&token],
                |row| -> User {
                    User {
                        user_id: row.get(0),
                        display_name: row.get(1),
                        balance: row.get(2),
                    }
                }
            )
            .map(|row| Some(row))
            .or_else(|err| {
                if let rusqlite::Error::QueryReturnedNoRows = err {
                    Ok(None)
                } else {
                    Err(err)
                }
            })?;

            Ok(row)
        }).boxed()
    }

    fn get_balance_for_user(&self, user: String)
        -> BoxFuture<i64, DatabaseError>
    {
        let db_pool = self.db_pool.clone();

        self.cpu_pool.spawn_fn(move || -> Result<_, DatabaseError>  {
            let conn = db_pool.get()?;

            let row = conn.query_row(
                r#"SELECT (
                    SELECT COALESCE(SUM(amount), 0)
                    FROM transactions
                    WHERE shafter = $1
                ) - (
                    SELECT COALESCE(SUM(amount), 0)
                    FROM transactions
                    WHERE shaftee = $1
                )"#,
                &[&user],
                |row| -> i64 {
                    row.get(0)
                }
            )?;

            Ok(row)
        }).boxed()
    }

    fn get_all_users(&self)
        -> BoxFuture<LinearMap<String, User>, DatabaseError>
    {
        let db_pool = self.db_pool.clone();

        self.cpu_pool.spawn_fn(move || -> Result<_, DatabaseError>  {
            let conn = db_pool.get()?;

            let mut stmt = conn.prepare(
                r#"
                SELECT user_id, display_name, COALESCE(balance, 0) AS balance
                FROM users
                LEFT JOIN (
                    SELECT user_id, SUM(amount) as balance
                    FROM (
                        SELECT shafter AS user_id, SUM(amount) AS amount
                        FROM transactions GROUP BY shafter
                        UNION ALL
                        SELECT shaftee AS user_id, -SUM(amount) AS amount
                        FROM transactions GROUP BY shaftee
                    ) t GROUP BY user_id
                )
                USING (user_id)
                ORDER BY balance ASC
                "#
            )?;

            let rows: Result<LinearMap<String, User>, _> = stmt.query_map(
                &[],
                |row| -> (String, User) {
                    (row.get(0), User {
                        user_id: row.get(0),
                        display_name: row.get(1),
                        balance: row.get(2),
                    })
                }
            )?.collect();

            Ok(rows?)
        }).boxed()
    }

    fn shaft_user(&self, transaction: Transaction)
        -> BoxFuture<(), ShaftUserError>
    {
        let db_pool = self.db_pool.clone();

        self.cpu_pool.spawn_fn(move || -> Result<_, ShaftUserError>  {
            let conn = db_pool.get()?;

            match conn.query_row(
                "SELECT user_id FROM users WHERE user_id = $1",
                &[&transaction.shaftee],
                |_row| {}
            ) {
                Ok(_) => (),
                Err(rusqlite::Error::QueryReturnedNoRows) => {
                    return Err(ShaftUserError::UnknownUser(transaction.shaftee))
                }
                Err(err) => {
                    return Err(ShaftUserError::Database(err.into()))
                }
            }

            let mut stmt = conn.prepare(
                "INSERT INTO transactions (shafter, shaftee, amount, time_sec, reason)\
                VALUES ($1, $2, $3, $4, $5)"
            )?;

            stmt.execute(&[
                &transaction.shafter,
                &transaction.shaftee,
                &transaction.amount,
                &transaction.datetime.timestamp(),
                &transaction.reason,
            ])?;

            Ok(())
        }).boxed()
    }

    fn get_last_transactions(&self, limit: u32)
        -> BoxFuture<Vec<Transaction>, DatabaseError>
    {
        let db_pool = self.db_pool.clone();

        self.cpu_pool.spawn_fn(move || -> Result<_, DatabaseError>  {
            let conn = db_pool.get()?;

            let mut stmt = conn.prepare(
                r#"SELECT shafter, shaftee, amount, time_sec, reason
                FROM transactions
                ORDER BY id DESC
                LIMIT $1
                "#
            )?;

            let rows: Result<Vec<_>, _> = stmt.query_map(
                &[&limit],
                |row| {
                    Transaction {
                        shafter: row.get(0),
                        shaftee: row.get(1),
                        amount: row.get(2),
                        datetime: chrono::Utc.timestamp(row.get(3), 0),
                        reason: row.get(4),
                    }
                }
            )?.collect();

            Ok(rows?)
        }).boxed()
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum DatabaseError {
        ConnectionPool(err: r2d2::GetTimeout) {
            from()
            display("DB Pool error: {}", err)
        }
        SqliteError(err: rusqlite::Error) {
            from()
            display("Sqlite Pool error: {}", err)
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum ShaftUserError {
        Database(err: DatabaseError) {
            from()
            from(e: r2d2::GetTimeout) -> (DatabaseError::from(e))
            from(e: rusqlite::Error) -> (DatabaseError::from(e))
            display("{}", err)
        }
        UnknownUser(user_id: String) {
            from()
            display("Unknown user: {}", user_id)
        }
    }
}

fn serialize_time<S>(date: &chrono::DateTime<chrono::Utc>, serializer: S)
    -> Result<S::Ok, S::Error>
where S: serde::Serializer
{
    serializer.serialize_i64(date.timestamp())
}<|endoftext|>


<commit_before>use super::{f32, Lab};

pub struct DE2000;

impl DE2000 {
    //! Returns the difference between two `Lab` colors as calculated by the
    //! [CIEDE2000 algorithm](http://en.wikipedia.org/wiki/Color_difference#CIEDE2000).

    pub fn new(x1: Lab, x2: Lab) -> f32 {
        let ksub_l = 1.0;
        let ksub_c = 1.0;
        let ksub_h = 1.0;

        let delta_l_prime = x2.l - x1.l;

        let l_bar = (x1.l + x2.l) / 2.0;

        let c1 = (x1.a.powi(2) + x1.b.powi(2)).sqrt();
        let c2 = (x2.a.powi(2) + x2.b.powi(2)).sqrt();

        let c_bar = (c1 + c2) / 2.0;

        let a_prime_1 =
            x1.a + (x1.a / 2.0) * (1.0 - (c_bar.powi(7) / (c_bar.powi(7) + 25f32.powi(7))).sqrt());
        let a_prime_2 =
            x2.a + (x2.a / 2.0) * (1.0 - (c_bar.powi(7) / (c_bar.powi(7) + 25f32.powi(7))).sqrt());

        let c_prime_1 = (a_prime_1.powi(2) + x1.b.powi(2)).sqrt();
        let c_prime_2 = (a_prime_2.powi(2) + x2.b.powi(2)).sqrt();

        let c_bar_prime = (c_prime_1 + c_prime_2) / 2.0;

        let delta_c_prime = c_prime_2 - c_prime_1;

        let s_sub_l = 1.0 +
                      ((0.015 * (l_bar - 50.0).powi(2)) / (20.0 + (l_bar - 50.0).powi(2)).sqrt());

        let s_sub_c = 1.0 + 0.045 * c_bar_prime;

        let h_prime_1 = get_h_prime_fn(x1.b, a_prime_1);
        let h_prime_2 = get_h_prime_fn(x2.b, a_prime_2);

        let delta_h_prime = get_delta_h_prime(c1, c2, h_prime_1, h_prime_2);

        let delta_updase_h_prime = 2.0 * (c_prime_1 * c_prime_2).sqrt() *
                                   (degrees_to_radians(delta_h_prime) / 2.0).sin();

        let upcase_h_bar_prime = get_upcase_h_bar_prime(h_prime_1, h_prime_2);

        let upcase_t = get_upcase_t(upcase_h_bar_prime);

        let s_sub_upcase_h = 1.0 + 0.015 * c_bar_prime * upcase_t;

        let r_sub_t = get_r_sub_t(c_bar_prime, upcase_h_bar_prime);

        let lightness: f32 = delta_l_prime / (ksub_l * s_sub_l);

        let chroma: f32 = delta_c_prime / (ksub_c * s_sub_c);

        let hue: f32 = delta_updase_h_prime / (ksub_h * s_sub_upcase_h);

        (lightness.powi(2) + chroma.powi(2) + hue.powi(2) + r_sub_t * chroma * hue).sqrt()
    }
}

fn get_h_prime_fn(x: f32, y: f32) -> f32 {
    let hue_angle;

    if x == 0.0 && y == 0.0 {
        return 0.0;
    }

    hue_angle = radians_to_degrees(x.atan2(y));

    if hue_angle < 0.0 {
        hue_angle + 360.0;
    }

    hue_angle
}

fn get_delta_h_prime(c1: f32, c2: f32, h_prime_1: f32, h_prime_2: f32) -> f32 {
    if 0.0 == c1 || 0.0 == c2 {
        return 0.0;
    }

    if (h_prime_1 - h_prime_2).abs() <= 180.0 {
        return h_prime_2 - h_prime_1;
    }

    if h_prime_2 <= h_prime_1 {
        return h_prime_2 - h_prime_1 + 360.0;
    } else {
        return h_prime_2 - h_prime_1 - 360.0;
    }
}

fn get_upcase_h_bar_prime(h_prime_1: f32, h_prime_2: f32) -> f32 {
    if (h_prime_1 - h_prime_2).abs() > 180.0 {
        return (h_prime_1 + h_prime_2 + 360.0) / 2.0;
    }

    (h_prime_1 + h_prime_2) / 2.0
}

fn get_upcase_t(upcase_h_bar_prime: f32) -> f32 {
    1.0 - 0.17 * (degrees_to_radians(upcase_h_bar_prime - 30.0)).cos() +
    0.24 * (degrees_to_radians(2.0 * upcase_h_bar_prime)).cos() +
    0.32 * (degrees_to_radians(3.0 * upcase_h_bar_prime + 6.0)).cos() -
    0.20 * (degrees_to_radians(4.0 * upcase_h_bar_prime - 63.0)).cos()
}

fn get_r_sub_t(c_bar_prime: f32, upcase_h_bar_prime: f32) -> f32 {
    -2.0 * (c_bar_prime.powi(7) / (c_bar_prime.powi(7) + 25f32.powi(7))).sqrt() *
    (degrees_to_radians(60.0 * (-(((upcase_h_bar_prime - 275.0) / 25.0).powi(2))).exp())).sin()
}

fn radians_to_degrees(radians: f32) -> f32 {
    radians * (180.0 / f32::consts::PI)
}

fn degrees_to_radians(degrees: f32) -> f32 {
    degrees * (f32::consts::PI / 180.0)
}

#[cfg(test)]
mod tests {
    use super::{DE2000, Lab};

    #[test]
    fn it_works() {
        let x1 = Lab {
            l: 36.0,
            a: 60.0,
            b: 41.0,
        };

        let x2 = Lab {
            l: 55.0,
            a: 66.0,
            b: 77.0,
        };

        assert_eq!(DE2000::new(x1, x2), 22.394508);
    }
}
<commit_msg>Fix variable typo<commit_after>use super::{f32, Lab};

pub struct DE2000;

impl DE2000 {
    //! Returns the difference between two `Lab` colors as calculated by the
    //! [CIEDE2000 algorithm](http://en.wikipedia.org/wiki/Color_difference#CIEDE2000).

    pub fn new(x1: Lab, x2: Lab) -> f32 {
        let ksub_l = 1.0;
        let ksub_c = 1.0;
        let ksub_h = 1.0;

        let delta_l_prime = x2.l - x1.l;

        let l_bar = (x1.l + x2.l) / 2.0;

        let c1 = (x1.a.powi(2) + x1.b.powi(2)).sqrt();
        let c2 = (x2.a.powi(2) + x2.b.powi(2)).sqrt();

        let c_bar = (c1 + c2) / 2.0;

        let a_prime_1 =
            x1.a + (x1.a / 2.0) * (1.0 - (c_bar.powi(7) / (c_bar.powi(7) + 25f32.powi(7))).sqrt());
        let a_prime_2 =
            x2.a + (x2.a / 2.0) * (1.0 - (c_bar.powi(7) / (c_bar.powi(7) + 25f32.powi(7))).sqrt());

        let c_prime_1 = (a_prime_1.powi(2) + x1.b.powi(2)).sqrt();
        let c_prime_2 = (a_prime_2.powi(2) + x2.b.powi(2)).sqrt();

        let c_bar_prime = (c_prime_1 + c_prime_2) / 2.0;

        let delta_c_prime = c_prime_2 - c_prime_1;

        let s_sub_l = 1.0 +
                      ((0.015 * (l_bar - 50.0).powi(2)) / (20.0 + (l_bar - 50.0).powi(2)).sqrt());

        let s_sub_c = 1.0 + 0.045 * c_bar_prime;

        let h_prime_1 = get_h_prime_fn(x1.b, a_prime_1);
        let h_prime_2 = get_h_prime_fn(x2.b, a_prime_2);

        let delta_h_prime = get_delta_h_prime(c1, c2, h_prime_1, h_prime_2);

        let delta_upcase_h_prime = 2.0 * (c_prime_1 * c_prime_2).sqrt() *
                                   (degrees_to_radians(delta_h_prime) / 2.0).sin();

        let upcase_h_bar_prime = get_upcase_h_bar_prime(h_prime_1, h_prime_2);

        let upcase_t = get_upcase_t(upcase_h_bar_prime);

        let s_sub_upcase_h = 1.0 + 0.015 * c_bar_prime * upcase_t;

        let r_sub_t = get_r_sub_t(c_bar_prime, upcase_h_bar_prime);

        let lightness: f32 = delta_l_prime / (ksub_l * s_sub_l);

        let chroma: f32 = delta_c_prime / (ksub_c * s_sub_c);

        let hue: f32 = delta_upcase_h_prime / (ksub_h * s_sub_upcase_h);

        (lightness.powi(2) + chroma.powi(2) + hue.powi(2) + r_sub_t * chroma * hue).sqrt()
    }
}

fn get_h_prime_fn(x: f32, y: f32) -> f32 {
    let hue_angle;

    if x == 0.0 && y == 0.0 {
        return 0.0;
    }

    hue_angle = radians_to_degrees(x.atan2(y));

    if hue_angle < 0.0 {
        hue_angle + 360.0;
    }

    hue_angle
}

fn get_delta_h_prime(c1: f32, c2: f32, h_prime_1: f32, h_prime_2: f32) -> f32 {
    if 0.0 == c1 || 0.0 == c2 {
        return 0.0;
    }

    if (h_prime_1 - h_prime_2).abs() <= 180.0 {
        return h_prime_2 - h_prime_1;
    }

    if h_prime_2 <= h_prime_1 {
        return h_prime_2 - h_prime_1 + 360.0;
    } else {
        return h_prime_2 - h_prime_1 - 360.0;
    }
}

fn get_upcase_h_bar_prime(h_prime_1: f32, h_prime_2: f32) -> f32 {
    if (h_prime_1 - h_prime_2).abs() > 180.0 {
        return (h_prime_1 + h_prime_2 + 360.0) / 2.0;
    }

    (h_prime_1 + h_prime_2) / 2.0
}

fn get_upcase_t(upcase_h_bar_prime: f32) -> f32 {
    1.0 - 0.17 * (degrees_to_radians(upcase_h_bar_prime - 30.0)).cos() +
    0.24 * (degrees_to_radians(2.0 * upcase_h_bar_prime)).cos() +
    0.32 * (degrees_to_radians(3.0 * upcase_h_bar_prime + 6.0)).cos() -
    0.20 * (degrees_to_radians(4.0 * upcase_h_bar_prime - 63.0)).cos()
}

fn get_r_sub_t(c_bar_prime: f32, upcase_h_bar_prime: f32) -> f32 {
    -2.0 * (c_bar_prime.powi(7) / (c_bar_prime.powi(7) + 25f32.powi(7))).sqrt() *
    (degrees_to_radians(60.0 * (-(((upcase_h_bar_prime - 275.0) / 25.0).powi(2))).exp())).sin()
}

fn radians_to_degrees(radians: f32) -> f32 {
    radians * (180.0 / f32::consts::PI)
}

fn degrees_to_radians(degrees: f32) -> f32 {
    degrees * (f32::consts::PI / 180.0)
}

#[cfg(test)]
mod tests {
    use super::{DE2000, Lab};

    #[test]
    fn it_works() {
        let x1 = Lab {
            l: 36.0,
            a: 60.0,
            b: 41.0,
        };

        let x2 = Lab {
            l: 55.0,
            a: 66.0,
            b: 77.0,
        };

        assert_eq!(DE2000::new(x1, x2), 22.394508);
    }
}
<|endoftext|>


<commit_before>use std::ptr;
use std::io::{IoError, standard_error, FileNotFound};
use std::fmt;
use libc::dev_t;
use std::iter;
use std::time::Duration;

use libudev_c;
use util;
use iterator;

use udev::Udev;
use iterator::UdevIterator;

pub struct Device<'u> {
    pub udev: &'u Udev,
    dev: libudev_c::udev_device,
}
pub type Devnum = dev_t;
pub enum DeviceType {
    CharDev,
    BlockDev
}

// Crate Private
pub unsafe fn device<'u>(udev: &'u Udev, dev: libudev_c::udev_device) -> Device<'u> {
    Device { udev: udev, dev: dev }
}

pub unsafe fn device_get_dev(device: &Device) -> libudev_c::udev_device {
    device.dev
}

impl<'u> Device<'u> {
    pub fn parent(&self) -> Option<Device> {
        match util::check_errno(|| unsafe {
            libudev_c::udev_device_ref(libudev_c::udev_device_get_parent(self.dev))
        }) {
            Ok(Some(dev)) => Some(unsafe { device(self.udev, dev) }),
            _ => None
        }
    }

    pub fn parent_with_subsystem(&self, subsystem: &str) -> Option<Device> {
        match subsystem.with_c_str(|subsystem| util::check_errno(|| unsafe {
            libudev_c::udev_device_ref(
                libudev_c::udev_device_get_parent_with_subsystem_devtype(self.dev, subsystem, ptr::null()))
        })) {
            Ok(Some(dev)) => Some(unsafe { device(self.udev, dev) }),
            _ => None
        }
    }

    pub fn parent_with_subsystem_devtype(&self, subsystem: &str, devtype: &str) -> Option<Device> {
        match subsystem.with_c_str(|subsystem| devtype.with_c_str(|devtype| util::check_errno(|| unsafe {
            libudev_c::udev_device_ref(
                libudev_c::udev_device_get_parent_with_subsystem_devtype(self.dev, subsystem, devtype))
        }))) {
            Ok(Some(dev)) => Some(unsafe { device(self.udev, dev) }),
            _ => None
        }
    }

    pub fn attribute<'s>(&'s self, attr: &str) -> Result<&'s str, IoError> {
        match attr.with_c_str(|cstr| util::check_errno(|| unsafe {
            libudev_c::udev_device_get_sysattr_value(self.dev, cstr)
        })) {
            Ok(Some(val)) => Ok(unsafe { util::c_to_str(val) }.unwrap()),
            Ok(None) => Err(standard_error(FileNotFound)),
            Err(errno) => Err(IoError::from_errno(errno as uint, true)),
        }
    }

    pub fn set_attribute(&self, attr: &str, value: &str) -> Result<(), IoError> {
        attr.with_c_str(|attr| value.with_c_str(|value| match unsafe {
            libudev_c::udev_device_set_sysattr_value(self.dev, attr, value)
        } {
            0           => Ok(()),
            n if n < 0  => Err(IoError::from_errno(-n as uint, true)),
            _           => fail!("udev returned an invalid error")
        }))
    }

    pub fn devpath<'s>(&'s self) -> &'s str {
        unsafe {
            util::c_to_str(libudev_c::udev_device_get_devpath(self.dev)).unwrap()
        }
    }

    pub fn syspath<'s>(&'s self) -> Path {
        unsafe {
            Path::new(util::c_to_str(libudev_c::udev_device_get_syspath(self.dev)).unwrap())
        }
    }

    pub fn sysname<'s>(&'s self) -> &'s str {
        unsafe {
            util::c_to_str(libudev_c::udev_device_get_sysname(self.dev)).unwrap()
        }
    }

    pub fn subsystem<'s>(&'s self) -> Option<&'s str> {
        unsafe {
            util::c_to_str(libudev_c::udev_device_get_subsystem(self.dev))
        }
    }

    pub fn devtype<'s>(&'s self) -> Option<&'s str> {
        unsafe {
            util::c_to_str(libudev_c::udev_device_get_devtype(self.dev))
        }
    }

    pub fn sysnum(&self) -> Option<u64> {
        match unsafe {
            util::c_to_str(libudev_c::udev_device_get_sysnum(self.dev))
        } {
            Some(n) => from_str(n),
            None => None
        }
    }

    pub fn devnum(&self) -> Option<Devnum> {
        match unsafe {
            libudev_c::udev_device_get_devnum(self.dev)
        } {
            0 => None,
            n => Some(n)
        }
    }

    pub fn driver<'s>(&'s self) -> Option<&'s str> {
        unsafe {
            util::c_to_str(libudev_c::udev_device_get_driver(self.dev))
        }
    }

    pub fn devnode<'s>(&'s self) -> Option<Path> {
        unsafe {
            util::c_to_str(libudev_c::udev_device_get_devnode(self.dev))
        }.map(|path| Path::new(path))
    }

    pub fn iter_devlinks(&self) -> iter::Map<(&Device,&str,Option<&str>),Path,UdevIterator<Device>> {
        unsafe {
            iterator::udev_iterator(self, libudev_c::udev_device_get_devlinks_list_entry(self.dev))
        }.map(|(_, key, _)| Path::new(key))
    }

    pub fn iter_tags(&self) -> iter::Map<(&Device,&str,Option<&str>),&str,UdevIterator<Device>> {
        unsafe {
            iterator::udev_iterator(self, libudev_c::udev_device_get_tags_list_entry(self.dev))
        }.map(|(_, key, _)| key)
    }

    pub fn iter_properties(&self) -> iter::Map<(&Device,&str,Option<&str>),(&str, Option<&str>),UdevIterator<Device>> {
        unsafe {
            iterator::udev_iterator(self, libudev_c::udev_device_get_properties_list_entry(self.dev))
        }.map(|(_, key, value)| (key, value))
    }

    pub fn iter_attributes(& self) -> iter::Map<(&Device,&str,Option<&str>),&str,UdevIterator<Device>> {
        unsafe {
            iterator::udev_iterator(self, libudev_c::udev_device_get_sysattr_list_entry(self.dev))
        }.map(|(_, key, _)| key)
    }

    pub fn time_since_initialized(&self) -> Option<Duration> {
        let usec = unsafe { libudev_c::udev_device_get_usec_since_initialized(self.dev) };
        if usec == 0 {
            None
        } else {
            // Note: I don't support machines that are online for over 292,471 years. Sorry.
            Some(Duration::microseconds(usec as i64))
        }
    }

    pub fn is_initialized(&self) -> bool {
        unsafe { libudev_c::udev_device_get_is_initialized(self.dev) != 0 }
    }

    pub fn has_tag(&self, tag: &str) -> bool {
        tag.with_c_str(|tag| unsafe {
            libudev_c::udev_device_has_tag(self.dev, tag) != 0
        })
    }
}

#[unsafe_destructor]
impl<'u> Drop for Device<'u> {
    fn drop(&mut self) {
        unsafe { libudev_c::udev_device_unref(self.dev) };
    }
}

impl<'u> fmt::Show for Device<'u> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.syspath().as_str().unwrap())
    }
}

impl DeviceType {
    pub fn to_char(self) -> i8 {
        match self {
            CharDev => 'c' as i8,
            BlockDev => 'b' as i8
        }
    }
}
<commit_msg>Document device.<commit_after>use std::ptr;
use std::io::{IoError, standard_error, FileNotFound};
use std::fmt;
use libc::dev_t;
use std::iter;
use std::time::Duration;

use libudev_c;
use util;
use iterator;

use udev::Udev;
use iterator::UdevIterator;

pub struct Device<'u> {
    pub udev: &'u Udev,
    dev: libudev_c::udev_device,
}
pub type Devnum = dev_t;
pub enum DeviceType {
    CharDev,
    BlockDev
}

// Crate Private
pub unsafe fn device<'u>(udev: &'u Udev, dev: libudev_c::udev_device) -> Device<'u> {
    Device { udev: udev, dev: dev }
}

pub unsafe fn device_get_dev(device: &Device) -> libudev_c::udev_device {
    device.dev
}

impl<'u> Device<'u> {
    /// Get the device's parent if one exists.
    pub fn parent(&self) -> Option<Device> {
        match util::check_errno(|| unsafe {
            libudev_c::udev_device_ref(libudev_c::udev_device_get_parent(self.dev))
        }) {
            Ok(Some(dev)) => Some(unsafe { device(self.udev, dev) }),
            _ => None
        }
    }

    /// Get the first parent with the specified subsystem.
    pub fn parent_with_subsystem(&self, subsystem: &str) -> Option<Device> {
        match subsystem.with_c_str(|subsystem| util::check_errno(|| unsafe {
            libudev_c::udev_device_ref(
                libudev_c::udev_device_get_parent_with_subsystem_devtype(self.dev, subsystem, ptr::null()))
        })) {
            Ok(Some(dev)) => Some(unsafe { device(self.udev, dev) }),
            _ => None
        }
    }

    /// Get the first parent with the specified subsystem and devtype.
    pub fn parent_with_subsystem_devtype(&self, subsystem: &str, devtype: &str) -> Option<Device> {
        match subsystem.with_c_str(|subsystem| devtype.with_c_str(|devtype| util::check_errno(|| unsafe {
            libudev_c::udev_device_ref(
                libudev_c::udev_device_get_parent_with_subsystem_devtype(self.dev, subsystem, devtype))
        }))) {
            Ok(Some(dev)) => Some(unsafe { device(self.udev, dev) }),
            _ => None
        }
    }

    /// Read a sysfs attribute.
    pub fn attribute<'s>(&'s self, attr: &str) -> Result<&'s str, IoError> {
        match attr.with_c_str(|cstr| util::check_errno(|| unsafe {
            libudev_c::udev_device_get_sysattr_value(self.dev, cstr)
        })) {
            Ok(Some(val)) => Ok(unsafe { util::c_to_str(val) }.unwrap()),
            Ok(None) => Err(standard_error(FileNotFound)),
            Err(errno) => Err(IoError::from_errno(errno as uint, true)),
        }
    }

    /// Write a sysfs attribute.
    pub fn set_attribute(&self, attr: &str, value: &str) -> Result<(), IoError> {
        attr.with_c_str(|attr| value.with_c_str(|value| match unsafe {
            libudev_c::udev_device_set_sysattr_value(self.dev, attr, value)
        } {
            0           => Ok(()),
            n if n < 0  => Err(IoError::from_errno(-n as uint, true)),
            _           => fail!("udev returned an invalid error")
        }))
    }

    /// Get the path to the device (minus `/sys`).
    pub fn devpath<'s>(&'s self) -> &'s str {
        unsafe {
            util::c_to_str(libudev_c::udev_device_get_devpath(self.dev)).unwrap()
        }
    }

    /// Get the full path to the device (including `/sys`).
    pub fn syspath<'s>(&'s self) -> Path {
        unsafe {
            Path::new(util::c_to_str(libudev_c::udev_device_get_syspath(self.dev)).unwrap())
        }
    }

    /// Get the device name.
    ///
    /// E.g. wlan0
    pub fn sysname<'s>(&'s self) -> &'s str {
        unsafe {
            util::c_to_str(libudev_c::udev_device_get_sysname(self.dev)).unwrap()
        }
    }

    /// Get the devices subsystem
    pub fn subsystem<'s>(&'s self) -> Option<&'s str> {
        unsafe {
            util::c_to_str(libudev_c::udev_device_get_subsystem(self.dev))
        }
    }

    /// Get the devices devtype
    pub fn devtype<'s>(&'s self) -> Option<&'s str> {
        unsafe {
            util::c_to_str(libudev_c::udev_device_get_devtype(self.dev))
        }
    }

    /// Get the devices sysnum.
    ///
    /// E.g. the X in ethX, wlanX, etc.
    pub fn sysnum(&self) -> Option<u64> {
        match unsafe {
            util::c_to_str(libudev_c::udev_device_get_sysnum(self.dev))
        } {
            Some(n) => from_str(n),
            None => None
        }
    }

    /// Get the device's devnum.
    pub fn devnum(&self) -> Option<Devnum> {
        match unsafe {
            libudev_c::udev_device_get_devnum(self.dev)
        } {
            0 => None,
            n => Some(n)
        }
    }

    /// Get the device's driver.
    pub fn driver<'s>(&'s self) -> Option<&'s str> {
        unsafe {
            util::c_to_str(libudev_c::udev_device_get_driver(self.dev))
        }
    }

    /// Get the device's devnode
    ///
    /// E.g. `/dev/sda`
    pub fn devnode<'s>(&'s self) -> Option<Path> {
        unsafe {
            util::c_to_str(libudev_c::udev_device_get_devnode(self.dev))
        }.map(|path| Path::new(path))
    }

    /// Iterate over the device's devlinks
    ///
    /// E.g. the symlinks in `/dev/disk/by-*/`
    pub fn iter_devlinks(&self) -> iter::Map<(&Device,&str,Option<&str>),Path,UdevIterator<Device>> {
        unsafe {
            iterator::udev_iterator(self, libudev_c::udev_device_get_devlinks_list_entry(self.dev))
        }.map(|(_, key, _)| Path::new(key))
    }

    /// Iterate over the device's tags.
    pub fn iter_tags(&self) -> iter::Map<(&Device,&str,Option<&str>),&str,UdevIterator<Device>> {
        unsafe {
            iterator::udev_iterator(self, libudev_c::udev_device_get_tags_list_entry(self.dev))
        }.map(|(_, key, _)| key)
    }

    /// Iterate over the device's properties.
    pub fn iter_properties(&self) -> iter::Map<(&Device,&str,Option<&str>),(&str, Option<&str>),UdevIterator<Device>> {
        unsafe {
            iterator::udev_iterator(self, libudev_c::udev_device_get_properties_list_entry(self.dev))
        }.map(|(_, key, value)| (key, value))
    }

    /// Iterate over the device's sysfs attribute names
    pub fn iter_attributes(& self) -> iter::Map<(&Device,&str,Option<&str>),&str,UdevIterator<Device>> {
        unsafe {
            iterator::udev_iterator(self, libudev_c::udev_device_get_sysattr_list_entry(self.dev))
        }.map(|(_, key, _)| key)
    }

    /// Get the time since the device was initialized by udev.
    pub fn time_since_initialized(&self) -> Option<Duration> {
        let usec = unsafe { libudev_c::udev_device_get_usec_since_initialized(self.dev) };
        if usec == 0 {
            None
        } else {
            // Note: I don't support machines that are online for over 292,471 years. Sorry.
            Some(Duration::microseconds(usec as i64))
        }
    }

    /// Determine if the device has been initialized.
    pub fn is_initialized(&self) -> bool {
        unsafe { libudev_c::udev_device_get_is_initialized(self.dev) != 0 }
    }

    /// Check whether the device is tagged with a given tag.
    pub fn has_tag(&self, tag: &str) -> bool {
        tag.with_c_str(|tag| unsafe {
            libudev_c::udev_device_has_tag(self.dev, tag) != 0
        })
    }
}

#[unsafe_destructor]
impl<'u> Drop for Device<'u> {
    fn drop(&mut self) {
        unsafe { libudev_c::udev_device_unref(self.dev) };
    }
}

impl<'u> fmt::Show for Device<'u> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.syspath().as_str().unwrap())
    }
}

impl DeviceType {
    pub fn to_char(self) -> i8 {
        match self {
            CharDev => 'c' as i8,
            BlockDev => 'b' as i8
        }
    }
}
<|endoftext|>