<commit_before>#![crate_name = "bytes"]
#![unstable]

#![feature(alloc, core, io, unsafe_no_drop_flag)]

pub use byte_buf::{ByteBuf, ROByteBuf, MutByteBuf};
pub use byte_str::{SeqByteStr, SmallByteStr, SmallByteStrBuf};
pub use bytes::Bytes;
pub use ring::{RingBuf, RingBufReader, RingBufWriter};
pub use rope::Rope;
pub use slice::{SliceBuf, MutSliceBuf};

use std::{cmp, io, ops, ptr, u32};

extern crate core;

mod alloc;
mod byte_buf;
mod byte_str;
mod bytes;
mod ring;
mod rope;
mod slice;

pub mod traits {
    //! All traits are re-exported here to allow glob imports.
    pub use {Buf, BufExt, MutBuf, MutBufExt, ByteStr};
}

const MAX_CAPACITY: usize = u32::MAX as usize;

/// A trait for values that provide sequential read access to bytes.
pub trait Buf {

    /// Returns the number of bytes that can be accessed from the Buf
    fn remaining(&self) -> usize;

    /// Returns a slice starting at the current Buf position and of length
    /// between 0 and `Buf::remaining()`.
    fn bytes<'a>(&'a self) -> &'a [u8];

    /// Advance the internal cursor of the Buf
    fn advance(&mut self, cnt: usize);

    /// Returns true if there are any more bytes to consume
    fn has_remaining(&self) -> bool {
        self.remaining() > 0
    }

    /// Read bytes from the `Buf` into the given slice and advance the cursor by
    /// the number of bytes read.
    ///
    /// If there are fewer bytes remaining than is needed to satisfy the
    /// request (aka `dst.len()` > self.remaining()`), then
    /// `Err(BufError::Overflow)` is returned.
    ///
    /// ```
    /// use bytes::{SliceBuf, Buf};
    ///
    /// let mut buf = SliceBuf::wrap(b"hello world");
    /// let mut dst = [0; 5];
    ///
    /// buf.read_slice(&mut dst);
    /// assert_eq!(b"hello", dst);
    /// assert_eq!(6, buf.remaining());
    /// ```
    fn read_slice(&mut self, dst: &mut [u8]) -> usize {
        let mut off = 0;
        let len = cmp::min(dst.len(), self.remaining());

        while off < len {
            let mut cnt;

            unsafe {
                let src = self.bytes();
                cnt = cmp::min(src.len(), len - off);

                ptr::copy_nonoverlapping_memory(
                    dst[off..].as_mut_ptr(), src.as_ptr(), cnt);

                off += src.len();
            }

            self.advance(cnt);
        }

        len
    }

    /// Read a single byte from the `Buf`
    fn read_byte(&mut self) -> Option<u8> {
        let mut dst = [0];

        if self.read_slice(&mut dst) == 0 {
            return None;
        }

        Some(dst[0])
    }
}

/// An extension trait providing extra functions applicable to all `Buf` values.
pub trait BufExt {

    /// Read bytes from this Buf into the given sink and advance the cursor by
    /// the number of bytes read.
    fn read<S: Sink>(&mut self, dst: S) -> Result<usize, S::Error>;
}

/// A trait for values that provide sequential write access to bytes.
pub trait MutBuf : Sized {

    /// Returns the number of bytes that can be accessed from the Buf
    fn remaining(&self) -> usize;

    /// Advance the internal cursor of the Buf
    fn advance(&mut self, cnt: usize);

    /// Returns true if there are any more bytes to consume
    fn has_remaining(&self) -> bool {
        self.remaining() > 0
    }

    /// Returns a mutable slice starting at the current Buf position and of
    /// length between 0 and `Buf::remaining()`.
    fn mut_bytes<'a>(&'a mut self) -> &'a mut [u8];

    /// Read bytes from this Buf into the given slice and advance the cursor by
    /// the number of bytes read.
    ///
    /// If there are fewer bytes remaining than is needed to satisfy the
    /// request (aka `dst.len()` > self.remaining()`), then
    /// `Err(BufError::Overflow)` is returned.
    ///
    /// ```
    /// use bytes::{MutSliceBuf, Buf, MutBuf};
    ///
    /// let mut dst = [0; 6];
    ///
    /// {
    ///     let mut buf = MutSliceBuf::wrap(&mut dst);
    ///     buf.write_slice(b"hello");
    ///
    ///     assert_eq!(1, buf.remaining());
    /// }
    ///
    /// assert_eq!(b"hello\0", dst);
    /// ```
    fn write_slice(&mut self, src: &[u8]) -> usize {
        let mut off = 0;
        let len = cmp::min(src.len(), self.remaining());

        while off < len {
            let mut cnt;

            unsafe {
                let dst = self.mut_bytes();
                cnt = cmp::min(dst.len(), len - off);

                ptr::copy_nonoverlapping_memory(
                    dst.as_mut_ptr(), src[off..].as_ptr(), cnt);

                off += cnt;
            }

            self.advance(cnt);
        }

        len
    }

    /// Write a single byte to the `MuBuf`
    fn write_byte(&mut self, byte: u8) -> bool {
        let src = [byte];

        if self.write_slice(&src) == 0 {
            return false;
        }

        true
    }
}

/// An extension trait providing extra functions applicable to all `MutBuf` values.
pub trait MutBufExt {

    /// Write bytes from the given source into the current `MutBuf` and advance
    /// the cursor by the number of bytes written.
    fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error>;
}

/*
 *
 * ===== ByteStr =====
 *
 */

/// An immutable sequence of bytes. Operations will not mutate the original
/// value. Since only immutable access is permitted, operations do not require
/// copying (though, sometimes copying will happen as an optimization).
pub trait ByteStr : Clone + Sized + Send + Sync + ops::Index<usize, Output=u8> {

    // Until HKT lands, the buf must be bound by 'static
    type Buf: Buf+'static;

    /// Returns a read-only `Buf` for accessing the byte contents of the
    /// `ByteStr`.
    fn buf(&self) -> Self::Buf;

    /// Returns a new `Bytes` value representing the concatenation of `self`
    /// with the given `Bytes`.
    fn concat<B: ByteStr+'static>(&self, other: B) -> Bytes;

    /// Returns the number of bytes in the ByteStr
    fn len(&self) -> usize;

    /// Returns true if the length of the `ByteStr` is 0
    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns a new ByteStr value containing the byte range between `begin`
    /// (inclusive) and `end` (exclusive)
    fn slice(&self, begin: usize, end: usize) -> Bytes;

    /// Returns a new ByteStr value containing the byte range starting from
    /// `begin` (inclusive) to the end of the byte str.
    ///
    /// Equivalent to `bytes.slice(begin, bytes.len())`
    fn slice_from(&self, begin: usize) -> Bytes {
        self.slice(begin, self.len())
    }

    /// Returns a new ByteStr value containing the byte range from the start up
    /// to `end` (exclusive).
    ///
    /// Equivalent to `bytes.slice(0, end)`
    fn slice_to(&self, end: usize) -> Bytes {
        self.slice(0, end)
    }

    /// Divides the value into two `Bytes` at the given index.
    ///
    /// The first will contain all bytes from `[0, mid]` (excluding the index
    /// `mid` itself) and the second will contain all indices from `[mid, len)`
    /// (excluding the index `len` itself).
    ///
    /// Panics if `mid > len`.
    fn split_at(&self, mid: usize) -> (Bytes, Bytes) {
        (self.slice_to(mid), self.slice_from(mid))
    }

    /// Consumes the value and returns a `Bytes` instance containing
    /// identical bytes
    fn to_bytes(self) -> Bytes;
}

/*
 *
 * ===== *Ext impls =====
 *
 */

impl<B: Buf> BufExt for B {
    fn read<S: Sink>(&mut self, dst: S) -> Result<usize, S::Error> {
        dst.sink(self)
    }
}

impl<B: MutBuf> MutBufExt for B {
    fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error> {
        src.fill(self)
    }
}

/*
 *
 * ===== Sink / Source =====
 *
 */

/// A value that reads bytes from a Buf into itself
pub trait Sink {
    type Error;

    fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, Self::Error>;
}

/// A value that writes bytes from itself into a `MutBuf`.
pub trait Source {
    type Error;

    fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, Self::Error>;
}

impl<'a> Sink for &'a mut [u8] {
    type Error = BufError;

    fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, BufError> {
        Ok(buf.read_slice(self))
    }
}

impl<'a> Sink for &'a mut Vec<u8> {
    type Error = BufError;

    fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, BufError> {
        use std::slice;

        let rem = buf.remaining();
        let cap = self.capacity();
        let len = rem - cap;

        // Ensure that the vec is big enough
        if cap < rem {
            self.reserve(len);
        }

        unsafe {
            {
                let dst = self.as_mut_slice();
                buf.read_slice(slice::from_raw_parts_mut(dst.as_mut_ptr(), rem));
            }

            self.set_len(rem);
        }

        Ok(len)
    }
}

impl<'a> Source for &'a [u8] {
    type Error = BufError;

    fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, BufError> {
        Ok(buf.write_slice(self))
    }
}

impl<'a> Source for &'a Vec<u8> {
    type Error = BufError;

    fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, BufError> {
        Ok(buf.write_slice(self.as_slice()))
    }
}

impl<'a> Source for &'a Bytes {
    type Error = BufError;

    fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, BufError> {
        unimplemented!();
    }
}

impl<'a> Source for &'a mut (io::Read+'a) {
    type Error = io::Error;

    fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, io::Error> {
        unimplemented!();
    }
}

impl<'a> Source for &'a mut (Iterator<Item=u8>+'a) {
    type Error = BufError;

    fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, BufError> {
        unimplemented!();
    }
}

/*
 *
 * ===== Buf impls =====
 *
 */

impl Buf for Box<Buf+'static> {
    fn remaining(&self) -> usize {
        (**self).remaining()
    }

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

    fn advance(&mut self, cnt: usize) {
        (**self).advance(cnt);
    }

    fn read_slice(&mut self, dst: &mut [u8]) -> usize {
        (**self).read_slice(dst)
    }
}

/*
 *
 * ===== BufError  =====
 *
 */

#[derive(Copy, Debug)]
pub enum BufError {
    Underflow,
    Overflow,
}
<commit_msg>Implement Read / Write for Buf types<commit_after>#![crate_name = "bytes"]
#![unstable]

#![feature(alloc, core, io, unsafe_no_drop_flag)]

pub use byte_buf::{ByteBuf, ROByteBuf, MutByteBuf};
pub use byte_str::{SeqByteStr, SmallByteStr, SmallByteStrBuf};
pub use bytes::Bytes;
pub use ring::{RingBuf, RingBufReader, RingBufWriter};
pub use rope::{Rope, RopeBuf};
pub use slice::{SliceBuf, MutSliceBuf};

use std::{cmp, fmt, io, ops, ptr, u32};

extern crate core;

mod alloc;
mod byte_buf;
mod byte_str;
mod bytes;
mod ring;
mod rope;
mod slice;

pub mod traits {
    //! All traits are re-exported here to allow glob imports.
    pub use {Buf, BufExt, MutBuf, MutBufExt, ByteStr};
}

const MAX_CAPACITY: usize = u32::MAX as usize;

/// A trait for values that provide sequential read access to bytes.
pub trait Buf {

    /// Returns the number of bytes that can be accessed from the Buf
    fn remaining(&self) -> usize;

