<commit_before>use euclid::vec2;
use num::Integer;
use rand::distributions::{Distribution, Standard};
use rand::Rng;
use std::cmp::max;
use std::f32::consts::PI;
use std::ops::{Add, Sub};
use std::slice;
use CellVector;

/// Hex grid geometry for vectors.
pub trait HexGeom {
    /// Hex distance represented by a vector.
    fn hex_dist(&self) -> i32;
}

impl HexGeom for CellVector {
    fn hex_dist(&self) -> i32 {
        if self.x.signum() == self.y.signum() {
            max(self.x.abs(), self.y.abs())
        } else {
            self.x.abs() + self.y.abs()
        }
    }
}

/// Return offsets to neighboring hexes.
pub fn hex_neighbors
(origin: P) -> impl Iterator<Item = R>
where
    P: Clone + Add<CellVector, Output = R>,
{
    use Dir6::*;

    [North, Northeast, Southeast, South, Southwest, Northwest]
        .iter()
        .map(move |&d| origin.clone() + d.into())
}

/// Return offsets to the four cardinal directions.
///
/// These are also the fake-isometric directions on a hex map.
pub fn taxicab_neighbors
(origin: P) -> impl Iterator<Item = R>
where
    P: Clone + Add<CellVector, Output = R>,
{
    use Dir6::*;

    [Northeast, Southeast, Southwest, Northwest]
        .iter()
        .map(move |&d| origin.clone() + d.into())
}

/// Return an iterator for all the points in the hex disc with the given radius.
pub fn hex_disc
(origin: P, radius: i32) -> HexDisc

where
    P: Clone + Add<CellVector, Output = R>,
{
    HexDisc {
        origin,
        radius,
        i: 0,
        r: 0,
    }
}

pub struct HexDisc
 {
    origin: P,
    radius: i32,
    i: i32,
    r: i32,
}

impl
 Iterator for HexDisc

where
    P: Clone + Add<CellVector, Output = R>,
{
    type Item = R;

    fn next(&mut self) -> Option<Self::Item> {
        if self.r > self.radius {
            return None;
        }

        if self.r == 0 {
            self.r += 1;
            self.i = 0;
            return Some(self.origin.clone() + vec2(0, 0));
        }

        let sector = self.i / self.r;
        let offset = self.i % self.r;
        let rod = Dir6::from_int(sector);
        let tangent = Dir6::from_int(sector + 2);

        let ret = rod.to_v2() * self.r + tangent.to_v2() * offset;

        self.i += 1;
        if self.i >= 6 * self.r {
            self.i = 0;
            self.r += 1;
        }

        Some(self.origin.clone() + ret)
    }
}

/// Hex grid directions.
#[derive(Copy, Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum Dir6 {
    North = 0,
    Northeast,
    Southeast,
    South,
    Southwest,
    Northwest,
}

impl Dir6 {
    /// Convert a vector into the closest hex direction.
    ///
    /// ```notrust
    ///        *0*       *1*
    ///           \ 14 15 | 00 01
    ///           13\     |      02
    ///               \   |
    ///         12      \ |        03
    ///     *5* ----------O-X------- *2*
    ///         11        Y \      04
    ///                   |   \
    ///           10      |     \05
    ///             09 08 | 07 06 \
    ///                  *4*       *3*
    ///
    /// The hexadecants (00 to 15) and the hex
    /// directions (*0* to *5*) around the origin.
    /// ```
    ///
    /// Vectors that are in a space between two hex direction vectors are
    /// rounded to a hexadecant, then assigned the hex direction whose vector
    /// is nearest to that hexadecant.
    pub fn from_v2(v: CellVector) -> Dir6 {
        let hexadecant = {
            let width = PI / 8.0;
            let mut radian = (v.x as f32).atan2(-v.y as f32);
            if radian < 0.0 {
                radian += 2.0 * PI
            }
            (radian / width).floor() as i32
        };

        Dir6::from_int(match hexadecant {
            13 | 14 => 0,
            15 | 0 | 1 => 1,
            2 | 3 | 4 => 2,
            5 | 6 => 3,
            7 | 8 | 9 => 4,
            10 | 11 | 12 => 5,
            _ => panic!("Bad hexadecant"),
        })
    }

    /// Convert an integer to a hex dir using modular arithmetic.
    pub fn from_int(i: i32) -> Dir6 { DIRS[i.mod_floor(&6) as usize] }

    /// Convert a hex dir into the corresponding unit vector.
    pub fn to_v2(&self) -> CellVector { CellVector::from(*self) }

    /// Iterate through the six hex dirs in the standard order.
    pub fn iter() -> slice::Iter<'static, Dir6> { DIRS.iter() }
}

impl Add<i32> for Dir6 {
    type Output = Dir6;
    fn add(self, other: i32) -> Dir6 { Dir6::from_int(self as i32 + other) }
}

impl Sub<i32> for Dir6 {
    type Output = Dir6;
    fn sub(self, other: i32) -> Dir6 { Dir6::from_int(self as i32 - other) }
}

impl Distribution<Dir6> for Standard {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Dir6 { Dir6::from_int(rng.gen_range(0, 6)) }
}

impl From<Dir6> for CellVector {
    fn from(d: Dir6) -> Self {
        const DIRS: [(i32, i32); 6] = [(-1, -1), (0, -1), (1, 0), (1, 1), (0, 1), (-1, 0)];

        let (x, y) = DIRS[d as usize];
        vec2(x, y)
    }
}

static DIRS: [Dir6; 6] = [
    Dir6::North,
    Dir6::Northeast,
    Dir6::Southeast,
    Dir6::South,
    Dir6::Southwest,
    Dir6::Northwest,
];

/// Hex grid directions with transitional directions.
#[derive(Copy, Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum Dir12 {
    North = 0,
    NorthNortheast,
    Northeast,
    East,
    Southeast,
    SouthSoutheast,
    South,
    SouthSouthwest,
    Southwest,
    West,
    Northwest,
    NorthNorthwest,
}

impl Dir12 {
    /// If there is exactly one cluster of neighbors in the neighbor mask,
    /// return a direction pointing away from that cluster.
    pub fn away_from(neighbors: &[bool; 6]) -> Option<Dir12> {
        let (begin, end) = match find_cluster(neighbors) {
            Some((a, b)) => (a, b),
            None => return None,
        };

        if !is_single_cluster(neighbors, begin, end) {
            return None;
        }

        let cluster_size = if end < begin {
            end + 6 - begin
        } else {
            end - begin
        };
        debug_assert!(cluster_size > 0);

        // Dir12 in use from here on.
        let center_dir = begin * 2 + (cluster_size - 1);
        let away_dir: u8 = ((center_dir + 6) % 12) as u8;
        debug_assert!(away_dir < 12);

        // XXX: Unsafe because I'm too lazy to do int conversion func by hand.
        return Some(unsafe { ::std::mem::transmute(away_dir) });

        fn find_cluster(neighbors: &[bool; 6]) -> Option<(usize, usize)> {
            // Start of the active cluster, inclusive.
            let mut cluster_start = None;
            // End of the active cluster, exclusive.
            let mut cluster_end = None;

            for i in 0..6 {
                if cluster_start.is_none() && neighbors[i] && !neighbors[(i + 5) % 6] {
                    cluster_start = Some(i);
                }

                if cluster_end.is_none() && !neighbors[i] && neighbors[(i + 5) % 6] {
                    cluster_end = Some(i);
                }
            }

            Some((cluster_start?, cluster_end?))
        }

        fn is_single_cluster(neighbors: &[bool; 6], start: usize, end: usize) -> bool {
            let mut in_cluster = true;

            for i in 0..6 {
                if (start + i) % 6 == end {
                    in_cluster = false;
                }

                if neighbors[(start + i) % 6] != in_cluster {
                    return false;
                }
            }

            true
        }
    }
}

#[cfg(test)]
mod test {
    use super::hex_disc;
    use super::Dir12;
    use super::Dir6;
    use super::Dir6::*;
    use euclid::vec2;

    #[test]
    fn test_dir6() {
        assert_eq!(North, Dir6::from_int(0));
        assert_eq!(Northwest, Dir6::from_int(-1));
        assert_eq!(Northwest, Dir6::from_int(5));
        assert_eq!(Northeast, Dir6::from_int(1));

        assert_eq!(Northeast, Dir6::from_v2(vec2(20i32, -21i32)));
        assert_eq!(Southeast, Dir6::from_v2(vec2(20, -10)));
        assert_eq!(North, Dir6::from_v2(vec2(-10, -10)));
        assert_eq!(South, Dir6::from_v2(vec2(1, 1)));

        for i in 0..6 {
            let d = Dir6::from_int(i);
            let v = d.to_v2();
            let v1 = Dir6::from_int(i - 1).to_v2();
            let v2 = Dir6::from_int(i + 1).to_v2();

            // Test static iter
            assert_eq!(Some(d), Dir6::iter().nth(i as usize).map(|&x| x));

            // Test vector mapping.
            assert_eq!(d, Dir6::from_v2(v));

            // Test opposite dir vector mapping.
            assert_eq!(Dir6::from_int(i + 3), Dir6::from_v2(vec2(-v.x, -v.y)));

            // Test approximation of longer vectors.
            assert_eq!(d, Dir6::from_v2(vec2(v.x * 3, v.y * 3)));
            assert_eq!(d, Dir6::from_v2(vec2(v.x * 3 + v1.x, v.y * 3 + v1.y)));
            assert_eq!(d, Dir6::from_v2(vec2(v.x * 3 + v2.x, v.y * 3 + v2.y)));
        }
    }

    #[test]
    fn test_dir12() {
        assert_eq!(
            None,
            Dir12::away_from(&[false, false, false, false, false, false])
        );
        assert_eq!(
            None,
            Dir12::away_from(&[true, true, true, true, true, true])
        );
        assert_eq!(
            None,
            Dir12::away_from(&[false, true, false, false, true, false])
        );
        assert_eq!(
            None,
            Dir12::away_from(&[true, true, false, true, false, false])
        );
        assert_eq!(
            None,
            Dir12::away_from(&[true, false, true, false, true, false])
        );
        assert_eq!(
            Some(Dir12::South),
            Dir12::away_from(&[true, false, false, false, false, false])
        );
        assert_eq!(
            Some(Dir12::East),
            Dir12::away_from(&[true, false, false, true, true, true])
        );
        assert_eq!(
            Some(Dir12::SouthSouthwest),
            Dir12::away_from(&[true, true, false, false, false, false])
        );
        assert_eq!(
            Some(Dir12::Southwest),
            Dir12::away_from(&[true, true, true, false, false, false])
        );
        assert_eq!(
            Some(Dir12::SouthSoutheast),
            Dir12::away_from(&[true, true, false, false, true, true])
        );
    }