    /// Returns a slice starting at the current Buf position and of length
    /// between 0 and `Buf::remaining()`.
    fn bytes<'a>(&'a self) -> &'a [u8];

    /// Advance the internal cursor of the Buf
    fn advance(&mut self, cnt: usize);

    /// Returns true if there are any more bytes to consume
    fn has_remaining(&self) -> bool {
        self.remaining() > 0
    }

    /// Read bytes from the `Buf` into the given slice and advance the cursor by
    /// the number of bytes read.
    ///
    /// If there are fewer bytes remaining than is needed to satisfy the
    /// request (aka `dst.len()` > self.remaining()`), then
    /// `Err(BufError::Overflow)` is returned.
    ///
    /// ```
    /// use bytes::{SliceBuf, Buf};
    ///
    /// let mut buf = SliceBuf::wrap(b"hello world");
    /// let mut dst = [0; 5];
    ///
    /// buf.read_slice(&mut dst);
    /// assert_eq!(b"hello", dst);
    /// assert_eq!(6, buf.remaining());
    /// ```
    fn read_slice(&mut self, dst: &mut [u8]) -> usize {
        let mut off = 0;
        let len = cmp::min(dst.len(), self.remaining());

        while off < len {
            let mut cnt;

            unsafe {
                let src = self.bytes();
                cnt = cmp::min(src.len(), len - off);

                ptr::copy_nonoverlapping_memory(
                    dst[off..].as_mut_ptr(), src.as_ptr(), cnt);

                off += src.len();
            }

            self.advance(cnt);
        }

        len
    }

    /// Read a single byte from the `Buf`
    fn read_byte(&mut self) -> Option<u8> {
        let mut dst = [0];

        if self.read_slice(&mut dst) == 0 {
            return None;
        }

        Some(dst[0])
    }
}

/// An extension trait providing extra functions applicable to all `Buf` values.
pub trait BufExt {

    /// Read bytes from this Buf into the given sink and advance the cursor by
    /// the number of bytes read.
    fn read<S: Sink>(&mut self, dst: S) -> Result<usize, S::Error>;
}

/// A trait for values that provide sequential write access to bytes.
pub trait MutBuf : Sized {

    /// Returns the number of bytes that can be accessed from the Buf
    fn remaining(&self) -> usize;

    /// Advance the internal cursor of the Buf
    fn advance(&mut self, cnt: usize);

    /// Returns true if there are any more bytes to consume
    fn has_remaining(&self) -> bool {
        self.remaining() > 0
    }

    /// Returns a mutable slice starting at the current Buf position and of
    /// length between 0 and `Buf::remaining()`.
    fn mut_bytes<'a>(&'a mut self) -> &'a mut [u8];

    /// Read bytes from this Buf into the given slice and advance the cursor by
    /// the number of bytes read.
    ///
    /// If there are fewer bytes remaining than is needed to satisfy the
    /// request (aka `dst.len()` > self.remaining()`), then
    /// `Err(BufError::Overflow)` is returned.
    ///
    /// ```
    /// use bytes::{MutSliceBuf, Buf, MutBuf};
    ///
    /// let mut dst = [0; 6];
    ///
    /// {
    ///     let mut buf = MutSliceBuf::wrap(&mut dst);
    ///     buf.write_slice(b"hello");
    ///
    ///     assert_eq!(1, buf.remaining());
    /// }
    ///
    /// assert_eq!(b"hello\0", dst);
    /// ```
    fn write_slice(&mut self, src: &[u8]) -> usize {
        let mut off = 0;
        let len = cmp::min(src.len(), self.remaining());

        while off < len {
            let mut cnt;

            unsafe {
                let dst = self.mut_bytes();
                cnt = cmp::min(dst.len(), len - off);

                ptr::copy_nonoverlapping_memory(
                    dst.as_mut_ptr(), src[off..].as_ptr(), cnt);

                off += cnt;
            }

            self.advance(cnt);
        }

        len
    }

    /// Write a single byte to the `MuBuf`
    fn write_byte(&mut self, byte: u8) -> bool {
        let src = [byte];

        if self.write_slice(&src) == 0 {
            return false;
        }

        true
    }
}

/// An extension trait providing extra functions applicable to all `MutBuf` values.
pub trait MutBufExt {

    /// Write bytes from the given source into the current `MutBuf` and advance
    /// the cursor by the number of bytes written.
    fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error>;
}

/*
 *
 * ===== ByteStr =====
 *
 */

/// An immutable sequence of bytes. Operations will not mutate the original
/// value. Since only immutable access is permitted, operations do not require
/// copying (though, sometimes copying will happen as an optimization).
pub trait ByteStr : Clone + Sized + Send + Sync + ops::Index<usize, Output=u8> {

    // Until HKT lands, the buf must be bound by 'static
    type Buf: Buf+'static;

    /// Returns a read-only `Buf` for accessing the byte contents of the
    /// `ByteStr`.
    fn buf(&self) -> Self::Buf;

    /// Returns a new `Bytes` value representing the concatenation of `self`
    /// with the given `Bytes`.
    fn concat<B: ByteStr+'static>(&self, other: B) -> Bytes;

    /// Returns the number of bytes in the ByteStr
    fn len(&self) -> usize;

    /// Returns true if the length of the `ByteStr` is 0
    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns a new ByteStr value containing the byte range between `begin`
    /// (inclusive) and `end` (exclusive)
    fn slice(&self, begin: usize, end: usize) -> Bytes;

    /// Returns a new ByteStr value containing the byte range starting from
    /// `begin` (inclusive) to the end of the byte str.
    ///
    /// Equivalent to `bytes.slice(begin, bytes.len())`
    fn slice_from(&self, begin: usize) -> Bytes {
        self.slice(begin, self.len())
    }

    /// Returns a new ByteStr value containing the byte range from the start up
    /// to `end` (exclusive).
    ///
    /// Equivalent to `bytes.slice(0, end)`
    fn slice_to(&self, end: usize) -> Bytes {
        self.slice(0, end)
    }

    /// Divides the value into two `Bytes` at the given index.
    ///
    /// The first will contain all bytes from `[0, mid]` (excluding the index
    /// `mid` itself) and the second will contain all indices from `[mid, len)`
    /// (excluding the index `len` itself).
    ///
    /// Panics if `mid > len`.
    fn split_at(&self, mid: usize) -> (Bytes, Bytes) {
        (self.slice_to(mid), self.slice_from(mid))
    }

    /// Consumes the value and returns a `Bytes` instance containing
    /// identical bytes
    fn to_bytes(self) -> Bytes;
}

/*
 *
 * ===== *Ext impls =====
 *
 */

impl<B: Buf> BufExt for B {
    fn read<S: Sink>(&mut self, dst: S) -> Result<usize, S::Error> {
        dst.sink(self)
    }
}

impl<B: MutBuf> MutBufExt for B {
    fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error> {
        src.fill(self)
    }
}

/*
 *
 * ===== Sink / Source =====
 *
 */

/// A value that reads bytes from a Buf into itself
pub trait Sink {
    type Error;

    fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, Self::Error>;
}

/// A value that writes bytes from itself into a `MutBuf`.
pub trait Source {
    type Error;

    fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, Self::Error>;
}

impl<'a> Sink for &'a mut [u8] {
    type Error = BufError;

    fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, BufError> {
        Ok(buf.read_slice(self))
    }
}

impl<'a> Sink for &'a mut Vec<u8> {
    type Error = BufError;

    fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, BufError> {
        use std::slice;

        let rem = buf.remaining();
        let cap = self.capacity();
        let len = rem - cap;

        // Ensure that the vec is big enough
        if cap < rem {
            self.reserve(len);
        }

        unsafe {
            {
                let dst = self.as_mut_slice();
                buf.read_slice(slice::from_raw_parts_mut(dst.as_mut_ptr(), rem));
            }

            self.set_len(rem);
        }

        Ok(len)
    }
}

impl<'a> Source for &'a [u8] {
    type Error = BufError;

    fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, BufError> {
        Ok(buf.write_slice(self))
    }
}

impl<'a> Source for &'a Vec<u8> {
    type Error = BufError;

    fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, BufError> {
        Ok(buf.write_slice(self.as_slice()))
    }
}

impl<'a> Source for &'a Bytes {
    type Error = BufError;

    fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, BufError> {
        unimplemented!();
    }
}

impl<'a> Source for &'a mut (io::Read+'a) {
    type Error = io::Error;

    fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, io::Error> {
        unimplemented!();
    }
}

impl<'a> Source for &'a mut (Iterator<Item=u8>+'a) {
    type Error = BufError;

    fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, BufError> {
        unimplemented!();
    }
}

/*
 *
 * ===== Buf impls =====
 *
 */

impl Buf for Box<Buf+'static> {
    fn remaining(&self) -> usize {
        (**self).remaining()
    }

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

    fn advance(&mut self, cnt: usize) {
        (**self).advance(cnt);
    }

    fn read_slice(&mut self, dst: &mut [u8]) -> usize {
        (**self).read_slice(dst)
    }
}

impl fmt::Debug for Box<Buf+'static> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "Box<Buf> {{ remaining: {} }}", self.remaining())
    }
}

/*
 *
 * ===== Read impls =====
 *
 */

macro_rules! impl_read {
    ($ty:ty) => {
        impl io::Read for $ty {
            fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
                if !self.has_remaining() {
                    return Ok(0);
                }

                Ok(self.read_slice(buf))
            }
        }
    }
}

impl_read!(ByteBuf);
impl_read!(ROByteBuf);
impl_read!(RopeBuf);
impl_read!(Box<Buf+'static>);

macro_rules! impl_write {
    ($ty:ty) => {
        impl io::Write for $ty {
            fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
                if !self.has_remaining() {
                    return Ok(0);
                }

                Ok(self.write_slice(buf))
            }

            fn flush(&mut self) -> io::Result<()> {
                Ok(())
            }
        }
    }
}

impl_write!(MutByteBuf);

/*
 *
 * ===== BufError  =====
 *
 */

#[derive(Copy, Debug)]
pub enum BufError {
    Underflow,
    Overflow,
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate rustc_serialize;

/// Width of game board
#[cfg(not(test))] pub const WIDTH: usize = 8;
#[cfg(test)]      pub const WIDTH: usize = 3;
/// Height of game board
#[cfg(not(test))] pub const HEIGHT: usize = 8;
#[cfg(test)]      pub const HEIGHT: usize = 3;
/// Number of rows
#[cfg(not(test))] pub const ROWS: usize = 2;
#[cfg(test)]      pub const ROWS: usize = 1;

const RED: Player = Player::Red;
const BLUE: Player = Player::Blue;

const ROCK: RPS = RPS::Rock;
const PAPER: RPS = RPS::Paper;
const SCISSORS: RPS = RPS::Scissors;

const WIN: Outcome = Outcome::Win;
const LOSE: Outcome = Outcome::Lose;
const DRAW: Outcome = Outcome::Draw;

use std::marker::PhantomData;

use moves::{is_valid, Move};
use win_conditions::{WinCondition};
use field::{Field, PovField};
use unit::{Unit, GeneralUnit};

pub mod moves;
pub mod win_conditions;
pub mod unit;
pub mod field;

#[derive(Clone, Debug)]
pub struct Game<T: WinCondition<GeneralUnit>> {
    turns: u32,
    current_turn: Player,
    winner: Option<Player>,
    field: Field<GeneralUnit>,
    rules: Rules<GeneralUnit, T>,
}

impl<T: WinCondition<GeneralUnit>> Game<T> {
    pub fn new(rules: Rules<GeneralUnit, T>) -> Game<T> {
        let mut rows = [[None; WIDTH]; HEIGHT];
        for i in 0..ROWS {
            rows[i] = [Some(RED.random_unit()); WIDTH];
            rows[HEIGHT - i - 1] = [Some(BLUE.random_unit()); WIDTH];
        }
        let field = Field { rows: rows };
        Game {
            turns: 1,
            current_turn: RED,
            winner: None,
            field: field,
            rules: rules,
        }
    }