    #[test]
    fn test_hex_disc() {
        use super::HexGeom;
        use euclid::vec2;

        for y in -8i32..8 {
            for x in -8i32..8 {
                let vec = vec2(x, y);

                for r in 0..8 {
                    assert_eq!(
                        vec.hex_dist() <= r,
                        hex_disc(vec2(0, 0), r).find(|&v| vec == v).is_some()
                    );
                }
            }
        }
    }
}
<commit_msg>Dir6::is_fake_isometric<commit_after>use euclid::vec2;
use num::Integer;
use rand::distributions::{Distribution, Standard};
use rand::Rng;
use std::cmp::max;
use std::f32::consts::PI;
use std::ops::{Add, Sub};
use std::slice;
use CellVector;

/// Hex grid geometry for vectors.
pub trait HexGeom {
    /// Hex distance represented by a vector.
    fn hex_dist(&self) -> i32;
}

impl HexGeom for CellVector {
    fn hex_dist(&self) -> i32 {
        if self.x.signum() == self.y.signum() {
            max(self.x.abs(), self.y.abs())
        } else {
            self.x.abs() + self.y.abs()
        }
    }
}

/// Return offsets to neighboring hexes.
pub fn hex_neighbors
(origin: P) -> impl Iterator<Item = R>
where
    P: Clone + Add<CellVector, Output = R>,
{
    use Dir6::*;

    [North, Northeast, Southeast, South, Southwest, Northwest]
        .iter()
        .map(move |&d| origin.clone() + d.into())
}

/// Return offsets to the four cardinal directions.
///
/// These are also the fake-isometric directions on a hex map.
pub fn taxicab_neighbors
(origin: P) -> impl Iterator<Item = R>
where
    P: Clone + Add<CellVector, Output = R>,
{
    use Dir6::*;

    [Northeast, Southeast, Southwest, Northwest]
        .iter()
        .map(move |&d| origin.clone() + d.into())
}

/// Return an iterator for all the points in the hex disc with the given radius.
pub fn hex_disc
(origin: P, radius: i32) -> HexDisc

where
    P: Clone + Add<CellVector, Output = R>,
{
    HexDisc {
        origin,
        radius,
        i: 0,
        r: 0,
    }
}

pub struct HexDisc
 {
    origin: P,
    radius: i32,
    i: i32,
    r: i32,
}

impl
 Iterator for HexDisc

where
    P: Clone + Add<CellVector, Output = R>,
{
    type Item = R;

    fn next(&mut self) -> Option<Self::Item> {
        if self.r > self.radius {
            return None;
        }

        if self.r == 0 {
            self.r += 1;
            self.i = 0;
            return Some(self.origin.clone() + vec2(0, 0));
        }

        let sector = self.i / self.r;
        let offset = self.i % self.r;
        let rod = Dir6::from_int(sector);
        let tangent = Dir6::from_int(sector + 2);

        let ret = rod.to_v2() * self.r + tangent.to_v2() * offset;

        self.i += 1;
        if self.i >= 6 * self.r {
            self.i = 0;
            self.r += 1;
        }

        Some(self.origin.clone() + ret)
    }
}

/// Hex grid directions.
#[derive(Copy, Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum Dir6 {
    North = 0,
    Northeast,
    Southeast,
    South,
    Southwest,
    Northwest,
}

impl Dir6 {
    /// Convert a vector into the closest hex direction.
    ///
    /// ```notrust
    ///        *0*       *1*
    ///           \ 14 15 | 00 01
    ///           13\     |      02
    ///               \   |
    ///         12      \ |        03
    ///     *5* ----------O-X------- *2*
    ///         11        Y \      04
    ///                   |   \
    ///           10      |     \05
    ///             09 08 | 07 06 \
    ///                  *4*       *3*
    ///
    /// The hexadecants (00 to 15) and the hex
    /// directions (*0* to *5*) around the origin.
    /// ```
    ///
    /// Vectors that are in a space between two hex direction vectors are
    /// rounded to a hexadecant, then assigned the hex direction whose vector
    /// is nearest to that hexadecant.
    pub fn from_v2(v: CellVector) -> Dir6 {
        let hexadecant = {
            let width = PI / 8.0;
            let mut radian = (v.x as f32).atan2(-v.y as f32);
            if radian < 0.0 {
                radian += 2.0 * PI
            }
            (radian / width).floor() as i32
        };

        Dir6::from_int(match hexadecant {
            13 | 14 => 0,
            15 | 0 | 1 => 1,
            2 | 3 | 4 => 2,
            5 | 6 => 3,
            7 | 8 | 9 => 4,
            10 | 11 | 12 => 5,
            _ => panic!("Bad hexadecant"),
        })
    }

    /// Convert an integer to a hex dir using modular arithmetic.
    pub fn from_int(i: i32) -> Dir6 { DIRS[i.mod_floor(&6) as usize] }

    /// Convert a hex dir into the corresponding unit vector.
    pub fn to_v2(&self) -> CellVector { CellVector::from(*self) }

    /// Iterate through the six hex dirs in the standard order.
    pub fn iter() -> slice::Iter<'static, Dir6> { DIRS.iter() }

    /// Return whether the direction is along the axes used in fake isometric graphics.
    pub fn is_fake_isometric(self) -> bool {
        use Dir6::*;

        match self {
            Northeast | Southeast | Southwest | Northwest => true,
            North | South => false
        }
    }
}

impl Add<i32> for Dir6 {
    type Output = Dir6;
    fn add(self, other: i32) -> Dir6 { Dir6::from_int(self as i32 + other) }
}

impl Sub<i32> for Dir6 {
    type Output = Dir6;
    fn sub(self, other: i32) -> Dir6 { Dir6::from_int(self as i32 - other) }
}

impl Distribution<Dir6> for Standard {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Dir6 { Dir6::from_int(rng.gen_range(0, 6)) }
}

impl From<Dir6> for CellVector {
    fn from(d: Dir6) -> Self {
        const DIRS: [(i32, i32); 6] = [(-1, -1), (0, -1), (1, 0), (1, 1), (0, 1), (-1, 0)];

        let (x, y) = DIRS[d as usize];
        vec2(x, y)
    }
}

static DIRS: [Dir6; 6] = [
    Dir6::North,
    Dir6::Northeast,
    Dir6::Southeast,
    Dir6::South,
    Dir6::Southwest,
    Dir6::Northwest,
];

/// Hex grid directions with transitional directions.
#[derive(Copy, Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum Dir12 {
    North = 0,
    NorthNortheast,
    Northeast,
    East,
    Southeast,
    SouthSoutheast,
    South,
    SouthSouthwest,
    Southwest,
    West,
    Northwest,
    NorthNorthwest,
}

impl Dir12 {
    /// If there is exactly one cluster of neighbors in the neighbor mask,
    /// return a direction pointing away from that cluster.
    pub fn away_from(neighbors: &[bool; 6]) -> Option<Dir12> {
        let (begin, end) = match find_cluster(neighbors) {
            Some((a, b)) => (a, b),
            None => return None,
        };

        if !is_single_cluster(neighbors, begin, end) {
            return None;
        }

        let cluster_size = if end < begin {
            end + 6 - begin
        } else {
            end - begin
        };
        debug_assert!(cluster_size > 0);

        // Dir12 in use from here on.
        let center_dir = begin * 2 + (cluster_size - 1);
        let away_dir: u8 = ((center_dir + 6) % 12) as u8;
        debug_assert!(away_dir < 12);

        // XXX: Unsafe because I'm too lazy to do int conversion func by hand.
        return Some(unsafe { ::std::mem::transmute(away_dir) });

        fn find_cluster(neighbors: &[bool; 6]) -> Option<(usize, usize)> {
            // Start of the active cluster, inclusive.
            let mut cluster_start = None;
            // End of the active cluster, exclusive.
            let mut cluster_end = None;

            for i in 0..6 {
                if cluster_start.is_none() && neighbors[i] && !neighbors[(i + 5) % 6] {
                    cluster_start = Some(i);
                }

                if cluster_end.is_none() && !neighbors[i] && neighbors[(i + 5) % 6] {
                    cluster_end = Some(i);
                }
            }

            Some((cluster_start?, cluster_end?))
        }

        fn is_single_cluster(neighbors: &[bool; 6], start: usize, end: usize) -> bool {
            let mut in_cluster = true;

            for i in 0..6 {
                if (start + i) % 6 == end {
                    in_cluster = false;
                }

                if neighbors[(start + i) % 6] != in_cluster {
                    return false;
                }
            }

            true
        }
    }
}

#[cfg(test)]
mod test {
    use super::hex_disc;
    use super::Dir12;
    use super::Dir6;
    use super::Dir6::*;
    use euclid::vec2;

    #[test]
    fn test_dir6() {
        assert_eq!(North, Dir6::from_int(0));
        assert_eq!(Northwest, Dir6::from_int(-1));
        assert_eq!(Northwest, Dir6::from_int(5));
        assert_eq!(Northeast, Dir6::from_int(1));

        assert_eq!(Northeast, Dir6::from_v2(vec2(20i32, -21i32)));
        assert_eq!(Southeast, Dir6::from_v2(vec2(20, -10)));
        assert_eq!(North, Dir6::from_v2(vec2(-10, -10)));
        assert_eq!(South, Dir6::from_v2(vec2(1, 1)));

        for i in 0..6 {
            let d = Dir6::from_int(i);
            let v = d.to_v2();
            let v1 = Dir6::from_int(i - 1).to_v2();
            let v2 = Dir6::from_int(i + 1).to_v2();

            // Test static iter
            assert_eq!(Some(d), Dir6::iter().nth(i as usize).map(|&x| x));

            // Test vector mapping.
            assert_eq!(d, Dir6::from_v2(v));

            // Test opposite dir vector mapping.
            assert_eq!(Dir6::from_int(i + 3), Dir6::from_v2(vec2(-v.x, -v.y)));

            // Test approximation of longer vectors.
            assert_eq!(d, Dir6::from_v2(vec2(v.x * 3, v.y * 3)));
            assert_eq!(d, Dir6::from_v2(vec2(v.x * 3 + v1.x, v.y * 3 + v1.y)));
            assert_eq!(d, Dir6::from_v2(vec2(v.x * 3 + v2.x, v.y * 3 + v2.y)));
        }
    }

    #[test]
    fn test_dir12() {
        assert_eq!(
            None,
            Dir12::away_from(&[false, false, false, false, false, false])
        );
        assert_eq!(
            None,
            Dir12::away_from(&[true, true, true, true, true, true])
        );
        assert_eq!(
            None,
            Dir12::away_from(&[false, true, false, false, true, false])
        );
        assert_eq!(
            None,
            Dir12::away_from(&[true, true, false, true, false, false])
        );
        assert_eq!(
            None,
            Dir12::away_from(&[true, false, true, false, true, false])
        );
        assert_eq!(
            Some(Dir12::South),
            Dir12::away_from(&[true, false, false, false, false, false])
        );
        assert_eq!(
            Some(Dir12::East),
            Dir12::away_from(&[true, false, false, true, true, true])
        );
        assert_eq!(
            Some(Dir12::SouthSouthwest),
            Dir12::away_from(&[true, true, false, false, false, false])
        );
        assert_eq!(
            Some(Dir12::Southwest),
            Dir12::away_from(&[true, true, true, false, false, false])
        );
        assert_eq!(
            Some(Dir12::SouthSoutheast),
            Dir12::away_from(&[true, true, false, false, true, true])
        );
    }

    #[test]
    fn test_hex_disc() {
        use super::HexGeom;
        use euclid::vec2;

        for y in -8i32..8 {
            for x in -8i32..8 {
                let vec = vec2(x, y);

                for r in 0..8 {
                    assert_eq!(
                        vec.hex_dist() <= r,
                        hex_disc(vec2(0, 0), r).find(|&v| vec == v).is_some()
                    );
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use libc::c_void;

use parse_code;
use std::io::{self, Write};
use zstd_sys;

#[cfg(feature = "tokio")]
use futures::Poll;
#[cfg(feature = "tokio")]
use tokio_io::AsyncWrite;

struct EncoderContext {
    s: *mut zstd_sys::ZSTD_CStream,
}

impl Default for EncoderContext {
    fn default() -> Self {
        EncoderContext { s: unsafe { zstd_sys::ZSTD_createCStream() } }
    }
}

impl Drop for EncoderContext {
    fn drop(&mut self) {
        let code = unsafe { zstd_sys::ZSTD_freeCStream(self.s) };
        parse_code(code).unwrap();
    }
}

#[derive(PartialEq)]
enum EncoderState {
    Accepting,
    // Finished just makes sure writes are no longer accepted.
    Finished,
    StreamEnd,
    // The "stream ended and flushed" state corresponds to the object being
    // destroyed.
}

/// An encoder that compress and forward data to another writer.
///
/// This allows to compress a stream of data
/// (good for files or heavy network stream).
///
/// Don't forget to call `finish()` before dropping it!
///
/// Note: The zstd library has its own internal input buffer (~128kb).
pub struct Encoder<W: Write> {
    // output writer (compressed data)
    writer: W,
    // output buffer
    buffer: Vec<u8>,
    // offset in the output buffer
    offset: usize,

    // compression context
    context: EncoderContext,
    state: EncoderState,
}

/// A wrapper around an `Encoder<W>` that finishes the stream on drop.
pub struct AutoFinishEncoder<W: Write> {
    // We wrap this in an option to take it during drop.
    encoder: Option<Encoder<W>>,
    // TODO: make this a FnOnce once it works in a Box
    on_finish: Option<Box<FnMut(io::Result<W>)>>,
}

impl<W: Write> AutoFinishEncoder<W> {
    fn new<F: 'static + FnMut(io::Result<W>)>(encoder: Encoder<W>,
                                              on_finish: F)
                                              -> Self {
        AutoFinishEncoder {
            encoder: Some(encoder),
            on_finish: Some(Box::new(on_finish)),
        }
    }

    /// Acquires a reference to the underlying writer.
    pub fn get_ref(&self) -> &W {
        self.encoder.as_ref().unwrap().get_ref()
    }

    /// Acquires a mutable reference to the underlying writer.
    ///
    /// Note that mutation of the writer may result in surprising results if
    /// this encoder is continued to be used.
    pub fn get_mut(&mut self) -> &mut W {
        self.encoder.as_mut().unwrap().get_mut()
    }
}

impl<W: Write> Drop for AutoFinishEncoder<W> {
    fn drop(&mut self) {
        let result = self.encoder.take().unwrap().finish();
        if let Some(mut on_finish) = self.on_finish.take() {
            on_finish(result);
        }
    }
}

impl<W: Write> Write for AutoFinishEncoder<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.encoder.as_mut().unwrap().write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.encoder.as_mut().unwrap().flush()
    }
}

impl<W: Write> Encoder<W> {
    /// Creates a new encoder.
    ///
    /// `level`: compression level (1-21)
    pub fn new(writer: W, level: i32) -> io::Result<Self> {
        Self::with_dictionary(writer, level, &[])
    }

    /// Creates a new encoder, using an existing dictionary.
    ///
    /// (Provides better compression ratio for small files,
    /// but requires the dictionary to be present during decompression.)
    pub fn with_dictionary(writer: W, level: i32, dictionary: &[u8])
                           -> io::Result<Self> {
        let context = EncoderContext::default();

        // Initialize the stream with an existing dictionary
        parse_code(unsafe {
            zstd_sys::ZSTD_initCStream_usingDict(context.s,
                                           dictionary.as_ptr() as *const c_void,
                                           dictionary.len(),
                                           level)
        })?;

        Encoder::with_context(writer, context)
    }

    /// Returns a wrapper around `self` that will finish the stream on drop.
    ///
    /// # Panic
    ///
    /// Panics on drop if an error happens when finishing the stream.
    pub fn auto_finish(self) -> AutoFinishEncoder<W> {
        self.on_finish(|result| { result.unwrap(); })
    }

    /// Returns an encoder that will finish the stream on drop.
    ///
    /// Calls the given callback with the result from `finish()`.
    pub fn on_finish<F: 'static + FnMut(io::Result<W>)>
        (self, f: F)
         -> AutoFinishEncoder<W> {
        AutoFinishEncoder::new(self, f)
    }

    fn with_context(writer: W, context: EncoderContext) -> io::Result<Self> {
        // This is the output buffer size,
        // for compressed data we get from zstd.
        let buffer_size = unsafe { zstd_sys::ZSTD_CStreamOutSize() };

        Ok(Encoder {
               writer: writer,
               buffer: Vec::with_capacity(buffer_size),
               offset: 0,
               context: context,
               state: EncoderState::Accepting,
           })
    }

    /// Acquires a reference to the underlying writer.
    pub fn get_ref(&self) -> &W {
        &self.writer
    }

    /// Acquires a mutable reference to the underlying writer.
    ///
    /// Note that mutation of the writer may result in surprising results if
    /// this encoder is continued to be used.
    pub fn get_mut(&mut self) -> &mut W {
        &mut self.writer
    }

    /// Finishes the stream. You *need* to call this after writing your stuff.
    ///
    /// This returns the inner writer in case you need it.
    ///
    /// To get back `self` in case an error happened, use `try_finish`.
    ///
    /// **Note**: If you don't want (or can't) call `finish()` manually after writing your data,
    /// consider using `auto_finish()` to get an `AutoFinishEncoder`.
    pub fn finish(mut self) -> io::Result<W> {
        self.do_finish()?;
        // Return the writer, because why not
        Ok(self.writer)
    }

    /// Attempts to finish the stream. You *need* to call this after writing your stuff.
    ///
    /// This returns the inner writer if the finish was successful, or the
    /// object plus an error if it wasn't.
    ///
    /// `write` on this object will panic after `try_finish` has been called,
    /// even if it fails.
    pub fn try_finish(mut self) -> Result<W, (Self, io::Error)> {
        match self.do_finish() {
            Ok(()) => Ok(self.writer),
            Err(e) => Err((self, e)),
        }
    }

    fn do_finish(&mut self) -> io::Result<()> {
        if self.state == EncoderState::Accepting {
            // Write any data pending in `self.buffer`.
            self.write_from_offset()?;
            self.state = EncoderState::Finished;
        }

        if self.state == EncoderState::Finished {
            // First, closes the stream.
            let mut buffer = zstd_sys::ZSTD_outBuffer {
                dst: self.buffer.as_mut_ptr() as *mut c_void,
                size: self.buffer.capacity(),
                pos: 0,
            };
            let remaining = parse_code(unsafe {
                zstd_sys::ZSTD_endStream(self.context.s,
                                   &mut buffer as *mut zstd_sys::ZSTD_outBuffer)
            })?;
            unsafe {
                self.buffer.set_len(buffer.pos);
            }
            if remaining != 0 {
                // Need to flush?
                panic!("Need to flush, but I'm lazy.");
            }
            self.offset = 0;
            self.state = EncoderState::StreamEnd;
        }

        self.write_from_offset()?;

        Ok(())
    }

    /// Return a recommendation for the size of data to write at once.
    pub fn recommended_input_size() -> usize {
        unsafe { zstd_sys::ZSTD_CStreamInSize() }
    }

    /// write_all, except keep track of partial writes for non-blocking IO.
    fn write_from_offset(&mut self) -> io::Result<()> {
        while self.offset < self.buffer.len() {
            match self.writer.write(&self.buffer[self.offset..]) {
                Ok(n) => self.offset += n,
                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => (),
                Err(e) => return Err(e),
            }
        }
        Ok(())
    }
}

impl<W: Write> Write for Encoder<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        if self.state != EncoderState::Accepting {
            panic!("write called after try_finish attempted");
        }

        loop {
            // Write any data pending in `self.buffer`.
            self.write_from_offset()?;

            // If we get to here, `self.buffer` can safely be discarded.

            let mut in_buffer = zstd_sys::ZSTD_inBuffer {
                src: buf.as_ptr() as *const c_void,
                size: buf.len(),
                pos: 0,
            };

            let mut out_buffer = zstd_sys::ZSTD_outBuffer {
                dst: self.buffer.as_mut_ptr() as *mut c_void,
                size: self.buffer.capacity(),
                pos: 0,
            };

            unsafe {
                // Time to fill our output buffer
                let code =
                    zstd_sys::ZSTD_compressStream(self.context.s,
                                                  &mut out_buffer as
                                                  *mut zstd_sys::ZSTD_outBuffer,
                                                  &mut in_buffer as
                                                  *mut zstd_sys::ZSTD_inBuffer);
                // Note: this may very well be empty,
                // if it doesn't exceed zstd's own buffer
                self.buffer.set_len(out_buffer.pos);

                // Do we care about the hint?
                let _ = parse_code(code)?;
            }
            self.offset = 0;

            if in_buffer.pos > 0 || buf.len() == 0 {
                return Ok(in_buffer.pos);
            }
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        if self.state == EncoderState::Accepting {
            self.write_from_offset()?;

            let mut buffer = zstd_sys::ZSTD_outBuffer {
                dst: self.buffer.as_mut_ptr() as *mut c_void,
                size: self.buffer.capacity(),
                pos: 0,
            };
            unsafe {
                let code =
                    zstd_sys::ZSTD_flushStream(self.context.s,
                                               &mut buffer as
                                               *mut zstd_sys::ZSTD_outBuffer);
                self.buffer.set_len(buffer.pos);
                let _ = parse_code(code)?;
            }
            self.offset = 0;
        }

        self.write_from_offset()?;
        Ok(())
    }
}

#[cfg(feature = "tokio")]
impl <W: AsyncWrite> AsyncWrite for Encoder<W> {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        try_nb!(self.do_finish());
        self.writer.shutdown()
    }
}

#[cfg(test)]
mod tests {
    use super::Encoder;
    use stream::decode_all;
    use stream::tests::WritePartial;

    /// Test that flush after a partial write works successfully without
    /// corrupting the frame. This test is in this module because it checks
    /// internal implementation details.
    #[test]
    fn test_partial_write_flush() {
        use std::io::Write;

        let (input, mut z) = setup_partial_write();

        // flush shouldn't corrupt the stream
        z.flush().unwrap();

        let buf = z.finish().unwrap().into_inner();
        assert_eq!(&decode_all(&buf[..]).unwrap(), &input);
    }