    pub fn turns(&self) -> u32 { self.turns }
    pub fn current_turn(&self) -> Player { self.current_turn }
    pub fn winner(&self) -> Option<Player> { self.winner }
    pub fn field(&self) -> &Field<GeneralUnit> { &self.field }

    pub fn force_win(&mut self, player: Player) {
        if !self.winner.is_some() { self.winner = Some(player); }
    }

    pub fn perspective(&self, player: Player) -> PovField {
        PovField::from((&self.field, player))
    }

    pub fn make_move(&mut self, movement: Move) -> Result<Option<Outcome>, MoveError> {
        if self.winner.is_some() { return Err(MoveError::GameAlreadyFinished); }

        if !is_valid(movement) {
            return Err(MoveError::DeclinedByMoveCondition);
        }

        let (from_x, from_y) = movement.from;

        if from_x >= WIDTH || from_y >= HEIGHT { return Err(MoveError::PositionOutOfBounds); }

        let attack_outcome;
        let (to_x, to_y);

        if let Some(ref unit) = self.field.rows[from_y][from_x].as_ref() {
            if unit.owner != self.current_turn { return Err(MoveError::WrongOwner); }
            let dist = movement.apply(unit.owner);
            to_x = dist.0;
            to_y = dist.1;
            if to_x >= WIDTH || to_y >= HEIGHT { return Err(MoveError::PositionOutOfBounds); }

            if let Some(ref defender) = self.field.rows[to_y][to_x].as_ref() {
                if defender.owner == self.current_turn { return Err(MoveError::SameOwner); }

                match unit.attack(defender) {
                    Some(res) => {
                        attack_outcome = Some(res);
                    },
                    None => { return Err(MoveError::UnexpextedError); }
                }
            } else {
                attack_outcome = None;
            }

        } else {
            return Err(MoveError::NoUnitInPosition);
        }

        if let Some(outcome) = attack_outcome {
            match outcome {
                WIN => {
                    self.field.rows[to_y][to_x] = self.field.rows[from_y][from_x];
                    self.field.rows[from_y][from_x] = None;
                    self.field.rows[to_y][to_x].as_mut().unwrap().visible = true;
                },
                LOSE => {
                    self.field.rows[from_y][from_x] = None;
                    self.field.rows[to_y][to_x].as_mut().unwrap().visible = true;
                },
                DRAW => {
                    let v1 = self.field.rows[from_y][from_x].as_mut().unwrap().visible;
                    let v2 = self.field.rows[to_y][to_x].as_mut().unwrap().visible;

                    if v1 && v2{
                        self.field.rows[from_y][from_x].as_mut().unwrap().rps = RPS::random();
                        self.field.rows[to_y][to_x].as_mut().unwrap().rps = RPS::random();
                    } else {
                        self.field.rows[from_y][from_x].as_mut().unwrap().visible = true;
                        self.field.rows[to_y][to_x].as_mut().unwrap().visible = true;
                    }
                }
            }
        } else {
            self.field.rows[to_y][to_x] = self.field.rows[from_y][from_x];
            self.field.rows[from_y][from_x] = None;
        }

        self.winner = self.rules.win_condition.winner(&self.field);
        self.turns += 1;
        self.current_turn = self.current_turn.next();

        Ok(attack_outcome)
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MoveError {
    GameAlreadyFinished,
    DeclinedByMoveCondition,
    PositionOutOfBounds,
    WrongOwner,
    NoUnitInPosition,
    SameOwner,
    UnexpextedError,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum Player {
    Red,
    Blue,
}

impl Player {
    fn next(&self) -> Player {
        match *self {
            RED => BLUE,
            BLUE => RED,
        }
    }

    fn unit(&self, rps: RPS) -> GeneralUnit {
        GeneralUnit::new(rps, *self)
    }

    fn random_unit(&self) -> GeneralUnit {
        self.unit(RPS::random())
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum RPS {
    Rock,
    Paper,
    Scissors,
}

impl RPS {
    fn attack(&self, opponent: RPS) -> Outcome {
        match (*self, opponent) {
            (PAPER, ROCK) | (ROCK, SCISSORS) | (SCISSORS, PAPER) => WIN,
            (ROCK, PAPER) | (SCISSORS, ROCK) | (PAPER, SCISSORS) => LOSE,
            _ => DRAW,
        }
    }

    fn random() -> RPS {
        match rand::random::<usize>() % 3 {
            0 => ROCK,
            1 => PAPER,
            2 => SCISSORS,
            _ => { panic!("rand::random::<usize>() % 3 returned not 0, nor 1, nor 2"); }
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Outcome {
    Win,
    Lose,
    Draw,
}

#[derive(Clone, Debug)]
pub struct Rules<K, T: WinCondition<K>> where K: Unit {
    pub win_condition: T,
    phantom_data: PhantomData<K>,
}

impl<K: Unit, T: WinCondition<K>> Rules<K, T> {
    pub fn new(win_condition: T) -> Rules<K, T> {
        Rules {
            win_condition: win_condition,
            phantom_data: PhantomData,
        }
    }
}

#[test]
fn basic_test() {
    use moves::{Direction};
    use win_conditions::EliminateCondition;

    let rules = Rules::new(EliminateCondition);
    let mut game = Game::new(rules);
    let move1 = Move::new(0, 0, Direction::Forward);

    assert_eq!(game.make_move(move1), Ok(None));

    assert_eq!(game.make_move(move1), Err(MoveError::NoUnitInPosition));

    let move2 = Move::new(0, 2, Direction::Forward);
    assert!(game.make_move(move2).unwrap().is_some());
}
<commit_msg>Impl rand::Rand for RPS enum<commit_after>extern crate rand;
extern crate rustc_serialize;

/// Width of game board
#[cfg(not(test))] pub const WIDTH: usize = 8;
#[cfg(test)]      pub const WIDTH: usize = 3;
/// Height of game board
#[cfg(not(test))] pub const HEIGHT: usize = 8;
#[cfg(test)]      pub const HEIGHT: usize = 3;
/// Number of rows
#[cfg(not(test))] pub const ROWS: usize = 2;
#[cfg(test)]      pub const ROWS: usize = 1;

const RED: Player = Player::Red;
const BLUE: Player = Player::Blue;

const ROCK: RPS = RPS::Rock;
const PAPER: RPS = RPS::Paper;
const SCISSORS: RPS = RPS::Scissors;

const WIN: Outcome = Outcome::Win;
const LOSE: Outcome = Outcome::Lose;
const DRAW: Outcome = Outcome::Draw;

use rand::{Rng, Rand};

use std::marker::PhantomData;

use moves::{is_valid, Move};
use win_conditions::{WinCondition};
use field::{Field, PovField};
use unit::{Unit, GeneralUnit};

pub mod moves;
pub mod win_conditions;
pub mod unit;
pub mod field;

#[derive(Clone, Debug)]
pub struct Game<T: WinCondition<GeneralUnit>> {
    turns: u32,
    current_turn: Player,
    winner: Option<Player>,
    field: Field<GeneralUnit>,
    rules: Rules<GeneralUnit, T>,
}

impl<T: WinCondition<GeneralUnit>> Game<T> {
    pub fn new(rules: Rules<GeneralUnit, T>) -> Game<T> {
        let mut rows = [[None; WIDTH]; HEIGHT];
        for i in 0..ROWS {
            rows[i] = [Some(RED.random_unit()); WIDTH];
            rows[HEIGHT - i - 1] = [Some(BLUE.random_unit()); WIDTH];
        }
        let field = Field { rows: rows };
        Game {
            turns: 1,
            current_turn: RED,
            winner: None,
            field: field,
            rules: rules,
        }
    }

    pub fn turns(&self) -> u32 { self.turns }
    pub fn current_turn(&self) -> Player { self.current_turn }
    pub fn winner(&self) -> Option<Player> { self.winner }
    pub fn field(&self) -> &Field<GeneralUnit> { &self.field }

    pub fn force_win(&mut self, player: Player) {
        if !self.winner.is_some() { self.winner = Some(player); }
    }

    pub fn perspective(&self, player: Player) -> PovField {
        PovField::from((&self.field, player))
    }

    pub fn make_move(&mut self, movement: Move) -> Result<Option<Outcome>, MoveError> {
        if self.winner.is_some() { return Err(MoveError::GameAlreadyFinished); }

        if !is_valid(movement) {
            return Err(MoveError::DeclinedByMoveCondition);
        }

        let (from_x, from_y) = movement.from;

        if from_x >= WIDTH || from_y >= HEIGHT { return Err(MoveError::PositionOutOfBounds); }

        let attack_outcome;
        let (to_x, to_y);

        if let Some(ref unit) = self.field.rows[from_y][from_x].as_ref() {
            if unit.owner != self.current_turn { return Err(MoveError::WrongOwner); }
            let dist = movement.apply(unit.owner);
            to_x = dist.0;
            to_y = dist.1;
            if to_x >= WIDTH || to_y >= HEIGHT { return Err(MoveError::PositionOutOfBounds); }

            if let Some(ref defender) = self.field.rows[to_y][to_x].as_ref() {
                if defender.owner == self.current_turn { return Err(MoveError::SameOwner); }

                match unit.attack(defender) {
                    Some(res) => {
                        attack_outcome = Some(res);
                    },
                    None => { return Err(MoveError::UnexpextedError); }
                }
            } else {
                attack_outcome = None;
            }

        } else {
            return Err(MoveError::NoUnitInPosition);
        }

        if let Some(outcome) = attack_outcome {
            match outcome {
                WIN => {
                    self.field.rows[to_y][to_x] = self.field.rows[from_y][from_x];
                    self.field.rows[from_y][from_x] = None;
                    self.field.rows[to_y][to_x].as_mut().unwrap().visible = true;
                },
                LOSE => {
                    self.field.rows[from_y][from_x] = None;
                    self.field.rows[to_y][to_x].as_mut().unwrap().visible = true;
                },
                DRAW => {
                    let v1 = self.field.rows[from_y][from_x].as_mut().unwrap().visible;
                    let v2 = self.field.rows[to_y][to_x].as_mut().unwrap().visible;

                    if v1 && v2{
                        self.field.rows[from_y][from_x].as_mut().unwrap().rps = RPS::random();
                        self.field.rows[to_y][to_x].as_mut().unwrap().rps = RPS::random();
                    } else {
                        self.field.rows[from_y][from_x].as_mut().unwrap().visible = true;
                        self.field.rows[to_y][to_x].as_mut().unwrap().visible = true;
                    }
                }
            }
        } else {
            self.field.rows[to_y][to_x] = self.field.rows[from_y][from_x];
            self.field.rows[from_y][from_x] = None;
        }

        self.winner = self.rules.win_condition.winner(&self.field);
        self.turns += 1;
        self.current_turn = self.current_turn.next();

        Ok(attack_outcome)
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MoveError {
    GameAlreadyFinished,
    DeclinedByMoveCondition,
    PositionOutOfBounds,
    WrongOwner,
    NoUnitInPosition,
    SameOwner,
    UnexpextedError,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum Player {
    Red,
    Blue,
}

impl Player {
    fn next(&self) -> Player {
        match *self {
            RED => BLUE,
            BLUE => RED,
        }
    }

    fn unit(&self, rps: RPS) -> GeneralUnit {
        GeneralUnit::new(rps, *self)
    }

    fn random_unit(&self) -> GeneralUnit {
        self.unit(RPS::random())
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum RPS {
    Rock,
    Paper,
    Scissors,
}

impl RPS {
    fn attack(&self, opponent: RPS) -> Outcome {
        match (*self, opponent) {
            (PAPER, ROCK) | (ROCK, SCISSORS) | (SCISSORS, PAPER) => WIN,
            (ROCK, PAPER) | (SCISSORS, ROCK) | (PAPER, SCISSORS) => LOSE,
            _ => DRAW,
        }
    }

    fn random() -> RPS {
        match rand::random::<usize>() % 3 {
            0 => ROCK,
            1 => PAPER,
            2 => SCISSORS,
            _ => { panic!("rand::random::<usize>() % 3 returned not 0, nor 1, nor 2"); }
        }
    }
}

impl Rand for RPS {
    fn rand<R: Rng>(rng: &mut R) -> Self {
        match rng.next_u32() % 3 {
            0 => ROCK,
            1 => PAPER,
            2 => SCISSORS,
            _ => { unreachable!(); }
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Outcome {
    Win,
    Lose,
    Draw,
}

#[derive(Clone, Debug)]
pub struct Rules<K, T: WinCondition<K>> where K: Unit {
    pub win_condition: T,
    phantom_data: PhantomData<K>,
}

impl<K: Unit, T: WinCondition<K>> Rules<K, T> {
    pub fn new(win_condition: T) -> Rules<K, T> {
        Rules {
            win_condition: win_condition,
            phantom_data: PhantomData,
        }
    }
}

#[test]
fn basic_test() {
    use moves::{Direction};
    use win_conditions::EliminateCondition;

    let rules = Rules::new(EliminateCondition);
    let mut game = Game::new(rules);
    let move1 = Move::new(0, 0, Direction::Forward);

    assert_eq!(game.make_move(move1), Ok(None));

    assert_eq!(game.make_move(move1), Err(MoveError::NoUnitInPosition));

    let move2 = Move::new(0, 2, Direction::Forward);
    assert!(game.make_move(move2).unwrap().is_some());
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![cfg_attr(feature = "unstable", feature(scoped))]

//! A stable version of `std::thread::scoped`
//!
//! ## Warning
//!
//! This is inherently unsafe if the `JoinGuard` is allowed to leak without being dropped.
//! See #24292 for more details.

use std::marker::PhantomData;
use std::thread::{spawn, JoinHandle, Thread};
use std::mem::{transmute, forget};

/// A RAII guard for that joins a scoped thread upon drop
///
/// # Panics
///
/// `JoinGuard` will panic on join or drop if its owned thread panics
#[must_use = "thread will be immediately joined if `JoinGuard` is not used"]
pub struct JoinGuard<'a, T: Send + 'a> {
    inner: Option<JoinHandle<BoxedThing>>,
    _marker: PhantomData<&'a T>,
}

unsafe impl<'a, T: Send + 'a> Sync for JoinGuard<'a, T> {}

impl<'a, T: Send + 'a> JoinGuard<'a, T> {
    /// Provides the backing `Thread` object
    pub fn thread(&self) -> &Thread {
        &self.inner.as_ref().unwrap().thread()
    }

    /// Joins the guarded thread and returns its result
    ///
    /// # Panics
    ///
    /// `join()` will panic if the owned thread panics
    pub fn join(mut self) -> T {
        match self.inner.take().unwrap().join() {
            Ok(res) => unsafe { *res.into_inner() },
            Err(_) => panic!("child thread {:?} panicked", self.thread()),
        }
    }
}

/// Detaches a child thread from its guard
pub trait ScopedDetach {
    /// Detaches a child thread from its guard
    ///
    /// Note: Only valid for the 'static lifetime
    fn detach(self);
}

impl<T: Send + 'static> ScopedDetach for JoinGuard<'static, T> {
    fn detach(mut self) {
        let _ = self.inner.take();
    }
}

#[cfg(feature = "unstable")]
impl<T: Send + 'static> ScopedDetach for ::std::thread::JoinGuard<'static, T> {
    fn detach(self) {
        use std::mem::forget;

        forget(self);
    }
}

impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> {
    fn drop(&mut self) {
        self.inner.take().map(|v| if v.join().is_err() {
            panic!("child thread {:?} panicked", self.thread());
        });
    }
}

/// Spawns a new scoped thread
pub unsafe fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where
    T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
{
    let f = BoxedThing::new(f);

    JoinGuard {
        inner: Some(spawn(move ||
            BoxedThing::new(f.into_inner::<F>()())
        )),
        _marker: PhantomData,
    }
}

struct BoxedThing(usize);
impl BoxedThing {
    fn new<T>(v: T) -> Self {
        let mut b = Box::new(v);
        let b_ptr = &mut *b as *mut _ as usize;
        forget(b);
        BoxedThing(b_ptr)
    }

    unsafe fn into_inner<T>(self) -> Box<T> {
        transmute(self.0 as *mut T)
    }
}

#[cfg(test)]
mod tests {
    use std::thread::sleep_ms;
    use super::scoped;

    #[test]
    fn test_scoped_stack() {
        unsafe {
            let mut a = 5;
            scoped(|| {
                sleep_ms(50);
                a = 2;
            }).join();
            assert_eq!(a, 2);
        }
    }

    #[test]
    fn test_join_success() {
        unsafe {
            assert!(scoped(move|| -> String {
                "Success!".to_string()
            }).join() == "Success!");
        }
    }

    #[test]
    fn test_scoped_success() {
        unsafe {
            let res = scoped(move|| -> String {
                "Success!".to_string()
            }).join();
            assert!(res == "Success!");
        }
    }

    #[test]
    #[should_panic]
    fn test_scoped_panic() {
        unsafe {
            scoped(|| panic!()).join();
        }
    }

    #[test]
    #[should_panic]
    fn test_scoped_implicit_panic() {
        unsafe {
            let _ = scoped(|| panic!());
        }
    }
}
<commit_msg>Fix link to Github issue<commit_after>#![deny(missing_docs)]
#![cfg_attr(feature = "unstable", feature(scoped))]

//! A stable version of `std::thread::scoped`
//!
//! ## Warning
//!
//! This is inherently unsafe if the `JoinGuard` is allowed to leak without being dropped.
//! See [rust-lang/rust#24292](https://github.com/rust-lang/rust/issues/24292) for more details.

use std::marker::PhantomData;
use std::thread::{spawn, JoinHandle, Thread};
use std::mem::{transmute, forget};

/// A RAII guard for that joins a scoped thread upon drop
///
/// # Panics
///
/// `JoinGuard` will panic on join or drop if its owned thread panics
#[must_use = "thread will be immediately joined if `JoinGuard` is not used"]
pub struct JoinGuard<'a, T: Send + 'a> {
    inner: Option<JoinHandle<BoxedThing>>,
    _marker: PhantomData<&'a T>,
}

unsafe impl<'a, T: Send + 'a> Sync for JoinGuard<'a, T> {}

impl<'a, T: Send + 'a> JoinGuard<'a, T> {
    /// Provides the backing `Thread` object
    pub fn thread(&self) -> &Thread {
        &self.inner.as_ref().unwrap().thread()
    }

    /// Joins the guarded thread and returns its result
    ///
    /// # Panics
    ///
    /// `join()` will panic if the owned thread panics
    pub fn join(mut self) -> T {
        match self.inner.take().unwrap().join() {
            Ok(res) => unsafe { *res.into_inner() },
            Err(_) => panic!("child thread {:?} panicked", self.thread()),
        }
    }
}

/// Detaches a child thread from its guard
pub trait ScopedDetach {
    /// Detaches a child thread from its guard
    ///
    /// Note: Only valid for the 'static lifetime
    fn detach(self);
}

impl<T: Send + 'static> ScopedDetach for JoinGuard<'static, T> {
    fn detach(mut self) {
        let _ = self.inner.take();
    }
}

#[cfg(feature = "unstable")]
impl<T: Send + 'static> ScopedDetach for ::std::thread::JoinGuard<'static, T> {
    fn detach(self) {
        use std::mem::forget;

        forget(self);
    }
}

impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> {
    fn drop(&mut self) {
        self.inner.take().map(|v| if v.join().is_err() {
            panic!("child thread {:?} panicked", self.thread());
        });
    }
}

/// Spawns a new scoped thread
pub unsafe fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where
    T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
{
    let f = BoxedThing::new(f);

    JoinGuard {
        inner: Some(spawn(move ||
            BoxedThing::new(f.into_inner::<F>()())
        )),
        _marker: PhantomData,
    }
}

struct BoxedThing(usize);
impl BoxedThing {
    fn new<T>(v: T) -> Self {
        let mut b = Box::new(v);
        let b_ptr = &mut *b as *mut _ as usize;
        forget(b);
        BoxedThing(b_ptr)
    }

    unsafe fn into_inner<T>(self) -> Box<T> {
        transmute(self.0 as *mut T)
    }
}

#[cfg(test)]
mod tests {
    use std::thread::sleep_ms;
    use super::scoped;

    #[test]
    fn test_scoped_stack() {
        unsafe {
            let mut a = 5;
            scoped(|| {
                sleep_ms(50);
                a = 2;
            }).join();
            assert_eq!(a, 2);
        }
    }

    #[test]
    fn test_join_success() {
        unsafe {
            assert!(scoped(move|| -> String {
                "Success!".to_string()
            }).join() == "Success!");
        }
    }

    #[test]
    fn test_scoped_success() {
        unsafe {
            let res = scoped(move|| -> String {
                "Success!".to_string()
            }).join();
            assert!(res == "Success!");
        }
    }

    #[test]
    #[should_panic]
    fn test_scoped_panic() {
        unsafe {
            scoped(|| panic!()).join();
        }
    }

    #[test]
    #[should_panic]
    fn test_scoped_implicit_panic() {
        unsafe {
            let _ = scoped(|| panic!());
        }
    }
}
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#[macro_use]
extern crate log;
extern crate libc;
use libc::{c_int, c_void};
extern crate ipc;
use ipc::Semaphore;

#[allow(non_camel_case_types)]
pub mod ffiairspy;

use std::mem;
use std::ptr;
use std::slice;

#[derive(Debug)]
pub enum AirspyError {
    InvalidParam       = ffiairspy::AIRSPY_ERROR_INVALID_PARAM as isize,
    NotFound           = ffiairspy::AIRSPY_ERROR_NOT_FOUND as isize,
    Busy               = ffiairspy::AIRSPY_ERROR_BUSY as isize,
    NoMem              = ffiairspy::AIRSPY_ERROR_NO_MEM as isize,
    LibUsb             = ffiairspy::AIRSPY_ERROR_LIBUSB as isize,
    Thread             = ffiairspy::AIRSPY_ERROR_THREAD as isize,
    StreamingThreadErr = ffiairspy::AIRSPY_ERROR_STREAMING_THREAD_ERR as isize,
    StreamingStopped   = ffiairspy::AIRSPY_ERROR_STREAMING_STOPPED as isize,
    Other              = ffiairspy::AIRSPY_ERROR_OTHER as isize,
}

#[derive(Debug, Copy, Clone)]
pub enum AirspySamplerate {
    Sps10000000 = 10_000_000,
    Sps2500000  =  2_500_000,
}

#[derive(Debug)]
pub enum AirspySampleType {
    /// 2 * 32bit float per sample
    Float32IQ   = ffiairspy::AIRSPY_SAMPLE_FLOAT32_IQ as isize,
    /// 1 * 32bit float per sample
    Float32Real = ffiairspy::AIRSPY_SAMPLE_FLOAT32_REAL as isize,
    /// 2 * 16bit int per sample
    Int16IQ     = ffiairspy::AIRSPY_SAMPLE_INT16_IQ as isize,
    /// 1 * 16bit int per sample
    Int16Real   = ffiairspy::AIRSPY_SAMPLE_INT16_REAL as isize,
    /// 1 * 16bit unsigned int per sample
    Uint16Real  = ffiairspy::AIRSPY_SAMPLE_UINT16_REAL as isize,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct IQ<T> {
    i: T,
    q: T,
}

pub trait AirspySupportedType<T> {
    fn get_sample_type() -> u32;
    fn sample_buf_to_vec(sample_buf: *mut c_void, sample_count: usize) -> Vec<T>;
    fn sample_vec_to_bytes(samples: &Vec<T>) -> &[u8];
}

macro_rules! impl_airspy_supported_type {
    ($typ:ty, $sample_type:expr) => {
        impl AirspySupportedType<$typ> for $typ {
            fn get_sample_type() -> u32 {
                $sample_type
            }

            fn sample_buf_to_vec(sample_buf: *mut c_void, sample_count: usize) -> Vec<$typ> {
                let slice: &[$typ] = unsafe {
                    slice::from_raw_parts(sample_buf as *mut $typ, sample_count)
                };
                slice.to_vec()
            }

            fn sample_vec_to_bytes(samples: &Vec<$typ>) -> &[u8] {
                let slice = &samples[..];
                let bytes_in_sample = match $sample_type {
                    ffiairspy::AIRSPY_SAMPLE_FLOAT32_IQ => 8,
                    ffiairspy::AIRSPY_SAMPLE_FLOAT32_REAL => 4,
                    ffiairspy::AIRSPY_SAMPLE_INT16_IQ => 4,
                    ffiairspy::AIRSPY_SAMPLE_INT16_REAL => 2,
                    ffiairspy::AIRSPY_SAMPLE_UINT16_REAL => 2,
                    _ => panic!("wrong sample type!"),
                };

                let sliceu8: &[u8] = unsafe {
                    slice::from_raw_parts(slice.as_ptr() as *mut u8, samples.len() * bytes_in_sample)
                };

                sliceu8
            }
        }
    };
}

impl_airspy_supported_type!(IQ<f32>, ffiairspy::AIRSPY_SAMPLE_FLOAT32_IQ);
impl_airspy_supported_type!(f32,     ffiairspy::AIRSPY_SAMPLE_FLOAT32_REAL);
impl_airspy_supported_type!(IQ<i16>, ffiairspy::AIRSPY_SAMPLE_INT16_IQ);
impl_airspy_supported_type!(i16,     ffiairspy::AIRSPY_SAMPLE_INT16_REAL);
impl_airspy_supported_type!(u16,     ffiairspy::AIRSPY_SAMPLE_UINT16_REAL);

pub struct Airspy<T: AirspySupportedType<T>> {
    device    : *mut ffiairspy::Struct_airspy_device,
    samples   : Vec<Vec<T>>,
    empty_sem : Semaphore,
    full_sem : Semaphore,
}

impl<T: AirspySupportedType<T>> Airspy<T> {

    fn context(&mut self) -> *mut c_void {
        self as *mut _ as *mut c_void
    }

    pub fn new() -> Result<Airspy<T>, AirspyError> {
        let mut device = ptr::null_mut();

        let error = unsafe {ffiairspy::airspy_open(&mut device)};
        match error {
            ffiairspy::AIRSPY_SUCCESS => {
                let airspy = Airspy {device: device,
                                    samples: Vec::<Vec<T>>::with_capacity(2),
                                    empty_sem: Semaphore::new("empty_count", 2).unwrap(),
                                    full_sem: Semaphore::new("full_count", 0).unwrap(),
                };

                match unsafe {ffiairspy::airspy_set_sample_type(device, T::get_sample_type())} {
                    ffiairspy::AIRSPY_SUCCESS => {
                        Ok(airspy)
                    },
                    err => {
                        // airspy_set_sample_type should only return SUCCESS
                        // however just in case panic here if for some reason it does anything else
                        panic!("airspy_set_sample_type returned error {}", err)
                    },
                }
            },
            ffiairspy::AIRSPY_ERROR_NO_MEM => Err(AirspyError::NoMem),
            ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
            err => panic!("airspy_open returned error ({:})", err),
        }
    }

    pub fn set_samplerate(&self, samplerate: AirspySamplerate) -> Result<(), AirspyError> {
        let mut supported_samplerates_count: u32 = 0;

        // get count of supported samplerates
        let mut error = unsafe {ffiairspy::airspy_get_samplerates(self.device, &mut supported_samplerates_count as *mut u32, 0)};
        // anything except SUCCESS is library failure, hence panic!
        match error {
            ffiairspy::AIRSPY_SUCCESS => {},
            err => panic!("airspy_get_samplerates returned error ({:})", err),
        }

        assert!(supported_samplerates_count == ffiairspy::AIRSPY_SAMPLERATE_END);

        // get list of supported samplerates
        let mut samplerates: Vec<u32> = vec![0_u32; supported_samplerates_count as usize];
        error = unsafe {ffiairspy::airspy_get_samplerates(self.device, mem::transmute::<&mut u32, *mut u32>(&mut samplerates[0]), supported_samplerates_count)};
        // supported_samplerates_count must be right because we just asked for it from library, there must be lib error if anything other than SUCCESS is returned
        match error {
            ffiairspy::AIRSPY_SUCCESS => {},
            err => panic!("airspy_get_samplerates returned error ({:})", err),
        }

        let sr = samplerate.clone() as u32;
        let mut index: Option<u32> = None;
        for (i, rate) in samplerates.iter().enumerate() {
            if *rate == sr {
                index = Some(i as u32);
                break;
            }
        }

        if index.is_some() {
            let error = unsafe {ffiairspy::airspy_set_samplerate(self.device, index.unwrap())};
            match error {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => panic!("airspy_set_samplerate returned error ({:})", err),
            }
        }
        else {
            panic!("samplerate {:?} not supported by libairspy, supported samplerates are {:?}", samplerate, samplerates);
        }
    }

    pub fn set_bias_tee(&self, onoff: bool) -> Result<(), AirspyError> {
        let c_onoff = match onoff {
            true => 1,
            false => 0,
        };

        match unsafe {ffiairspy::airspy_set_rf_bias(self.device, c_onoff)} {
            ffiairspy::AIRSPY_SUCCESS => Ok(()),
            ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
            err => {
                panic!("airspy_set_rf_bias returned error {}", err)
            }
        }
    }

    pub fn set_lna_gain(&self, gain: u8) -> Result<(), AirspyError> {
        if gain > 15 {
            Err(AirspyError::InvalidParam)
        }
        else {
            match unsafe {ffiairspy::airspy_set_lna_gain(self.device, gain)} {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => panic!("airspy_set_lna_gain returned error {}", err),
            }
        }
    }

    pub fn set_mixer_gain(&self, gain: u8) -> Result<(), AirspyError> {
        if gain > 15 {
            Err(AirspyError::InvalidParam)
        }
        else {
            match unsafe {ffiairspy::airspy_set_mixer_gain(self.device, gain)} {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => panic!("airspy_set_mixer_gain returned error {}", err)
            }
        }
    }

    pub fn set_vga_gain(&self, gain: u8) -> Result<(), AirspyError> {
        if gain > 15 {
            Err(AirspyError::InvalidParam)
        }
        else {
            match unsafe {ffiairspy::airspy_set_vga_gain(self.device, gain)} {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => panic!("airspy_set_vga_gain returned error {}", err),
            }
        }
    }

    pub fn set_frequency(&self, freq_hz: u32) -> Result<(), AirspyError> {
        // 24 MHz to 1.8 GHz
        if freq_hz < 24_000_000 || freq_hz > 1_8_00_000_000 {
            Err(AirspyError::InvalidParam)
        }
        else {
            match unsafe {ffiairspy::airspy_set_freq(self.device, freq_hz)} {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => panic!("airspy_set_freq returned error {}", err),
            }
        }
    }

    pub fn start_rx(&mut self) -> Result<(), AirspyError> {
        match unsafe {ffiairspy::airspy_start_rx(self.device, Some(Self::receive), self.context())} {
            ffiairspy::AIRSPY_SUCCESS => Ok(()),
            ffiairspy::AIRSPY_ERROR_BUSY => Err(AirspyError::Busy),
            ffiairspy::AIRSPY_ERROR_THREAD => Err(AirspyError::Thread),
            err => panic!("airspy_start_rx returned error {}", err),
        }
    }

    extern "C" fn receive(transfer: *mut ffiairspy::airspy_transfer) -> c_int {
        let transfer: &mut ffiairspy::airspy_transfer = unsafe {mem::transmute(transfer)};
        assert!(!transfer.ctx.is_null());
        assert!(transfer.sample_count == 131072 || transfer.sample_count == 65536);

        let selfclient : &mut Self = unsafe {mem::transmute(transfer.ctx)};

        // mutex here?
        // actually it currently does not use double buffering
        selfclient.empty_sem.acquire();
        selfclient.samples.push(T::sample_buf_to_vec(transfer.samples, transfer.sample_count as usize));
        selfclient.full_sem.release();

        0
    }

    pub fn samples(&mut self) -> AirspyIntoIterator<T> {
        AirspyIntoIterator {
            airspy: self,
        }
    }

    pub fn convert_samples_to_bytes<'a>(samples: &'a Vec<T>) -> &[u8] {
        T::sample_vec_to_bytes(samples)
    }
}

pub struct AirspyIntoIterator<'a, T: AirspySupportedType<T> + 'a> {
    airspy: &'a mut Airspy<T>,
}

impl <'a, T: AirspySupportedType<T>>Iterator for AirspyIntoIterator<'a, T> {
    type Item = Vec<T>;
    fn next(&mut self) -> Option<Vec<T>> {
        // mutex here?
        self.airspy.full_sem.acquire();
        if self.airspy.samples.len() > 0 {
            self.airspy.empty_sem.release();
            Some(self.airspy.samples.remove(0))
        }
        else {
            None
        }
    }
}

impl<T: AirspySupportedType<T>> Drop for Airspy<T> {
    fn drop(&mut self) {
        unsafe{ffiairspy::airspy_close(self.device)};
        unsafe{ffiairspy::airspy_exit()};
    }
}
<commit_msg>add stop_rx<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#[macro_use]
extern crate log;
extern crate libc;
use libc::{c_int, c_void};
extern crate ipc;
use ipc::Semaphore;

#[allow(non_camel_case_types)]
pub mod ffiairspy;

use std::mem;
use std::ptr;
use std::slice;

#[derive(Debug)]
pub enum AirspyError {
    InvalidParam       = ffiairspy::AIRSPY_ERROR_INVALID_PARAM as isize,
    NotFound           = ffiairspy::AIRSPY_ERROR_NOT_FOUND as isize,
    Busy               = ffiairspy::AIRSPY_ERROR_BUSY as isize,
    NoMem              = ffiairspy::AIRSPY_ERROR_NO_MEM as isize,
    LibUsb             = ffiairspy::AIRSPY_ERROR_LIBUSB as isize,
    Thread             = ffiairspy::AIRSPY_ERROR_THREAD as isize,
    StreamingThreadErr = ffiairspy::AIRSPY_ERROR_STREAMING_THREAD_ERR as isize,
    StreamingStopped   = ffiairspy::AIRSPY_ERROR_STREAMING_STOPPED as isize,
    Other              = ffiairspy::AIRSPY_ERROR_OTHER as isize,
}

#[derive(Debug, Copy, Clone)]
pub enum AirspySamplerate {
    Sps10000000 = 10_000_000,
    Sps2500000  =  2_500_000,
}

#[derive(Debug)]
pub enum AirspySampleType {
    /// 2 * 32bit float per sample
    Float32IQ   = ffiairspy::AIRSPY_SAMPLE_FLOAT32_IQ as isize,
    /// 1 * 32bit float per sample
    Float32Real = ffiairspy::AIRSPY_SAMPLE_FLOAT32_REAL as isize,
    /// 2 * 16bit int per sample
    Int16IQ     = ffiairspy::AIRSPY_SAMPLE_INT16_IQ as isize,
    /// 1 * 16bit int per sample
    Int16Real   = ffiairspy::AIRSPY_SAMPLE_INT16_REAL as isize,
    /// 1 * 16bit unsigned int per sample
    Uint16Real  = ffiairspy::AIRSPY_SAMPLE_UINT16_REAL as isize,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct IQ<T> {
    i: T,
    q: T,
}

pub trait AirspySupportedType<T> {
    fn get_sample_type() -> u32;
    fn sample_buf_to_vec(sample_buf: *mut c_void, sample_count: usize) -> Vec<T>;
    fn sample_vec_to_bytes(samples: &Vec<T>) -> &[u8];
}

macro_rules! impl_airspy_supported_type {
    ($typ:ty, $sample_type:expr) => {
        impl AirspySupportedType<$typ> for $typ {
            fn get_sample_type() -> u32 {
                $sample_type
            }

            fn sample_buf_to_vec(sample_buf: *mut c_void, sample_count: usize) -> Vec<$typ> {
                let slice: &[$typ] = unsafe {
                    slice::from_raw_parts(sample_buf as *mut $typ, sample_count)
                };
                slice.to_vec()
            }

            fn sample_vec_to_bytes(samples: &Vec<$typ>) -> &[u8] {
                let slice = &samples[..];
                let bytes_in_sample = match $sample_type {
                    ffiairspy::AIRSPY_SAMPLE_FLOAT32_IQ => 8,
                    ffiairspy::AIRSPY_SAMPLE_FLOAT32_REAL => 4,
                    ffiairspy::AIRSPY_SAMPLE_INT16_IQ => 4,
                    ffiairspy::AIRSPY_SAMPLE_INT16_REAL => 2,
                    ffiairspy::AIRSPY_SAMPLE_UINT16_REAL => 2,
                    _ => panic!("wrong sample type!"),
                };

                let sliceu8: &[u8] = unsafe {
                    slice::from_raw_parts(slice.as_ptr() as *mut u8, samples.len() * bytes_in_sample)
                };

                sliceu8
            }
        }
    };
}

impl_airspy_supported_type!(IQ<f32>, ffiairspy::AIRSPY_SAMPLE_FLOAT32_IQ);
impl_airspy_supported_type!(f32,     ffiairspy::AIRSPY_SAMPLE_FLOAT32_REAL);
impl_airspy_supported_type!(IQ<i16>, ffiairspy::AIRSPY_SAMPLE_INT16_IQ);
impl_airspy_supported_type!(i16,     ffiairspy::AIRSPY_SAMPLE_INT16_REAL);
impl_airspy_supported_type!(u16,     ffiairspy::AIRSPY_SAMPLE_UINT16_REAL);

pub struct Airspy<T: AirspySupportedType<T>> {
    device    : *mut ffiairspy::Struct_airspy_device,
    samples   : Vec<Vec<T>>,
    empty_sem : Semaphore,
    full_sem : Semaphore,
}

impl<T: AirspySupportedType<T>> Airspy<T> {

    fn context(&mut self) -> *mut c_void {
        self as *mut _ as *mut c_void
    }

    pub fn new() -> Result<Airspy<T>, AirspyError> {
        let mut device = ptr::null_mut();

        let error = unsafe {ffiairspy::airspy_open(&mut device)};
        match error {
            ffiairspy::AIRSPY_SUCCESS => {
                let airspy = Airspy {device: device,
                                    samples: Vec::<Vec<T>>::with_capacity(2),
                                    empty_sem: Semaphore::new("empty_count", 2).unwrap(),
                                    full_sem: Semaphore::new("full_count", 0).unwrap(),
                };

                match unsafe {ffiairspy::airspy_set_sample_type(device, T::get_sample_type())} {
                    ffiairspy::AIRSPY_SUCCESS => {
                        Ok(airspy)
                    },
                    err => {
                        // airspy_set_sample_type should only return SUCCESS
                        // however just in case panic here if for some reason it does anything else
                        panic!("airspy_set_sample_type returned error {}", err)
                    },
                }
            },
            ffiairspy::AIRSPY_ERROR_NO_MEM => Err(AirspyError::NoMem),
            ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
            err => panic!("airspy_open returned error ({:})", err),
        }
    }

    pub fn set_samplerate(&self, samplerate: AirspySamplerate) -> Result<(), AirspyError> {
        let mut supported_samplerates_count: u32 = 0;

        // get count of supported samplerates
        let mut error = unsafe {ffiairspy::airspy_get_samplerates(self.device, &mut supported_samplerates_count as *mut u32, 0)};
        // anything except SUCCESS is library failure, hence panic!
        match error {
            ffiairspy::AIRSPY_SUCCESS => {},
            err => panic!("airspy_get_samplerates returned error ({:})", err),
        }

        assert!(supported_samplerates_count == ffiairspy::AIRSPY_SAMPLERATE_END);

        // get list of supported samplerates
        let mut samplerates: Vec<u32> = vec![0_u32; supported_samplerates_count as usize];
        error = unsafe {ffiairspy::airspy_get_samplerates(self.device, mem::transmute::<&mut u32, *mut u32>(&mut samplerates[0]), supported_samplerates_count)};
        // supported_samplerates_count must be right because we just asked for it from library, there must be lib error if anything other than SUCCESS is returned
        match error {
            ffiairspy::AIRSPY_SUCCESS => {},
            err => panic!("airspy_get_samplerates returned error ({:})", err),
        }

        let sr = samplerate.clone() as u32;
        let mut index: Option<u32> = None;
        for (i, rate) in samplerates.iter().enumerate() {
            if *rate == sr {
                index = Some(i as u32);
                break;
            }
        }

        if index.is_some() {
            let error = unsafe {ffiairspy::airspy_set_samplerate(self.device, index.unwrap())};
            match error {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => panic!("airspy_set_samplerate returned error ({:})", err),
            }
        }
        else {
            panic!("samplerate {:?} not supported by libairspy, supported samplerates are {:?}", samplerate, samplerates);
        }
    }

    pub fn set_bias_tee(&self, onoff: bool) -> Result<(), AirspyError> {
        let c_onoff = match onoff {
            true => 1,
            false => 0,
        };

        match unsafe {ffiairspy::airspy_set_rf_bias(self.device, c_onoff)} {
            ffiairspy::AIRSPY_SUCCESS => Ok(()),
            ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
            err => {
                panic!("airspy_set_rf_bias returned error {}", err)
            }
        }
    }

    pub fn set_lna_gain(&self, gain: u8) -> Result<(), AirspyError> {
        if gain > 15 {
            Err(AirspyError::InvalidParam)
        }
        else {
            match unsafe {ffiairspy::airspy_set_lna_gain(self.device, gain)} {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => panic!("airspy_set_lna_gain returned error {}", err),
            }
        }
    }

    pub fn set_mixer_gain(&self, gain: u8) -> Result<(), AirspyError> {
        if gain > 15 {
            Err(AirspyError::InvalidParam)
        }
        else {
            match unsafe {ffiairspy::airspy_set_mixer_gain(self.device, gain)} {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => panic!("airspy_set_mixer_gain returned error {}", err)
            }
        }
    }

    pub fn set_vga_gain(&self, gain: u8) -> Result<(), AirspyError> {
        if gain > 15 {
            Err(AirspyError::InvalidParam)
        }
        else {
            match unsafe {ffiairspy::airspy_set_vga_gain(self.device, gain)} {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => panic!("airspy_set_vga_gain returned error {}", err),
            }
        }
    }

    pub fn set_frequency(&self, freq_hz: u32) -> Result<(), AirspyError> {
        // 24 MHz to 1.8 GHz
        if freq_hz < 24_000_000 || freq_hz > 1_8_00_000_000 {
            Err(AirspyError::InvalidParam)
        }
        else {
            match unsafe {ffiairspy::airspy_set_freq(self.device, freq_hz)} {
                ffiairspy::AIRSPY_SUCCESS => Ok(()),
                ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
                err => panic!("airspy_set_freq returned error {}", err),
            }
        }
    }

    pub fn start_rx(&mut self) -> Result<(), AirspyError> {
        match unsafe {ffiairspy::airspy_start_rx(self.device, Some(Self::receive), self.context())} {
            ffiairspy::AIRSPY_SUCCESS => Ok(()),
            ffiairspy::AIRSPY_ERROR_BUSY => Err(AirspyError::Busy),
            ffiairspy::AIRSPY_ERROR_THREAD => Err(AirspyError::Thread),
            err => panic!("airspy_start_rx returned error {}", err),
        }
    }

    pub fn stop_rx(&mut self) -> Result<(), AirspyError> {
        match unsafe {ffiairspy::airspy_stop_rx(self.device)} {
            ffiairspy::AIRSPY_SUCCESS => Ok(()),
            ffiairspy::AIRSPY_ERROR_LIBUSB => Err(AirspyError::LibUsb),
            err => panic!("airspy_stop_rx returned error {}", err),
        }
    }

    extern "C" fn receive(transfer: *mut ffiairspy::airspy_transfer) -> c_int {
        let transfer: &mut ffiairspy::airspy_transfer = unsafe {mem::transmute(transfer)};
        assert!(!transfer.ctx.is_null());
        assert!(transfer.sample_count == 131072 || transfer.sample_count == 65536);

        let selfclient : &mut Self = unsafe {mem::transmute(transfer.ctx)};

        // mutex here?
        // actually it currently does not use double buffering
        selfclient.empty_sem.acquire();
        selfclient.samples.push(T::sample_buf_to_vec(transfer.samples, transfer.sample_count as usize));
        selfclient.full_sem.release();

        0
    }

    pub fn samples(&mut self) -> AirspyIntoIterator<T> {
        AirspyIntoIterator {
            airspy: self,
        }
    }

    pub fn convert_samples_to_bytes<'a>(samples: &'a Vec<T>) -> &[u8] {
        T::sample_vec_to_bytes(samples)
    }
}

pub struct AirspyIntoIterator<'a, T: AirspySupportedType<T> + 'a> {
    airspy: &'a mut Airspy<T>,
}

impl <'a, T: AirspySupportedType<T>>Iterator for AirspyIntoIterator<'a, T> {
    type Item = Vec<T>;
    fn next(&mut self) -> Option<Vec<T>> {
        // mutex here?
        self.airspy.full_sem.acquire();
        if self.airspy.samples.len() > 0 {
            self.airspy.empty_sem.release();
            Some(self.airspy.samples.remove(0))
        }
        else {
            None
        }
    }
}

impl<T: AirspySupportedType<T>> Drop for Airspy<T> {
    fn drop(&mut self) {
        unsafe{ffiairspy::airspy_close(self.device)};
        unsafe{ffiairspy::airspy_exit()};
    }
}
<|endoftext|>


<commit_before>//! Implementation of a Frequency Distribution in Rust. Keeps track of how many
//! times an object appears in a larger context (for example, how many times a
//! word appears in a piece of text). The underlying data structure of the
//! Frequency Distribution is a HashMap, so the object that is being counted
//! must be hashable.
//!
//! # Example
//!
//! ```
//! # use freqdist::FrequencyDistribution;
//! #
//! let mut fdist: FrequencyDistribution<&str> = FrequencyDistribution::new();
//!
//! fdist.insert("hello");
//! fdist.insert("hello");
//! fdist.insert("goodbye");
//!
//! assert_eq!(fdist.get(&"hello"), 2);
//! ```

#![feature(std_misc)]
#![warn(missing_docs)]
#![cfg_attr(test, feature(test))]

#[cfg(test)] extern crate test;

use std::ops::Index;
use std::default::Default;
use std::hash::{Hasher, Hash, SipHasher};
use std::iter::{FromIterator, IntoIterator};
use std::borrow::Borrow;
use std::collections::HashMap;
use std::collections::hash_map::{Keys, IntoIter, Iter};
use std::collections::hash_state::{HashState, DefaultState};

static ZERO: usize = 0;

#[allow(missing_docs)] pub struct FrequencyDistribution<K, S = DefaultState<SipHasher>> {
  hashmap: HashMap<K, usize, S>,
  sum_counts: usize
}

impl<K, H = SipHasher, S = DefaultState<SipHasher>> FrequencyDistribution<K, S>
  where K : Eq + Hash,
        H : Hasher,
        S : HashState<Hasher = H>
{
  /// Creates a new FrequencyDistrbution with a hash state and size, where
  /// the size is known or can be estimated.
  #[inline(always)] pub fn with_capacity_and_hash_state(
    size: usize,
    state: S
  ) -> FrequencyDistribution<K, S> {
    FrequencyDistribution {
      hashmap: HashMap::with_capacity_and_hash_state(size, state),
      sum_counts: 0
    }
  }

  /// Creates a new FrequencyDistribution with a hash state and default size.
  #[inline(always)] pub fn with_hash_state(state: S) -> FrequencyDistribution<K, S> {
    FrequencyDistribution {
      hashmap: HashMap::with_hash_state(state),
      sum_counts: 0
    }
  }

    /// Iterator over the keys.
  #[inline(always)] pub fn keys(&self) -> Keys<K, usize> {
    self.hashmap.keys()
  }

  /// Iterator over the key, frequency pairs.
  #[inline(always)] pub fn iter(&self) -> Iter<K, usize> {
    self.hashmap.iter()
  }

  /// Iterator over the non-zero frequency keys.
  ///
  /// # Example
  ///
  /// ```
  /// # use std::iter::{FromIterator, IntoIterator};
  /// # use freqdist::FrequencyDistribution;
  /// #
  /// let existing = vec![
  ///   ("shoes", 1),
  ///   ("scarf", 0),
  ///   ("shirt", 13),
  ///   ("pants", 4)
  /// ];
  ///
  /// let fdist: FrequencyDistribution<&str> =
  ///   FromIterator::from_iter(existing.into_iter());
  /// let mut iter = fdist.iter_non_zero();
  ///
  /// assert_eq!(*iter.next().unwrap(), "shirt");
  /// assert_eq!(*iter.next().unwrap(), "shoes");
  /// assert_eq!(*iter.next().unwrap(), "pants");
  /// assert!(iter.next().is_none());
  /// ```
  #[inline(always)] pub fn iter_non_zero(&self) -> NonZeroKeysIter<K> {
    NonZeroKeysIter { iter: self.iter() }
  }

  /// Sum of the total number of items counted thus far.
  #[inline(always)] pub fn sum_counts(&self) -> usize {
    self.sum_counts
  }

  /// Returns the number of entries in the distribution
  #[inline(always)] pub fn len(&self) -> usize {
    self.hashmap.len()
  }

  /// Gets the frequency in which the key occurs.
  #[inline(always)] pub fn get<Q : ?Sized>(&self, k: &Q) -> usize
    where K : Borrow<Q>, Q : Hash + Eq
  {
    self[k]
  }

  /// Clears the counts of all keys and clears all keys from
  /// the distribution.
  #[inline(always)] pub fn clear(&mut self) {
    self.hashmap.clear()
  }

  /// Updates the frequency of the value found with the key if it
  /// already exists. Otherwise, inserts the key sizeo the hashmap,
  /// and sets its frequency to 1.
  #[inline(always)] pub fn insert(&mut self, k: K) {
    self.insert_or_incr_by(k, 1);
  }

  /// Removes an item and its associated counts.
  #[inline(always)] pub fn remove<Q : ?Sized>(&mut self, k: &Q)
    where K : Borrow<Q>, Q : Hash + Eq
  {
    match self.hashmap.remove(k) {
      Some(count) => self.sum_counts -= count,
      None => ()
    }
  }

  /// Inserts a value sizeo the hashmap if it does not exist with a new quantity
  /// specified by the increment. If the value already exists, increments by
  /// the specified amount.
  #[inline] fn insert_or_incr_by(&mut self, k: K, incr: usize) {
    if !self.hashmap.contains_key(&k) {
      self.hashmap.insert(k, incr);
    } else {
      *self.hashmap.get_mut(&k).unwrap() += incr;
    }

    self.sum_counts += incr;
  }
}

impl<K, H = SipHasher, S = DefaultState<SipHasher>> FrequencyDistribution<K, S>
  where K : Eq + Hash,
        H : Hasher + Default,
        S : HashState<Hasher = H> + Default
{
  /// Creates a new FrequencyDistribution where the size of the
  /// HashMap is unknown.
  #[inline(always)] pub fn new() -> FrequencyDistribution<K, S> {
    FrequencyDistribution::with_hash_state(Default::default())
  }

  /// Creates a new FrequencyDistribution where the size of the HashMap
  /// is known, or a estimate can be made.
  #[inline(always)] pub fn with_capacity(
    size: usize
  ) -> FrequencyDistribution<K, S> {
    FrequencyDistribution::with_capacity_and_hash_state(size, Default::default())
  }
}

impl<K, H = SipHasher, S = DefaultState<SipHasher>> Default for FrequencyDistribution<K, S>
  where K : Eq + Hash,
        H : Hasher + Default,
        S : HashState<Hasher = H> + Default
{
  /// Creates a default FrequencyDistribution.
  #[inline(always)] fn default() -> FrequencyDistribution<K, S> {
    FrequencyDistribution::new()
  }
}

impl<K, H, S> FromIterator<(K, usize)> for FrequencyDistribution<K, S>
  where K : Eq + Hash,
        H : Hasher,
        S : HashState<Hasher = H> + Default
{
  /// Iterates through an iterator, and creates a new FrequencyDistribution from
  /// it. The iterator should be an iterator over keys and frequencies. If a
  /// upper bounded `size_hsize` is available, then it is used, otherwise the lower
  /// bounded `size_hsize` is used.
  ///
  /// # Example
  ///
  /// ```
  /// # use std::iter::FromIterator;
  /// # use freqdist::FrequencyDistribution;
  /// #
  /// let existing = vec![
  ///   ("apples", 3),
  ///   ("oranges", 4),
  ///   ("bannana", 7)
  /// ];
  ///
  /// let fdist: FrequencyDistribution<&str> =
  ///   FromIterator::from_iter(existing.into_iter());
  ///
  /// assert_eq!(fdist.get(&"apples"), 3);
  /// assert_eq!(fdist.get(&"oranges"), 4);
  /// assert_eq!(fdist.get(&"bannana"), 7);
  /// ```
  fn from_iter<T>(iter: T) -> FrequencyDistribution<K, S>
    where T : IntoIterator<Item = (K, usize)>
  {
    let iterator = iter.into_iter();
    let mut fdist = if iterator.size_hint().1.is_some() {
      FrequencyDistribution::with_capacity_and_hash_state(
        iterator.size_hint().1.unwrap(),
        Default::default())
    } else {
      FrequencyDistribution::with_capacity_and_hash_state(
        iterator.size_hint().0,
        Default::default())
    };

    for (k, freq) in iterator { fdist.insert_or_incr_by(k, freq); }

    fdist
  }
}

impl<K, H, S> Extend<(K, usize)> for FrequencyDistribution<K, S>
  where K : Eq + Hash,
        H : Hasher,
        S : HashState<Hasher = H>
{
  /// Extends the hashmap by adding the keys or updating the frequencies of the keys.
  fn extend<T>(&mut self, iter: T)
    where T: IntoIterator<Item = (K, usize)>
  {
    for (k, freq) in iter.into_iter() { self.insert_or_incr_by(k, freq); }
  }
}

impl<K, H, S> IntoIterator for FrequencyDistribution<K, S>
  where K : Eq + Hash,
        H : Hasher,
        S : HashState<Hasher = H>
{
  type Item = (K, usize);
  type IntoIter = IntoIter<K, usize>;

  /// Consumes the distribution, and creates an iterator over the
  /// (Key, Quantity: usize) pairs.
  #[inline] fn into_iter(self) -> IntoIter<K, usize> {
    self.hashmap.into_iter()
  }
}

impl<'a, K, H, S, Q : ?Sized> Index<&'a Q> for FrequencyDistribution<K, S>
  where K : Eq + Hash + Borrow<Q>,
        H : Hasher,
        S : HashState<Hasher = H>,
        Q : Eq + Hash
{
  type Output = usize;

  #[inline] fn index<'b>(&'b self, index: &Q) -> &'b usize {
    self.hashmap.get(index).unwrap_or(&ZERO)
  }
}