    /// Test that finish after a partial write works successfully without
    /// corrupting the frame. This test is in this module because it checks
    /// internal implementation details.
    #[test]
    fn test_partial_write_finish() {
        let (input, z) = setup_partial_write();

        // finish shouldn't corrupt the stream
        let buf = z.finish().unwrap().into_inner();
        assert_eq!(&decode_all(&buf[..]).unwrap(), &input);
    }

    fn setup_partial_write() -> (Vec<u8>, Encoder<WritePartial>) {
        use std::io::Write;

        let mut buf = WritePartial::new();
        buf.accept(Some(1));
        let mut z = Encoder::new(buf, 1).unwrap();

        // Fill in enough data to make sure the buffer gets written out.
        let input = "b".repeat(128 * 1024).into_bytes();
        z.write(&input).unwrap();

        // At this point, the internal buffer in z should have some data.
        assert_ne!(z.offset, z.buffer.len());

        (input, z)
    }
}

#[cfg(test)]
#[cfg(feature = "tokio")]
mod async_tests {
    use std::io::{self, Cursor};
    use tokio_io::{AsyncWrite, AsyncRead, io as tokio_io};
    use futures::{Future, Poll, task, executor};

    struct BlockingWriter<T: AsyncWrite> {
        block: bool,
        writer: T,
    }

    impl<T: AsyncWrite> BlockingWriter<T> {
        fn new(writer: T)-> BlockingWriter<T> {
            BlockingWriter { block: false, writer: writer }
        }

        fn into_inner(self)-> T {
            self.writer
        }
    }

    impl<T: AsyncWrite> AsyncWrite for BlockingWriter<T> {
        fn shutdown(&mut self) -> Poll<(), io::Error> {
            self.writer.shutdown()
        }
    }

    impl<T: AsyncWrite> io::Write for BlockingWriter<T> {
        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
            if self.block {
                self.block = false;
                task::park().unpark();
                Err(io::Error::from(io::ErrorKind::WouldBlock))
            }
            else {
                self.block = true;
                self.writer.write(buf)
            }
        }
        fn flush(&mut self) -> io::Result<()> {
            Ok(())
        }
    }

    #[test]
    fn test_async_write() {
        use stream::decode_all;

        let source = "abc".repeat(1024 * 100).into_bytes();
        let encoded_output = test_async_write_worker(&source[..], Cursor::new(Vec::new()), |w| { w.into_inner() });
        let decoded = decode_all(&encoded_output[..]).unwrap();
        assert_eq!(source, &decoded[..]);
    }

    #[test]
    fn test_async_write_block() {
        use stream::decode_all;

        let source = "abc".repeat(1024 * 100).into_bytes();
        let encoded_output = test_async_write_worker(&source[..], BlockingWriter::new(Cursor::new(Vec::new())), |w| { w.into_inner().into_inner() });
        let decoded = decode_all(&encoded_output[..]).unwrap();
        assert_eq!(source, &decoded[..]);
    }

    fn test_async_write_worker<R: AsyncRead, W: AsyncWrite, Res, F: FnOnce(W) -> Res>(r: R, w: W, map: F) -> Res {
        use super::Encoder;

        let encoder = Encoder::new(w, 1).unwrap();
        let copy_future =
            tokio_io::copy(r, encoder)
            .map(|(_, _, encoder)| {
                let mut e = encoder;
                loop {
                    e = match e.try_finish() {
                        Ok(v) => return Ok(map(v)),
                        Err((encoder, err)) => {
                            if err.kind() == io::ErrorKind::WouldBlock {
                                encoder
                            }
                            else {
                                return Err(err);
                            }
                        }
                    }
                }
            });
        executor::spawn(copy_future).wait_future().unwrap().unwrap()
    }
}<commit_msg>use dedicate future type for Decoder::finish operation<commit_after>use libc::c_void;

use parse_code;
use std::io::{self, Write};
use zstd_sys;

#[cfg(feature = "tokio")]
use futures::Poll;
#[cfg(feature = "tokio")]
use tokio_io::AsyncWrite;

struct EncoderContext {
    s: *mut zstd_sys::ZSTD_CStream,
}

impl Default for EncoderContext {
    fn default() -> Self {
        EncoderContext { s: unsafe { zstd_sys::ZSTD_createCStream() } }
    }
}

impl Drop for EncoderContext {
    fn drop(&mut self) {
        let code = unsafe { zstd_sys::ZSTD_freeCStream(self.s) };
        parse_code(code).unwrap();
    }
}

#[derive(PartialEq)]
enum EncoderState {
    Accepting,
    // Finished just makes sure writes are no longer accepted.
    Finished,
    StreamEnd,
    // The "stream ended and flushed" state corresponds to the object being
    // destroyed.
}

/// An encoder that compress and forward data to another writer.
///
/// This allows to compress a stream of data
/// (good for files or heavy network stream).
///
/// Don't forget to call `finish()` before dropping it!
///
/// Note: The zstd library has its own internal input buffer (~128kb).
pub struct Encoder<W: Write> {
    // output writer (compressed data)
    writer: W,
    // output buffer
    buffer: Vec<u8>,
    // offset in the output buffer
    offset: usize,

    // compression context
    context: EncoderContext,
    state: EncoderState,
}

/// A wrapper around an `Encoder<W>` that finishes the stream on drop.
pub struct AutoFinishEncoder<W: Write> {
    // We wrap this in an option to take it during drop.
    encoder: Option<Encoder<W>>,
    // TODO: make this a FnOnce once it works in a Box
    on_finish: Option<Box<FnMut(io::Result<W>)>>,
}

impl<W: Write> AutoFinishEncoder<W> {
    fn new<F: 'static + FnMut(io::Result<W>)>(encoder: Encoder<W>,
                                              on_finish: F)
                                              -> Self {
        AutoFinishEncoder {
            encoder: Some(encoder),
            on_finish: Some(Box::new(on_finish)),
        }
    }

    /// Acquires a reference to the underlying writer.
    pub fn get_ref(&self) -> &W {
        self.encoder.as_ref().unwrap().get_ref()
    }

    /// Acquires a mutable reference to the underlying writer.
    ///
    /// Note that mutation of the writer may result in surprising results if
    /// this encoder is continued to be used.
    pub fn get_mut(&mut self) -> &mut W {
        self.encoder.as_mut().unwrap().get_mut()
    }
}

impl<W: Write> Drop for AutoFinishEncoder<W> {
    fn drop(&mut self) {
        let result = self.encoder.take().unwrap().finish();
        if let Some(mut on_finish) = self.on_finish.take() {
            on_finish(result);
        }
    }
}

impl<W: Write> Write for AutoFinishEncoder<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.encoder.as_mut().unwrap().write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.encoder.as_mut().unwrap().flush()
    }
}

impl<W: Write> Encoder<W> {
    /// Creates a new encoder.
    ///
    /// `level`: compression level (1-21)
    pub fn new(writer: W, level: i32) -> io::Result<Self> {
        Self::with_dictionary(writer, level, &[])
    }

    /// Creates a new encoder, using an existing dictionary.
    ///
    /// (Provides better compression ratio for small files,
    /// but requires the dictionary to be present during decompression.)
    pub fn with_dictionary(writer: W, level: i32, dictionary: &[u8])
                           -> io::Result<Self> {
        let context = EncoderContext::default();

        // Initialize the stream with an existing dictionary
        parse_code(unsafe {
            zstd_sys::ZSTD_initCStream_usingDict(context.s,
                                           dictionary.as_ptr() as *const c_void,
                                           dictionary.len(),
                                           level)
        })?;

        Encoder::with_context(writer, context)
    }

    /// Returns a wrapper around `self` that will finish the stream on drop.
    ///
    /// # Panic
    ///
    /// Panics on drop if an error happens when finishing the stream.
    pub fn auto_finish(self) -> AutoFinishEncoder<W> {
        self.on_finish(|result| { result.unwrap(); })
    }

    /// Returns an encoder that will finish the stream on drop.
    ///
    /// Calls the given callback with the result from `finish()`.
    pub fn on_finish<F: 'static + FnMut(io::Result<W>)>
        (self, f: F)
         -> AutoFinishEncoder<W> {
        AutoFinishEncoder::new(self, f)
    }

    fn with_context(writer: W, context: EncoderContext) -> io::Result<Self> {
        // This is the output buffer size,
        // for compressed data we get from zstd.
        let buffer_size = unsafe { zstd_sys::ZSTD_CStreamOutSize() };

        Ok(Encoder {
               writer: writer,
               buffer: Vec::with_capacity(buffer_size),
               offset: 0,
               context: context,
               state: EncoderState::Accepting,
           })
    }

    /// Acquires a reference to the underlying writer.
    pub fn get_ref(&self) -> &W {
        &self.writer
    }

    /// Acquires a mutable reference to the underlying writer.
    ///
    /// Note that mutation of the writer may result in surprising results if
    /// this encoder is continued to be used.
    pub fn get_mut(&mut self) -> &mut W {
        &mut self.writer
    }

    /// Finishes the stream. You *need* to call this after writing your stuff.
    ///
    /// This returns the inner writer in case you need it.
    ///
    /// To get back `self` in case an error happened, use `try_finish`.
    ///
    /// **Note**: If you don't want (or can't) call `finish()` manually after writing your data,
    /// consider using `auto_finish()` to get an `AutoFinishEncoder`.
    pub fn finish(mut self) -> io::Result<W> {
        self.do_finish()?;
        // Return the writer, because why not
        Ok(self.writer)
    }

    /// Attempts to finish the stream. You *need* to call this after writing your stuff.
    ///
    /// This returns the inner writer if the finish was successful, or the
    /// object plus an error if it wasn't.
    ///
    /// `write` on this object will panic after `try_finish` has been called,
    /// even if it fails.
    pub fn try_finish(mut self) -> Result<W, (Self, io::Error)> {
        match self.do_finish() {
            Ok(()) => Ok(self.writer),
            Err(e) => Err((self, e)),
        }
    }

    fn do_finish(&mut self) -> io::Result<()> {
        if self.state == EncoderState::Accepting {
            // Write any data pending in `self.buffer`.
            self.write_from_offset()?;
            self.state = EncoderState::Finished;
        }

        if self.state == EncoderState::Finished {
            // First, closes the stream.
            let mut buffer = zstd_sys::ZSTD_outBuffer {
                dst: self.buffer.as_mut_ptr() as *mut c_void,
                size: self.buffer.capacity(),
                pos: 0,
            };
            let remaining = parse_code(unsafe {
                zstd_sys::ZSTD_endStream(self.context.s,
                                   &mut buffer as *mut zstd_sys::ZSTD_outBuffer)
            })?;
            unsafe {
                self.buffer.set_len(buffer.pos);
            }
            if remaining != 0 {
                // Need to flush?
                panic!("Need to flush, but I'm lazy.");
            }
            self.offset = 0;
            self.state = EncoderState::StreamEnd;
        }

        self.write_from_offset()?;

        Ok(())
    }

    /// Return a recommendation for the size of data to write at once.
    pub fn recommended_input_size() -> usize {
        unsafe { zstd_sys::ZSTD_CStreamInSize() }
    }

    /// write_all, except keep track of partial writes for non-blocking IO.
    fn write_from_offset(&mut self) -> io::Result<()> {
        while self.offset < self.buffer.len() {
            match self.writer.write(&self.buffer[self.offset..]) {
                Ok(n) => self.offset += n,
                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => (),
                Err(e) => return Err(e),
            }
        }
        Ok(())
    }
}

impl<W: Write> Write for Encoder<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        if self.state != EncoderState::Accepting {
            panic!("write called after try_finish attempted");
        }

        loop {
            // Write any data pending in `self.buffer`.
            self.write_from_offset()?;

            // If we get to here, `self.buffer` can safely be discarded.

            let mut in_buffer = zstd_sys::ZSTD_inBuffer {
                src: buf.as_ptr() as *const c_void,
                size: buf.len(),
                pos: 0,
            };

            let mut out_buffer = zstd_sys::ZSTD_outBuffer {
                dst: self.buffer.as_mut_ptr() as *mut c_void,
                size: self.buffer.capacity(),
                pos: 0,
            };

            unsafe {
                // Time to fill our output buffer
                let code =
                    zstd_sys::ZSTD_compressStream(self.context.s,
                                                  &mut out_buffer as
                                                  *mut zstd_sys::ZSTD_outBuffer,
                                                  &mut in_buffer as
                                                  *mut zstd_sys::ZSTD_inBuffer);
                // Note: this may very well be empty,
                // if it doesn't exceed zstd's own buffer
                self.buffer.set_len(out_buffer.pos);

                // Do we care about the hint?
                let _ = parse_code(code)?;
            }
            self.offset = 0;

            if in_buffer.pos > 0 || buf.len() == 0 {
                return Ok(in_buffer.pos);
            }
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        if self.state == EncoderState::Accepting {
            self.write_from_offset()?;

            let mut buffer = zstd_sys::ZSTD_outBuffer {
                dst: self.buffer.as_mut_ptr() as *mut c_void,
                size: self.buffer.capacity(),
                pos: 0,
            };
            unsafe {
                let code =
                    zstd_sys::ZSTD_flushStream(self.context.s,
                                               &mut buffer as
                                               *mut zstd_sys::ZSTD_outBuffer);
                self.buffer.set_len(buffer.pos);
                let _ = parse_code(code)?;
            }
            self.offset = 0;
        }

        self.write_from_offset()?;
        Ok(())
    }
}

#[cfg(feature = "tokio")]
impl <W: AsyncWrite> AsyncWrite for Encoder<W> {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        try_nb!(self.do_finish());
        self.writer.shutdown()
    }
}

#[cfg(test)]
mod tests {
    use super::Encoder;
    use stream::decode_all;
    use stream::tests::WritePartial;

    /// Test that flush after a partial write works successfully without
    /// corrupting the frame. This test is in this module because it checks
    /// internal implementation details.
    #[test]
    fn test_partial_write_flush() {
        use std::io::Write;

        let (input, mut z) = setup_partial_write();

        // flush shouldn't corrupt the stream
        z.flush().unwrap();

        let buf = z.finish().unwrap().into_inner();
        assert_eq!(&decode_all(&buf[..]).unwrap(), &input);
    }

    /// Test that finish after a partial write works successfully without
    /// corrupting the frame. This test is in this module because it checks
    /// internal implementation details.
    #[test]
    fn test_partial_write_finish() {
        let (input, z) = setup_partial_write();

        // finish shouldn't corrupt the stream
        let buf = z.finish().unwrap().into_inner();
        assert_eq!(&decode_all(&buf[..]).unwrap(), &input);
    }

    fn setup_partial_write() -> (Vec<u8>, Encoder<WritePartial>) {
        use std::io::Write;

        let mut buf = WritePartial::new();
        buf.accept(Some(1));
        let mut z = Encoder::new(buf, 1).unwrap();

        // Fill in enough data to make sure the buffer gets written out.
        let input = "b".repeat(128 * 1024).into_bytes();
        z.write(&input).unwrap();

        // At this point, the internal buffer in z should have some data.
        assert_ne!(z.offset, z.buffer.len());

        (input, z)
    }
}

#[cfg(test)]
#[cfg(feature = "tokio")]
mod async_tests {
    use std::io::{self, Cursor};
    use tokio_io::{AsyncWrite, AsyncRead, io as tokio_io};
    use futures::{Future, Poll, task, executor};

    struct BlockingWriter<T: AsyncWrite> {
        block: bool,
        writer: T,
    }

    impl<T: AsyncWrite> BlockingWriter<T> {
        fn new(writer: T)-> BlockingWriter<T> {
            BlockingWriter { block: false, writer: writer }
        }

        fn into_inner(self)-> T {
            self.writer
        }
    }

    impl<T: AsyncWrite> AsyncWrite for BlockingWriter<T> {
        fn shutdown(&mut self) -> Poll<(), io::Error> {
            self.writer.shutdown()
        }
    }

    impl<T: AsyncWrite> io::Write for BlockingWriter<T> {
        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
            if self.block {
                self.block = false;
                task::park().unpark();
                Err(io::Error::from(io::ErrorKind::WouldBlock))
            }
            else {
                self.block = true;
                self.writer.write(buf)
            }
        }
        fn flush(&mut self) -> io::Result<()> {
            Ok(())
        }
    }

    #[test]
    fn test_async_write() {
        use stream::decode_all;

        let source = "abc".repeat(1024 * 100).into_bytes();
        let encoded_output = test_async_write_worker(&source[..], Cursor::new(Vec::new()), |w| { w.into_inner() });
        let decoded = decode_all(&encoded_output[..]).unwrap();
        assert_eq!(source, &decoded[..]);
    }

    #[test]
    fn test_async_write_block() {
        use stream::decode_all;

        let source = "abc".repeat(1024 * 100).into_bytes();
        let encoded_output = test_async_write_worker(&source[..], BlockingWriter::new(Cursor::new(Vec::new())), |w| { w.into_inner().into_inner() });
        let decoded = decode_all(&encoded_output[..]).unwrap();
        assert_eq!(source, &decoded[..]);
    }

    struct Finish<W: AsyncWrite> {
        encoder: Option<super::Encoder<W>>,
    }

    impl<W: AsyncWrite> Future for Finish<W> {
        type Item = W;
        type Error = io::Error;

        fn poll(&mut self) -> Poll<W, io::Error> {
            use futures::Async;

            match self.encoder.take().unwrap().try_finish() {
                Ok(v) => {
                    return Ok(v.into())
                },
                Err((encoder, err)) => {
                    if err.kind() == io::ErrorKind::WouldBlock {
                        self.encoder = Some(encoder);
                        return Ok(Async::NotReady);
                    }
                    else {
                        return Err(err)
                    }
                },
            };
        }
    }

    fn test_async_write_worker<R: AsyncRead, W: AsyncWrite, Res, F: FnOnce(W) -> Res>(r: R, w: W, f: F) -> Res {
        use super::Encoder;

        let encoder = Encoder::new(w, 1).unwrap();
        let copy_future =
            tokio_io::copy(r, encoder)
            .and_then(| (_, _, encoder) | {
                Finish { encoder: Some (encoder) }
            })
            .map(f);
        executor::spawn(copy_future).wait_future().unwrap()
    }
}<|endoftext|>


<commit_before>// Copyright 2013-2014 The Num-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![allow(missing_docs)]

use structure::MonoidMultiplicativeApprox;
use structure::MonoidMultiplicative;
use structure::GroupAdditiveAbelianApprox;
use structure::GroupAdditiveAbelian;
use structure::GroupMultiplicativeAbelian;
use structure::GroupMultiplicativeAbelianApprox;

pub trait RingApprox
    : GroupAdditiveAbelianApprox
    + MonoidMultiplicativeApprox
{
    /// Returns `true` if the multiplication and addition operators are approximately distributive for
    /// the given argument tuple.
    fn prop_mul_and_add_are_distributive_approx(args: (Self, Self, Self)) -> bool {
        let (a, b, c) = args;
        // Left distributivity
        a.clone() * (b.clone() + c.clone()) == (a.clone() * b.clone()) + (a.clone() * c.clone()) &&
        // Right distributivity
        (b.clone() + c.clone()) * a.clone() == (b * a.clone()) + (c * a)
    }
}

impl RingApprox for i8   {}
impl RingApprox for i16  {}
impl RingApprox for i32  {}
impl RingApprox for i64  {}

pub trait Ring
    : RingApprox
    + GroupAdditiveAbelian
    + MonoidMultiplicative
{
    /// Returns `true` if the multiplication and addition operators are distributive for
    /// the given argument tuple.
    fn prop_mul_and_add_are_distributive(args: (Self, Self, Self)) -> bool {
        let (a, b, c) = args;
        // Left distributivity
        a.clone() * (b.clone() + c.clone()) == (a.clone() * b.clone()) + (a.clone() * c.clone()) &&
        // Right distributivity
        (b.clone() + c.clone()) * a.clone() == (b * a.clone()) + (c * a)
    }
}

impl Ring for i8   {}
impl Ring for i16  {}
impl Ring for i32  {}
impl Ring for i64  {}

pub trait RingCommutativeApprox
    : RingApprox
{
    /// Returns `true` if the multiplication operator is approximately commutative for
    /// the given argument tuple.
    fn prop_mul_is_commutative_approx(args: (Self, Self)) -> bool {
        let (a, b) = args;
        a.clone() * b.clone() == b * a
    }
}

impl RingCommutativeApprox for i8   {}
impl RingCommutativeApprox for i16  {}
impl RingCommutativeApprox for i32  {}
impl RingCommutativeApprox for i64  {}

pub trait RingCommutative
    : RingApprox
    + Ring
{
    /// Returns `true` if the multiplication operator is commutative for
    /// the given argument tuple.
    fn prop_mul_is_commutative(args: (Self, Self)) -> bool {
        let (a, b) = args;
        a.clone() * b.clone() == b * a
    }
}

impl RingCommutative for i8   {}
impl RingCommutative for i16  {}
impl RingCommutative for i32  {}
impl RingCommutative for i64  {}

pub trait FieldApprox
    : RingCommutativeApprox
    + GroupMultiplicativeAbelianApprox
{}

pub trait Field
    : FieldApprox
    + RingCommutative
    + GroupMultiplicativeAbelian
{}
<commit_msg>Fixed commutative ring.<commit_after>// Copyright 2013-2014 The Num-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![allow(missing_docs)]

use structure::MonoidMultiplicativeApprox;
use structure::MonoidMultiplicative;
use structure::GroupAdditiveAbelianApprox;
use structure::GroupAdditiveAbelian;
use structure::GroupMultiplicativeAbelian;
use structure::GroupMultiplicativeAbelianApprox;