/// Iterator over entries with non-zero quantities.
pub struct NonZeroKeysIter<'a, K: 'a> {
  iter: Iter<'a, K, usize>
}

impl<'a, K: 'a> Iterator for NonZeroKeysIter<'a, K> {
  type Item = &'a K;

  #[inline(always)] fn next(&mut self) -> Option<&'a K> {
    loop {
      match self.iter.next() {
        Some((k, c)) if *c > 0 => return Some(k),
        None => return None,
        _ => ()
      }
    }
  }
}

#[test]
fn smoke_test_frequency_distribution_insert() {
  let words = vec!("alpha", "beta");
  let mut dist: FrequencyDistribution<&str> = FrequencyDistribution::new();

  dist.insert(words[0]);

  assert_eq!(dist.get(&words[0]), 1);

  dist.insert(words[1]);

  assert_eq!(dist.get(&words[1]), 1);

  for _ in (0..7u32) { dist.insert(words[0]); }

  assert_eq!(dist.get(&words[0]), 8);
}

#[test]
fn smoke_test_frequency_distribution_iter() {
  let words = vec!(("a", 50usize), ("b", 100usize), ("c", 75usize), ("d", 0usize));
  let dist: FrequencyDistribution<&str> = FromIterator::from_iter(words.into_iter());

  assert_eq!(dist.get(&"a"), 50);
  assert_eq!(dist.get(&"b"), 100);
  assert_eq!(dist.get(&"c"), 75);

  let mut iter = dist.iter_non_zero();

  assert!(iter.next().is_some());
  assert!(iter.next().is_some());
  assert!(iter.next().is_some());
  assert!(iter.next().is_none());

  assert_eq!(dist.sum_counts(), 225);
}