pub trait RingApprox
    : GroupAdditiveAbelianApprox
    + MonoidMultiplicativeApprox
{
    /// Returns `true` if the multiplication and addition operators are approximately distributive for
    /// the given argument tuple.
    fn prop_mul_and_add_are_distributive_approx(args: (Self, Self, Self)) -> bool {
        let (a, b, c) = args;
        // Left distributivity
        a.clone() * (b.clone() + c.clone()) == (a.clone() * b.clone()) + (a.clone() * c.clone()) &&
        // Right distributivity
        (b.clone() + c.clone()) * a.clone() == (b * a.clone()) + (c * a)
    }
}

impl RingApprox for i8   {}
impl RingApprox for i16  {}
impl RingApprox for i32  {}
impl RingApprox for i64  {}

pub trait Ring
    : RingApprox
    + GroupAdditiveAbelian
    + MonoidMultiplicative
{
    /// Returns `true` if the multiplication and addition operators are distributive for
    /// the given argument tuple.
    fn prop_mul_and_add_are_distributive(args: (Self, Self, Self)) -> bool {
        let (a, b, c) = args;
        // Left distributivity
        a.clone() * (b.clone() + c.clone()) == (a.clone() * b.clone()) + (a.clone() * c.clone()) &&
        // Right distributivity
        (b.clone() + c.clone()) * a.clone() == (b * a.clone()) + (c * a)
    }
}

impl Ring for i8   {}
impl Ring for i16  {}
impl Ring for i32  {}
impl Ring for i64  {}

pub trait RingCommutativeApprox
    : RingApprox
{
    /// Returns `true` if the multiplication operator is approximately commutative for
    /// the given argument tuple.
    fn prop_mul_is_commutative_approx(args: (Self, Self)) -> bool {
        let (a, b) = args;
        a.clone() * b.clone() == b * a
    }
}

impl RingCommutativeApprox for i8   {}
impl RingCommutativeApprox for i16  {}
impl RingCommutativeApprox for i32  {}
impl RingCommutativeApprox for i64  {}

pub trait RingCommutative
    : RingCommutativeApprox
    + Ring
{
    /// Returns `true` if the multiplication operator is commutative for
    /// the given argument tuple.
    fn prop_mul_is_commutative(args: (Self, Self)) -> bool {
        let (a, b) = args;
        a.clone() * b.clone() == b * a
    }
}

impl RingCommutative for i8   {}
impl RingCommutative for i16  {}
impl RingCommutative for i32  {}
impl RingCommutative for i64  {}

pub trait FieldApprox
    : RingCommutativeApprox
    + GroupMultiplicativeAbelianApprox
{}

pub trait Field
    : FieldApprox
    + RingCommutative
    + GroupMultiplicativeAbelian
{}
<|endoftext|>


<commit_before>#[cfg(any(target_os = "linux", target_os = "android"))]
mod eventfd {
    use crate::sys::Selector;
    use crate::{Interest, Token};

    use std::fs::File;
    use std::io::{self, Read, Write};
    use std::os::unix::io::FromRawFd;

    /// Waker backed by `eventfd`.
    ///
    /// `eventfd` is effectively an 64 bit counter. All writes must be of 8
    /// bytes (64 bits) and are converted (native endian) into an 64 bit
    /// unsigned integer and added to the count. Reads must also be 8 bytes and
    /// reset the count to 0, returning the count.
    #[derive(Debug)]
    pub struct Waker {
        fd: File,
    }

    impl Waker {
        pub fn new(selector: &Selector, token: Token) -> io::Result<Waker> {
            syscall!(eventfd(0, libc::EFD_CLOEXEC | libc::EFD_NONBLOCK)).and_then(|fd| {
                // Turn the file descriptor into a file first so we're ensured
                // it's closed when dropped, e.g. when register below fails.
                let file = unsafe { File::from_raw_fd(fd) };
                selector
                    .register(fd, token, Interest::READABLE)
                    .map(|()| Waker { fd: file })
            })
        }

        pub fn wake(&self) -> io::Result<()> {
            let buf: [u8; 8] = 1u64.to_ne_bytes();
            match (&self.fd).write(&buf) {
                Ok(_) => Ok(()),
                Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
                    // Writing only blocks if the counter is going to overflow.
                    // So we'll reset the counter to 0 and wake it again.
                    self.reset()?;
                    self.wake()
                }
                Err(err) => Err(err),
            }
        }

        /// Reset the eventfd object, only need to call this if `wake` fails.
        fn reset(&self) -> io::Result<()> {
            let mut buf: [u8; 8] = 0u64.to_ne_bytes();
            match (&self.fd).read(&mut buf) {
                Ok(_) => Ok(()),
                // If the `Waker` hasn't been awoken yet this will return a
                // `WouldBlock` error which we can safely ignore.
                Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => Ok(()),
                Err(err) => Err(err),
            }
        }
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub use self::eventfd::Waker;

#[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))]
mod kqueue {
    use crate::sys::Selector;
    use crate::Token;

    use std::io;

    /// Waker backed by kqueue user space notifications (`EVFILT_USER`).
    ///
    /// The implementation is fairly simple, first the kqueue must be setup to
    /// receive waker events this done by calling `Selector.setup_waker`. Next
    /// we need access to kqueue, thus we need to duplicate the file descriptor.
    /// Now waking is as simple as adding an event to the kqueue.
    #[derive(Debug)]
    pub struct Waker {
        selector: Selector,
        token: Token,
    }

    impl Waker {
        pub fn new(selector: &Selector, token: Token) -> io::Result<Waker> {
            selector.try_clone().and_then(|selector| {
                selector
                    .setup_waker(token)
                    .map(|()| Waker { selector, token })
            })
        }

        pub fn wake(&self) -> io::Result<()> {
            self.selector.wake(self.token)
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))]
pub use self::kqueue::Waker;

#[cfg(any(
    target_os = "dragonfly",
    target_os = "illumos",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
mod pipe {
    use crate::sys::unix::Selector;
    use crate::{Interest, Token};

    use std::fs::File;
    use std::io::{self, Read, Write};
    use std::os::unix::io::FromRawFd;

    /// Waker backed by a unix pipe.
    ///
    /// Waker controls both the sending and receiving ends and empties the pipe
    /// if writing to it (waking) fails.
    #[derive(Debug)]
    pub struct Waker {
        sender: File,
        receiver: File,
    }

    impl Waker {
        pub fn new(selector: &Selector, token: Token) -> io::Result<Waker> {
            let mut fds = [-1; 2];
            syscall!(pipe2(fds.as_mut_ptr(), libc::O_NONBLOCK | libc::O_CLOEXEC))?;
            // Turn the file descriptors into files first so we're ensured
            // they're closed when dropped, e.g. when register below fails.
            let sender = unsafe { File::from_raw_fd(fds[1]) };
            let receiver = unsafe { File::from_raw_fd(fds[0]) };
            selector
                .register(fds[0], token, Interest::READABLE)
                .map(|()| Waker { sender, receiver })
        }

        pub fn wake(&self) -> io::Result<()> {
            match (&self.sender).write(&[1]) {
                Ok(_) => Ok(()),
                Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
                    // The reading end is full so we'll empty the buffer and try
                    // again.
                    self.empty();
                    self.wake()
                }
                Err(ref err) if err.kind() == io::ErrorKind::Interrupted => self.wake(),
                Err(err) => Err(err),
            }
        }

        /// Empty the pipe's buffer, only need to call this if `wake` fails.
        /// This ignores any errors.
        fn empty(&self) {
            let mut buf = [0; 4096];
            loop {
                match (&self.receiver).read(&mut buf) {
                    Ok(n) if n > 0 => continue,
                    _ => return,
                }
            }
        }
    }
}

#[cfg(any(
    target_os = "dragonfly",
    target_os = "illumos",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
pub use self::pipe::Waker;
<commit_msg>illumos epoll may not wake up unless pipe is empty<commit_after>#[cfg(any(target_os = "linux", target_os = "android"))]
mod eventfd {
    use crate::sys::Selector;
    use crate::{Interest, Token};

    use std::fs::File;
    use std::io::{self, Read, Write};
    use std::os::unix::io::FromRawFd;

    /// Waker backed by `eventfd`.
    ///
    /// `eventfd` is effectively an 64 bit counter. All writes must be of 8
    /// bytes (64 bits) and are converted (native endian) into an 64 bit
    /// unsigned integer and added to the count. Reads must also be 8 bytes and
    /// reset the count to 0, returning the count.
    #[derive(Debug)]
    pub struct Waker {
        fd: File,
    }

    impl Waker {
        pub fn new(selector: &Selector, token: Token) -> io::Result<Waker> {
            syscall!(eventfd(0, libc::EFD_CLOEXEC | libc::EFD_NONBLOCK)).and_then(|fd| {
                // Turn the file descriptor into a file first so we're ensured
                // it's closed when dropped, e.g. when register below fails.
                let file = unsafe { File::from_raw_fd(fd) };
                selector
                    .register(fd, token, Interest::READABLE)
                    .map(|()| Waker { fd: file })
            })
        }

        pub fn wake(&self) -> io::Result<()> {
            let buf: [u8; 8] = 1u64.to_ne_bytes();
            match (&self.fd).write(&buf) {
                Ok(_) => Ok(()),
                Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
                    // Writing only blocks if the counter is going to overflow.
                    // So we'll reset the counter to 0 and wake it again.
                    self.reset()?;
                    self.wake()
                }
                Err(err) => Err(err),
            }
        }

        /// Reset the eventfd object, only need to call this if `wake` fails.
        fn reset(&self) -> io::Result<()> {
            let mut buf: [u8; 8] = 0u64.to_ne_bytes();
            match (&self.fd).read(&mut buf) {
                Ok(_) => Ok(()),
                // If the `Waker` hasn't been awoken yet this will return a
                // `WouldBlock` error which we can safely ignore.
                Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => Ok(()),
                Err(err) => Err(err),
            }
        }
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub use self::eventfd::Waker;

#[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))]
mod kqueue {
    use crate::sys::Selector;
    use crate::Token;

    use std::io;

    /// Waker backed by kqueue user space notifications (`EVFILT_USER`).
    ///
    /// The implementation is fairly simple, first the kqueue must be setup to
    /// receive waker events this done by calling `Selector.setup_waker`. Next
    /// we need access to kqueue, thus we need to duplicate the file descriptor.
    /// Now waking is as simple as adding an event to the kqueue.
    #[derive(Debug)]
    pub struct Waker {
        selector: Selector,
        token: Token,
    }

    impl Waker {
        pub fn new(selector: &Selector, token: Token) -> io::Result<Waker> {
            selector.try_clone().and_then(|selector| {
                selector
                    .setup_waker(token)
                    .map(|()| Waker { selector, token })
            })
        }

        pub fn wake(&self) -> io::Result<()> {
            self.selector.wake(self.token)
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))]
pub use self::kqueue::Waker;

#[cfg(any(
    target_os = "dragonfly",
    target_os = "illumos",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
mod pipe {
    use crate::sys::unix::Selector;
    use crate::{Interest, Token};

    use std::fs::File;
    use std::io::{self, Read, Write};
    use std::os::unix::io::FromRawFd;

    /// Waker backed by a unix pipe.
    ///
    /// Waker controls both the sending and receiving ends and empties the pipe
    /// if writing to it (waking) fails.
    #[derive(Debug)]
    pub struct Waker {
        sender: File,
        receiver: File,
    }

    impl Waker {
        pub fn new(selector: &Selector, token: Token) -> io::Result<Waker> {
            let mut fds = [-1; 2];
            syscall!(pipe2(fds.as_mut_ptr(), libc::O_NONBLOCK | libc::O_CLOEXEC))?;
            // Turn the file descriptors into files first so we're ensured
            // they're closed when dropped, e.g. when register below fails.
            let sender = unsafe { File::from_raw_fd(fds[1]) };
            let receiver = unsafe { File::from_raw_fd(fds[0]) };
            selector
                .register(fds[0], token, Interest::READABLE)
                .map(|()| Waker { sender, receiver })
        }

        pub fn wake(&self) -> io::Result<()> {
            // The epoll emulation on some illumos systems currently requires
            // the pipe buffer to be completely empty for an edge-triggered
            // wakeup on the pipe read side.
            #[cfg(target_os = "illumos")]
            self.empty();

            match (&self.sender).write(&[1]) {
                Ok(_) => Ok(()),
                Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
                    // The reading end is full so we'll empty the buffer and try
                    // again.
                    self.empty();
                    self.wake()
                }
                Err(ref err) if err.kind() == io::ErrorKind::Interrupted => self.wake(),
                Err(err) => Err(err),
            }
        }

        /// Empty the pipe's buffer, only need to call this if `wake` fails.
        /// This ignores any errors.
        fn empty(&self) {
            let mut buf = [0; 4096];
            loop {
                match (&self.receiver).read(&mut buf) {
                    Ok(n) if n > 0 => continue,
                    _ => return,
                }
            }
        }
    }
}

#[cfg(any(
    target_os = "dragonfly",
    target_os = "illumos",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
pub use self::pipe::Waker;
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::fmt;
use std::path::{Path, PathBuf};
use std::result::Result as StdResult;
use std::str;

use java_properties;
use toml;
use walkdir::{DirEntry, WalkDir, WalkDirIterator};

use super::errors::*;
use super::format::Style;
use super::fsutils;
use super::template::{Params, Template};

#[derive(Debug)]
pub struct Project {
    pub root_path: Option<String>,
    pub config_format: ConfigFormat,
    pub style: Style,
    pub force_packaged: bool,
}

#[derive(Copy, Clone, Debug)]
pub enum ConfigFormat {
    JavaProps,
    Toml,
}

impl fmt::Display for ConfigFormat {
    fn fmt(&self, f: &mut fmt::Formatter) -> StdResult<(), fmt::Error> {
        let name = match *self {
            ConfigFormat::JavaProps => "default.properties",
            ConfigFormat::Toml => "_rig.toml",
        };
        write!(f, "{}", &name)
    }
}

impl Default for Project {
    fn default() -> Project {
        Project {
            root_path: None,
            config_format: ConfigFormat::Toml,
            style: Style::Simple,
            force_packaged: false,
        }
    }
}

impl Project {
    pub fn new<S>(root: Option<S>, config_format: ConfigFormat, packaged: bool) -> Project
        where S: AsRef<str>
    {
        Project {
            root_path: root.map(|v| v.as_ref().to_owned()),
            config_format: config_format,
            style: Style::Simple,
            force_packaged: packaged,
        }
    }

    pub fn new_g8(root: Option<&str>) -> Project {
        Project {
            root_path: root.map(|v| v.to_string()),
            config_format: ConfigFormat::JavaProps,
            style: Style::Giter8,
            force_packaged: true,
        }
    }

    pub fn set_root_dir(&mut self, root: &str) -> &mut Project {
        self.root_path = Some(root.into());
        self
    }

    pub fn resolve_root_dir(&self, clone_root: &Path) -> PathBuf {
        let mut buf = clone_root.to_path_buf();

        if let Some(ref inner) = self.root_path {
            if fsutils::exists(clone_root.join(inner)) {
                buf.push(inner);
            }
        }
        buf
    }

    pub fn default_params(&self, clone_root: &Path) -> Result<Params> {
        let root = self.resolve_root_dir(clone_root);
        get_defaults(self, &root)
    }

    // TODO: give clear `Err` type
    // TODO: make it run async
    pub fn generate(&self,
                    params: &Params,
                    clone_root: &Path,
                    dest: &Path,
                    dry_run: bool)
                    -> Result<()> {

        let root = self.resolve_root_dir(clone_root);
        let walker = WalkDir::new(&root).into_iter();

        let mut file_map: HashMap<OsString, String> = HashMap::new();
        let default_file = root.join(format!("{}", &self.config_format));

        if !dry_run {
            fs::create_dir_all(dest).unwrap();
        }

        for entry in walker.filter_entry(|e| !is_git_metadata(e)) {
            let entry = entry.unwrap();

            if entry.path() == &root || entry.path() == &default_file {
                debug!("skipping {:?}", entry.file_name());
                continue;
            }

            let mut segment: Vec<&OsStr> = Vec::new();
            let mut rel_path_up = entry.path().parent();
            let mut upwards = 1;
            while let Some(parent) = rel_path_up {
                if upwards >= entry.depth() {
                    break;
                } else {
                    segment.push(parent.file_name().unwrap_or("".as_ref()));
                }
                upwards += 1;
                rel_path_up = parent.parent();
            }

            let base = entry.file_name();
            let mut dest = dest.to_path_buf();
            if !segment.is_empty() {
                segment.reverse();
                for part in segment {
                    if let Some(rep) = file_map.get(part) {
                        debug!("File tree altered: {:?} => {:?}", part, rep);
                        dest.push(rep);
                    } else {
                        dest.push(part);
                    }
                }
            }

            let mut buf = Vec::new();
            // FIXME: we need to re-design `Template` so we can manipulate its elements
            if "$package$" == base.to_string_lossy().as_ref() && self.force_packaged {
                Template::compile_inline(&mut buf,
                                         Style::Pathname,
                                         "$package__packaged$",
                                         &params.param_map)
                    .unwrap();
            } else {
                Template::compile_inline(&mut buf,
                                         Style::Pathname,
                                         &base.to_string_lossy(),
                                         &params.param_map)
                    .unwrap();
            }

            let name = String::from_utf8(buf).unwrap();
            if &name != base.to_string_lossy().as_ref() {
                file_map.insert(base.to_os_string(), name.clone());
            }
            dest.push(&name);
            debug!("Destination entry: {:?}", dest);

            // TODO:
            if !dry_run {
                if entry.file_type().is_file() {
                    let mut tpl = Template::read_file(self.style.clone(), &entry.path()).unwrap();
                    let mut f = fs::OpenOptions::new()
                        .write(true)
                        .truncate(true)
                        .create(true)
                        .open(dest.as_path())
                        .unwrap();

                    tpl.write(&mut f, &params.param_map).unwrap();
                    f.sync_data().unwrap();
                } else if entry.file_type().is_dir() {
                    fs::create_dir_all(dest.as_path()).expect("Failed to copy directory");
                }
            }
        }
        debug!("{:?}", &file_map);

        Ok(())
    }
}

fn is_git_metadata(entry: &DirEntry) -> bool {
    let is_git = entry.file_name().to_str().map(|s| s == ".git").unwrap_or(false);
    fsutils::is_directory(entry.path()) && is_git
}

fn get_defaults(project: &Project, root_dir: &Path) -> Result<Params> {
    let defaults_file = root_dir.join(format!("{}", project.config_format));

    match project.config_format {
        ConfigFormat::JavaProps => {
            fs::File::open(&defaults_file)
                .map(|f| {
                    let props = java_properties::read(f).unwrap();
                    Params::from_map(props)
                })
                .map_err(|e| ErrorKind::Io(e).into())
        }
        ConfigFormat::Toml => {
            fsutils::read_file(&defaults_file)
                .map(|s| {
                    let mut parser = toml::Parser::new(&s);
                    let tbl = parser.parse().unwrap();
                    Params::convert_toml(&tbl)
                })
                .chain_err(|| ErrorKind::TomlDecodeFailure)
        }
    }
}
<commit_msg>project: now configuration file name is &'static str instead of String<commit_after>use std::collections::HashMap;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::path::{Path, PathBuf};
use std::str;

use java_properties;
use toml;
use walkdir::{DirEntry, WalkDir, WalkDirIterator};

use super::errors::*;
use super::format::Style;
use super::fsutils;
use super::template::{Params, Template};

#[derive(Debug)]
pub struct Project {
    pub root_path: Option<String>,
    pub config_format: ConfigFormat,
    pub style: Style,
    pub force_packaged: bool,
}

#[derive(Copy, Clone, Debug)]
pub enum ConfigFormat {
    JavaProps,
    Toml,
}

impl Default for Project {
    fn default() -> Project {
        Project {
            root_path: None,
            config_format: ConfigFormat::Toml,
            style: Style::Simple,
            force_packaged: false,
        }
    }
}

impl Project {
    pub fn new<S>(root: Option<S>, config_format: ConfigFormat, packaged: bool) -> Project
        where S: AsRef<str>
    {
        Project {
            root_path: root.map(|v| v.as_ref().to_owned()),
            config_format: config_format,
            style: Style::Simple,
            force_packaged: packaged,
        }
    }

    pub fn new_g8(root: Option<&str>) -> Project {
        Project {
            root_path: root.map(|v| v.to_string()),
            config_format: ConfigFormat::JavaProps,
            style: Style::Giter8,
            force_packaged: true,
        }
    }