#[test]
fn smoke_test_frequency_distribution_remove() {
  let words = vec!(("a", 50usize), ("b", 100usize), ("c", 25usize));
  let mut dist: FrequencyDistribution<&str> = FromIterator::from_iter(words.into_iter());

  assert_eq!(dist.get(&"a"), 50);

  dist.remove(&"a");

  assert_eq!(dist.get(&"a"), 0);
  assert_eq!(dist.sum_counts(), 125);
}

#[test]
fn smoke_test_frequency_sum_counts() {
  let words = vec!(("a", 7usize), ("b", 5usize), ("c", 8usize), ("d", 3usize));
  let mut dist: FrequencyDistribution<&str> = FromIterator::from_iter(words.into_iter());

  assert_eq!(dist.sum_counts(), 23);

  dist.insert("e");

  assert_eq!(dist.sum_counts(), 24);
}
<commit_msg>added hashmap_hasher feature<commit_after>//! Implementation of a Frequency Distribution in Rust. Keeps track of how many
//! times an object appears in a larger context (for example, how many times a
//! word appears in a piece of text). The underlying data structure of the
//! Frequency Distribution is a HashMap, so the object that is being counted
//! must be hashable.
//!
//! # Example
//!
//! ```
//! # use freqdist::FrequencyDistribution;
//! #
//! let mut fdist: FrequencyDistribution<&str> = FrequencyDistribution::new();
//!
//! fdist.insert("hello");
//! fdist.insert("hello");
//! fdist.insert("goodbye");
//!
//! assert_eq!(fdist.get(&"hello"), 2);
//! ```