    pub fn config_name(&self) -> &'static str {
        match self.config_format {
            ConfigFormat::JavaProps => "default.properties",
            ConfigFormat::Toml => "_rig.toml",
        }
    }

    pub fn set_root_dir(&mut self, root: &str) -> &mut Project {
        self.root_path = Some(root.into());
        self
    }

    pub fn resolve_root_dir(&self, clone_root: &Path) -> PathBuf {
        let mut buf = clone_root.to_path_buf();

        if let Some(ref inner) = self.root_path {
            if fsutils::exists(clone_root.join(inner)) {
                buf.push(inner);
            }
        }
        buf
    }

    pub fn default_params(&self, clone_root: &Path) -> Result<Params> {
        let root = self.resolve_root_dir(clone_root);
        get_defaults(self, &root)
    }

    // TODO: give clear `Err` type
    // TODO: make it run async
    pub fn generate(&self,
                    params: &Params,
                    clone_root: &Path,
                    dest: &Path,
                    dry_run: bool)
                    -> Result<()> {

        let root = self.resolve_root_dir(clone_root);
        let walker = WalkDir::new(&root).into_iter();

        let mut file_map: HashMap<OsString, String> = HashMap::new();
        let default_file = root.join(self.config_name());

        if !dry_run {
            fs::create_dir_all(dest).unwrap();
        }

        for entry in walker.filter_entry(|e| !is_git_metadata(e)) {
            let entry = entry.unwrap();

            if entry.path() == &root || entry.path() == &default_file {
                debug!("skipping {:?}", entry.file_name());
                continue;
            }

            let mut segment: Vec<&OsStr> = Vec::new();
            let mut rel_path_up = entry.path().parent();
            let mut upwards = 1;
            while let Some(parent) = rel_path_up {
                if upwards >= entry.depth() {
                    break;
                } else {
                    segment.push(parent.file_name().unwrap_or("".as_ref()));
                }
                upwards += 1;
                rel_path_up = parent.parent();
            }

            let base = entry.file_name();
            let mut dest = dest.to_path_buf();
            if !segment.is_empty() {
                segment.reverse();
                for part in segment {
                    if let Some(rep) = file_map.get(part) {
                        debug!("File tree altered: {:?} => {:?}", part, rep);
                        dest.push(rep);
                    } else {
                        dest.push(part);
                    }
                }
            }

            let mut buf = Vec::new();
            // FIXME: we need to re-design `Template` so we can manipulate its elements
            if "$package$" == base.to_string_lossy().as_ref() && self.force_packaged {
                Template::compile_inline(&mut buf,
                                         Style::Pathname,
                                         "$package__packaged$",
                                         &params.param_map)
                    .unwrap();
            } else {
                Template::compile_inline(&mut buf,
                                         Style::Pathname,
                                         &base.to_string_lossy(),
                                         &params.param_map)
                    .unwrap();
            }

            let name = String::from_utf8(buf).unwrap();
            if &name != base.to_string_lossy().as_ref() {
                file_map.insert(base.to_os_string(), name.clone());
            }
            dest.push(&name);
            debug!("Destination entry: {:?}", dest);

            // TODO:
            if !dry_run {
                if entry.file_type().is_file() {
                    let mut tpl = Template::read_file(self.style.clone(), &entry.path()).unwrap();
                    let mut f = fs::OpenOptions::new()
                        .write(true)
                        .truncate(true)
                        .create(true)
                        .open(dest.as_path())
                        .unwrap();

                    tpl.write(&mut f, &params.param_map).unwrap();
                    f.sync_data().unwrap();
                } else if entry.file_type().is_dir() {
                    fs::create_dir_all(dest.as_path()).expect("Failed to copy directory");
                }
            }
        }
        debug!("{:?}", &file_map);

        Ok(())
    }
}

fn is_git_metadata(entry: &DirEntry) -> bool {
    let is_git = entry.file_name().to_str().map(|s| s == ".git").unwrap_or(false);
    fsutils::is_directory(entry.path()) && is_git
}

fn get_defaults(project: &Project, root_dir: &Path) -> Result<Params> {
    let defaults_file = root_dir.join(project.config_name());

    match project.config_format {
        ConfigFormat::JavaProps => {
            fs::File::open(&defaults_file)
                .map(|f| {
                    let props = java_properties::read(f).unwrap();
                    Params::from_map(props)
                })
                .map_err(|e| ErrorKind::Io(e).into()) // Should convert ParseError
        }
        ConfigFormat::Toml => {
            fsutils::read_file(&defaults_file)
                .map(|s| {
                    let mut parser = toml::Parser::new(&s);
                    let tbl = parser.parse().unwrap();
                    Params::convert_toml(&tbl)
                })
                .chain_err(|| ErrorKind::TomlDecodeFailure)
        }
    }
}
<|endoftext|>


<commit_before>extern crate lapin_async as lapin;

use std::net::TcpStream;
use std::{thread,time};

use lapin::types::*;
use lapin::connection::*;
use lapin::buffer::Buffer;
use lapin::generated::basic;

#[test]
fn connection() {
      let mut stream = TcpStream::connect("127.0.0.1:5672").unwrap();
      stream.set_nonblocking(true).unwrap();

      let capacity = 8192;
      let mut send_buffer    = Buffer::with_capacity(capacity as usize);
      let mut receive_buffer = Buffer::with_capacity(capacity as usize);

      let mut conn: Connection = Connection::new();
      conn.set_frame_max(capacity);
      assert_eq!(conn.connect().unwrap(), ConnectionState::Connecting(ConnectingState::SentProtocolHeader));
      loop {
        match conn.run(&mut stream, &mut send_buffer, &mut receive_buffer) {
          Err(e) => panic!("could not connect: {:?}", e),
          Ok(ConnectionState::Connected) => break,
          Ok(state) => println!("now at state {:?}, continue", state),
        }
        thread::sleep(time::Duration::from_millis(100));
      }
      println!("CONNECTED");

      //now connected

      let frame_max = conn.configuration.frame_max;
      if frame_max > capacity {
        send_buffer.grow(frame_max as usize);
        receive_buffer.grow(frame_max as usize);
      }

      let channel_a: u16 = conn.create_channel().unwrap();
      let channel_b: u16 = conn.create_channel().unwrap();
      //send channel
      conn.channel_open(channel_a, "".to_string()).expect("channel_open");
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());
      thread::sleep(time::Duration::from_millis(100));
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());

      //receive channel
      conn.channel_open(channel_b, "".to_string()).expect("channel_open");
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());
      thread::sleep(time::Duration::from_millis(100));
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());

      //create the hello queue
      conn.queue_declare(channel_a, 0, "hello-async".to_string(), false, false, false, false, false, FieldTable::new()).expect("queue_declare");
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());
      thread::sleep(time::Duration::from_millis(100));
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());

      //purge the hello queue in case it already exists with contents in it
      conn.queue_purge(channel_a, 0, "hello-async".to_string(), false).expect("queue_purge");
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());
      thread::sleep(time::Duration::from_millis(100));
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());

      conn.queue_declare(channel_b, 0, "hello-async".to_string(), false, false, false, false, false, FieldTable::new()).expect("queue_declare");
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());
      thread::sleep(time::Duration::from_millis(100));
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());

      println!("will consume");
      conn.basic_consume(channel_b, 0, "hello-async".to_string(), "my_consumer".to_string(), false, true, false, false, FieldTable::new()).expect("basic_consume");
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());
      thread::sleep(time::Duration::from_millis(100));
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());

      println!("will publish");
      conn.basic_publish(channel_a, 0, "".to_string(), "hello-async".to_string(), false, false).expect("basic_publish");
      let payload = b"Hello world!";
      conn.send_content_frames(channel_a, 60, payload, basic::Properties::default());
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());
      thread::sleep(time::Duration::from_millis(100));
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());
      let msg = conn.next_delivery(channel_b, "hello-async", "my_consumer").unwrap();
      println!("received message: {:?}", msg);
      println!("data: {}", std::str::from_utf8(&msg.data).unwrap());

      assert_eq!(msg.data, b"Hello world!");
}
<commit_msg>init env_logger in test<commit_after>extern crate env_logger;
extern crate lapin_async as lapin;

use std::net::TcpStream;
use std::{thread,time};

use lapin::types::*;
use lapin::connection::*;
use lapin::buffer::Buffer;
use lapin::generated::basic;

#[test]
fn connection() {
      env_logger::init();

      let mut stream = TcpStream::connect("127.0.0.1:5672").unwrap();
      stream.set_nonblocking(true).unwrap();

      let capacity = 8192;
      let mut send_buffer    = Buffer::with_capacity(capacity as usize);
      let mut receive_buffer = Buffer::with_capacity(capacity as usize);

      let mut conn: Connection = Connection::new();
      conn.set_frame_max(capacity);
      assert_eq!(conn.connect().unwrap(), ConnectionState::Connecting(ConnectingState::SentProtocolHeader));
      loop {
        match conn.run(&mut stream, &mut send_buffer, &mut receive_buffer) {
          Err(e) => panic!("could not connect: {:?}", e),
          Ok(ConnectionState::Connected) => break,
          Ok(state) => println!("now at state {:?}, continue", state),
        }
        thread::sleep(time::Duration::from_millis(100));
      }
      println!("CONNECTED");

      //now connected

      let frame_max = conn.configuration.frame_max;
      if frame_max > capacity {
        send_buffer.grow(frame_max as usize);
        receive_buffer.grow(frame_max as usize);
      }

      let channel_a: u16 = conn.create_channel().unwrap();
      let channel_b: u16 = conn.create_channel().unwrap();
      //send channel
      conn.channel_open(channel_a, "".to_string()).expect("channel_open");
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());
      thread::sleep(time::Duration::from_millis(100));
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());

      //receive channel
      conn.channel_open(channel_b, "".to_string()).expect("channel_open");
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());
      thread::sleep(time::Duration::from_millis(100));
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());

      //create the hello queue
      conn.queue_declare(channel_a, 0, "hello-async".to_string(), false, false, false, false, false, FieldTable::new()).expect("queue_declare");
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());
      thread::sleep(time::Duration::from_millis(100));
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());

      //purge the hello queue in case it already exists with contents in it
      conn.queue_purge(channel_a, 0, "hello-async".to_string(), false).expect("queue_purge");
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());
      thread::sleep(time::Duration::from_millis(100));
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());

      conn.queue_declare(channel_b, 0, "hello-async".to_string(), false, false, false, false, false, FieldTable::new()).expect("queue_declare");
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());
      thread::sleep(time::Duration::from_millis(100));
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());

      println!("will consume");
      conn.basic_consume(channel_b, 0, "hello-async".to_string(), "my_consumer".to_string(), false, true, false, false, FieldTable::new()).expect("basic_consume");
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());
      thread::sleep(time::Duration::from_millis(100));
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());

      println!("will publish");
      conn.basic_publish(channel_a, 0, "".to_string(), "hello-async".to_string(), false, false).expect("basic_publish");
      let payload = b"Hello world!";
      conn.send_content_frames(channel_a, 60, payload, basic::Properties::default());
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());
      thread::sleep(time::Duration::from_millis(100));
      println!("[{}] state: {:?}", line!(), conn.run(&mut stream, &mut send_buffer, &mut receive_buffer).unwrap());
      let msg = conn.next_delivery(channel_b, "hello-async", "my_consumer").unwrap();
      println!("received message: {:?}", msg);
      println!("data: {}", std::str::from_utf8(&msg.data).unwrap());

      assert_eq!(msg.data, b"Hello world!");
}
<|endoftext|>


<commit_before>extern crate demon;
use demon::Demon;
use demon::DemonRunner;

fn main() {
	let demon = Demon {
		name: "Example".to_string()
	};
	demon.run();
}

<commit_msg>Add simple example<commit_after>#![feature(io)]
#![feature(env)]
#![feature(path)]

extern crate demon;
use demon::Demon;
use demon::DemonRunner;
use std::env;
use std::old_io::{File, Open, ReadWrite, IoError, SeekStyle};

fn main() {
	log("Example started.");
	let demon = Demon {
		name: "Example".to_string()
	};
	demon.run();
	log("Example finished.");
}

fn log(message: &str) -> Result<(), IoError> {
	let path = try! (env::current_exe()).with_extension("log");
	let mut file = try! (File::open_mode(&path, Open, ReadWrite));
	try! (file.seek(0, SeekStyle::SeekEnd));
	try! (file.write_line(message));
	Ok(())
}
<|endoftext|>