#![feature(std_misc, hashmap_hasher)]
#![warn(missing_docs)]
#![cfg_attr(test, feature(test))]

#[cfg(test)] extern crate test;

use std::ops::Index;
use std::default::Default;
use std::hash::{Hasher, Hash, SipHasher};
use std::iter::{FromIterator, IntoIterator};
use std::borrow::Borrow;
use std::collections::HashMap;
use std::collections::hash_map::{Keys, IntoIter, Iter};
use std::collections::hash_state::{HashState, DefaultState};

static ZERO: usize = 0;

#[allow(missing_docs)] pub struct FrequencyDistribution<K, S = DefaultState<SipHasher>> {
  hashmap: HashMap<K, usize, S>,
  sum_counts: usize
}

impl<K, H = SipHasher, S = DefaultState<SipHasher>> FrequencyDistribution<K, S>
  where K : Eq + Hash,
        H : Hasher,
        S : HashState<Hasher = H>
{
  /// Creates a new FrequencyDistrbution with a hash state and size, where
  /// the size is known or can be estimated.
  #[inline(always)] pub fn with_capacity_and_hash_state(
    size: usize,
    state: S
  ) -> FrequencyDistribution<K, S> {
    FrequencyDistribution {
      hashmap: HashMap::with_capacity_and_hash_state(size, state),
      sum_counts: 0
    }
  }

  /// Creates a new FrequencyDistribution with a hash state and default size.
  #[inline(always)] pub fn with_hash_state(state: S) -> FrequencyDistribution<K, S> {
    FrequencyDistribution {
      hashmap: HashMap::with_hash_state(state),
      sum_counts: 0
    }
  }

    /// Iterator over the keys.
  #[inline(always)] pub fn keys(&self) -> Keys<K, usize> {
    self.hashmap.keys()
  }

  /// Iterator over the key, frequency pairs.
  #[inline(always)] pub fn iter(&self) -> Iter<K, usize> {
    self.hashmap.iter()
  }

  /// Iterator over the non-zero frequency keys.
  ///
  /// # Example
  ///
  /// ```
  /// # use std::iter::{FromIterator, IntoIterator};
  /// # use freqdist::FrequencyDistribution;
  /// #
  /// let existing = vec![
  ///   ("shoes", 1),
  ///   ("scarf", 0),
  ///   ("shirt", 13),
  ///   ("pants", 4)
  /// ];
  ///
  /// let fdist: FrequencyDistribution<&str> =
  ///   FromIterator::from_iter(existing.into_iter());
  /// let mut iter = fdist.iter_non_zero();
  ///
  /// assert_eq!(*iter.next().unwrap(), "shirt");
  /// assert_eq!(*iter.next().unwrap(), "shoes");
  /// assert_eq!(*iter.next().unwrap(), "pants");
  /// assert!(iter.next().is_none());
  /// ```
  #[inline(always)] pub fn iter_non_zero(&self) -> NonZeroKeysIter<K> {
    NonZeroKeysIter { iter: self.iter() }
  }

  /// Sum of the total number of items counted thus far.
  #[inline(always)] pub fn sum_counts(&self) -> usize {
    self.sum_counts
  }

  /// Returns the number of entries in the distribution
  #[inline(always)] pub fn len(&self) -> usize {
    self.hashmap.len()
  }

  /// Gets the frequency in which the key occurs.
  #[inline(always)] pub fn get<Q : ?Sized>(&self, k: &Q) -> usize
    where K : Borrow<Q>, Q : Hash + Eq
  {
    self[k]
  }

  /// Clears the counts of all keys and clears all keys from
  /// the distribution.
  #[inline(always)] pub fn clear(&mut self) {
    self.hashmap.clear()
  }

  /// Updates the frequency of the value found with the key if it
  /// already exists. Otherwise, inserts the key sizeo the hashmap,
  /// and sets its frequency to 1.
  #[inline(always)] pub fn insert(&mut self, k: K) {
    self.insert_or_incr_by(k, 1);
  }

  /// Removes an item and its associated counts.
  #[inline(always)] pub fn remove<Q : ?Sized>(&mut self, k: &Q)
    where K : Borrow<Q>, Q : Hash + Eq
  {
    match self.hashmap.remove(k) {
      Some(count) => self.sum_counts -= count,
      None => ()
    }
  }

  /// Inserts a value sizeo the hashmap if it does not exist with a new quantity
  /// specified by the increment. If the value already exists, increments by
  /// the specified amount.
  #[inline] fn insert_or_incr_by(&mut self, k: K, incr: usize) {
    if !self.hashmap.contains_key(&k) {
      self.hashmap.insert(k, incr);
    } else {
      *self.hashmap.get_mut(&k).unwrap() += incr;
    }

    self.sum_counts += incr;
  }
}

impl<K, H = SipHasher, S = DefaultState<SipHasher>> FrequencyDistribution<K, S>
  where K : Eq + Hash,
        H : Hasher + Default,
        S : HashState<Hasher = H> + Default
{
  /// Creates a new FrequencyDistribution where the size of the
  /// HashMap is unknown.
  #[inline(always)] pub fn new() -> FrequencyDistribution<K, S> {
    FrequencyDistribution::with_hash_state(Default::default())
  }

  /// Creates a new FrequencyDistribution where the size of the HashMap
  /// is known, or a estimate can be made.
  #[inline(always)] pub fn with_capacity(
    size: usize
  ) -> FrequencyDistribution<K, S> {
    FrequencyDistribution::with_capacity_and_hash_state(size, Default::default())
  }
}

impl<K, H = SipHasher, S = DefaultState<SipHasher>> Default for FrequencyDistribution<K, S>
  where K : Eq + Hash,
        H : Hasher + Default,
        S : HashState<Hasher = H> + Default
{
  /// Creates a default FrequencyDistribution.
  #[inline(always)] fn default() -> FrequencyDistribution<K, S> {
    FrequencyDistribution::new()
  }
}

impl<K, H, S> FromIterator<(K, usize)> for FrequencyDistribution<K, S>
  where K : Eq + Hash,
        H : Hasher,
        S : HashState<Hasher = H> + Default
{
  /// Iterates through an iterator, and creates a new FrequencyDistribution from
  /// it. The iterator should be an iterator over keys and frequencies. If a
  /// upper bounded `size_hsize` is available, then it is used, otherwise the lower
  /// bounded `size_hsize` is used.
  ///
  /// # Example
  ///
  /// ```
  /// # use std::iter::FromIterator;
  /// # use freqdist::FrequencyDistribution;
  /// #
  /// let existing = vec![
  ///   ("apples", 3),
  ///   ("oranges", 4),
  ///   ("bannana", 7)
  /// ];
  ///
  /// let fdist: FrequencyDistribution<&str> =
  ///   FromIterator::from_iter(existing.into_iter());
  ///
  /// assert_eq!(fdist.get(&"apples"), 3);
  /// assert_eq!(fdist.get(&"oranges"), 4);
  /// assert_eq!(fdist.get(&"bannana"), 7);
  /// ```
  fn from_iter<T>(iter: T) -> FrequencyDistribution<K, S>
    where T : IntoIterator<Item = (K, usize)>
  {
    let iterator = iter.into_iter();
    let mut fdist = if iterator.size_hint().1.is_some() {
      FrequencyDistribution::with_capacity_and_hash_state(
        iterator.size_hint().1.unwrap(),
        Default::default())
    } else {
      FrequencyDistribution::with_capacity_and_hash_state(
        iterator.size_hint().0,
        Default::default())
    };

    for (k, freq) in iterator { fdist.insert_or_incr_by(k, freq); }

    fdist
  }
}

impl<K, H, S> Extend<(K, usize)> for FrequencyDistribution<K, S>
  where K : Eq + Hash,
        H : Hasher,
        S : HashState<Hasher = H>
{
  /// Extends the hashmap by adding the keys or updating the frequencies of the keys.
  fn extend<T>(&mut self, iter: T)
    where T: IntoIterator<Item = (K, usize)>
  {
    for (k, freq) in iter.into_iter() { self.insert_or_incr_by(k, freq); }
  }
}

impl<K, H, S> IntoIterator for FrequencyDistribution<K, S>
  where K : Eq + Hash,
        H : Hasher,
        S : HashState<Hasher = H>
{
  type Item = (K, usize);
  type IntoIter = IntoIter<K, usize>;

  /// Consumes the distribution, and creates an iterator over the
  /// (Key, Quantity: usize) pairs.
  #[inline] fn into_iter(self) -> IntoIter<K, usize> {
    self.hashmap.into_iter()
  }
}

impl<'a, K, H, S, Q : ?Sized> Index<&'a Q> for FrequencyDistribution<K, S>
  where K : Eq + Hash + Borrow<Q>,
        H : Hasher,
        S : HashState<Hasher = H>,
        Q : Eq + Hash
{
  type Output = usize;

  #[inline] fn index<'b>(&'b self, index: &Q) -> &'b usize {
    self.hashmap.get(index).unwrap_or(&ZERO)
  }
}

/// Iterator over entries with non-zero quantities.
pub struct NonZeroKeysIter<'a, K: 'a> {
  iter: Iter<'a, K, usize>
}

impl<'a, K: 'a> Iterator for NonZeroKeysIter<'a, K> {
  type Item = &'a K;

  #[inline(always)] fn next(&mut self) -> Option<&'a K> {
    loop {
      match self.iter.next() {
        Some((k, c)) if *c > 0 => return Some(k),
        None => return None,
        _ => ()
      }
    }
  }
}

#[test]
fn smoke_test_frequency_distribution_insert() {
  let words = vec!("alpha", "beta");
  let mut dist: FrequencyDistribution<&str> = FrequencyDistribution::new();

  dist.insert(words[0]);

  assert_eq!(dist.get(&words[0]), 1);

  dist.insert(words[1]);

  assert_eq!(dist.get(&words[1]), 1);

  for _ in (0..7u32) { dist.insert(words[0]); }

  assert_eq!(dist.get(&words[0]), 8);
}

#[test]
fn smoke_test_frequency_distribution_iter() {
  let words = vec!(("a", 50usize), ("b", 100usize), ("c", 75usize), ("d", 0usize));
  let dist: FrequencyDistribution<&str> = FromIterator::from_iter(words.into_iter());

  assert_eq!(dist.get(&"a"), 50);
  assert_eq!(dist.get(&"b"), 100);
  assert_eq!(dist.get(&"c"), 75);

  let mut iter = dist.iter_non_zero();

  assert!(iter.next().is_some());
  assert!(iter.next().is_some());
  assert!(iter.next().is_some());
  assert!(iter.next().is_none());

  assert_eq!(dist.sum_counts(), 225);
}

#[test]
fn smoke_test_frequency_distribution_remove() {
  let words = vec!(("a", 50usize), ("b", 100usize), ("c", 25usize));
  let mut dist: FrequencyDistribution<&str> = FromIterator::from_iter(words.into_iter());

  assert_eq!(dist.get(&"a"), 50);

  dist.remove(&"a");

  assert_eq!(dist.get(&"a"), 0);
  assert_eq!(dist.sum_counts(), 125);
}

#[test]
fn smoke_test_frequency_sum_counts() {
  let words = vec!(("a", 7usize), ("b", 5usize), ("c", 8usize), ("d", 3usize));
  let mut dist: FrequencyDistribution<&str> = FromIterator::from_iter(words.into_iter());

  assert_eq!(dist.sum_counts(), 23);

  dist.insert("e");

  assert_eq!(dist.sum_counts(), 24);
}
<|endoftext|>