<commit_before>use super::{Cell, Mesh, Point};

/// Holds samples of meshes
pub struct Samples;

impl Samples {
    /// Returns two quadrilaterals along the horizontal
    ///
    /// ```text
    /// 1.0  3-----------2-----------5
    ///      |           |           |
    ///      |    [0]    |    [1]    |  [*] indicates id
    ///      |    (1)    |    (2)    |  (*) indicates attribute_id
    ///      |           |           |
    /// 0.0  0-----------1-----------4
    ///     0.0         1.0         2.0
    /// ```
    #[rustfmt::skip]
    pub fn two_quads_horizontal() -> Mesh {
        Mesh {
            space_ndim: 2,
            points: vec![
                Point { id: 0, coords: vec![0.0, 0.0] },
                Point { id: 1, coords: vec![1.0, 0.0] },
                Point { id: 2, coords: vec![1.0, 1.0] },
                Point { id: 3, coords: vec![0.0, 1.0] },
                Point { id: 4, coords: vec![2.0, 0.0] },
                Point { id: 5, coords: vec![2.0, 1.0] },
            ],
            cells: vec![
                Cell { id: 0, attribute_id: 1, geo_ndim: 2, points: vec![0, 1, 2, 3] },
                Cell { id: 1, attribute_id: 2, geo_ndim: 2, points: vec![1, 4, 5, 2] },
            ],
        }
    }

    /// Returns two cubes along the vertical
    ///
    /// ```text
    ///           8-------------11
    ///          /.             /|
    ///         / .            / |
    ///        /  .           /  |
    ///       /   .          /   |       id = 1
    /// 2.0  9-------------10    |       attribute_id = 2
    ///      |    .         |    |
    ///      |    4---------|----7
    ///      |   /.         |   /|
    ///      |  / .         |  / |
    ///      | /  .         | /  |
    ///      |/   .         |/   |
    /// 1.0  5--------------6    |       id = 0
    ///      |    .         |    |       attribute_id = 1
    ///      |    0---------|----3  0.0
    ///      |   /          |   /
    ///      |  /           |  /
    ///      | /            | /
    ///      |/             |/
    /// 0.0  1--------------2   1.0
    ///     0.0            1.0
    /// ```
    #[rustfmt::skip]
    pub fn two_cubes_vertical() -> Mesh {
        Mesh {
            space_ndim: 3,
            points: vec![
                Point { id:  0, coords: vec![0.0, 0.0, 0.0] },
                Point { id:  1, coords: vec![1.0, 0.0, 0.0] },
                Point { id:  2, coords: vec![1.0, 1.0, 0.0] },
                Point { id:  3, coords: vec![0.0, 1.0, 0.0] },
                Point { id:  4, coords: vec![0.0, 0.0, 1.0] },
                Point { id:  5, coords: vec![1.0, 0.0, 1.0] },
                Point { id:  6, coords: vec![1.0, 1.0, 1.0] },
                Point { id:  7, coords: vec![0.0, 1.0, 1.0] },
                Point { id:  8, coords: vec![0.0, 0.0, 2.0] },
                Point { id:  9, coords: vec![1.0, 0.0, 2.0] },
                Point { id: 10, coords: vec![1.0, 1.0, 2.0] },
                Point { id: 11, coords: vec![0.0, 1.0, 2.0] },
            ],
            cells: vec![
                Cell { id: 0, attribute_id: 1, geo_ndim: 3, points: vec![0,1,2,3, 4,5,6,7] },
                Cell { id: 1, attribute_id: 2, geo_ndim: 3, points: vec![4,5,6,7, 8,9,10,11] },
            ],
        }
    }

    /// Returns a mesh with mixed shapes in 2D
    ///
    /// ```text
    /// 1.0              4-----------3
    ///                  |           |
    ///                  |    [1]    |   [*] indicates id
    ///                  |    (2)    |   (*) indicates attribute_id
    ///                  |           |
    /// 0.0  0-----------1-----------2
    ///           [0]
    ///           (1)
    ///
    ///     0.0         1.0         2.0
    /// ```
    #[rustfmt::skip]
    pub fn mixed_shapes_2d() -> Mesh {
        Mesh {
            space_ndim: 2,
            points: vec![
                Point { id: 0, coords: vec![0.0, 0.0] },
                Point { id: 1, coords: vec![1.0, 0.0] },
                Point { id: 2, coords: vec![2.0, 0.0] },
                Point { id: 3, coords: vec![2.0, 1.0] },
                Point { id: 4, coords: vec![1.0, 1.0] },
            ],
            cells: vec![
                Cell { id: 0, attribute_id: 1, geo_ndim: 1, points: vec![0, 1] },
                Cell { id: 1, attribute_id: 2, geo_ndim: 2, points: vec![1, 2, 3, 4] },
            ],
        }
    }

    /// Returns a mesh with mixed shapes in 3D
    ///
    /// ```text
    ///                       4------------7-----------10
    ///                      /.           /|            |
    ///                     / .          / |            |
    ///                    /  .         /  |            |
    ///                   /   .        /   |            |
    ///                  5------------6    |            |
    ///                  |    .       |`.  |            |
    ///                  |    0-------|--`.3------------9
    ///                  |   /        |   /`.          /
    ///                  |  /         |  /   `.       /
    ///                  | /          | /      `.    /
    ///                  |/           |/         `. /
    ///  12-----11-------1------------2------------8
    /// ```
    #[rustfmt::skip]
    pub fn mixed_shapes_3d() -> Mesh {
        Mesh {
            space_ndim: 3,
            points: vec![
                Point { id: 0, coords: vec![0.0, 0.0, 0.0] },
                Point { id: 1, coords: vec![1.0, 0.0, 0.0] },
                Point { id: 2, coords: vec![1.0, 1.0, 0.0] },
                Point { id: 3, coords: vec![0.0, 1.0, 0.0] },
                Point { id: 4, coords: vec![0.0, 0.0, 1.0] },
                Point { id: 5, coords: vec![1.0, 0.0, 1.0] },
                Point { id: 6, coords: vec![1.0, 1.0, 1.0] },
                Point { id: 7, coords: vec![0.0, 1.0, 1.0] },
                Point { id: 8, coords: vec![1.0, 2.0, 0.0] },
                Point { id: 9, coords: vec![0.0, 2.0, 0.0] },
                Point { id:10, coords: vec![0.0, 2.0, 1.0] },
                Point { id:11, coords: vec![1.0,-0.5, 0.0] },
                Point { id:12, coords: vec![1.0,-1.0, 0.0] },
            ],
            cells: vec![
                Cell { id: 0, attribute_id: 1, geo_ndim: 3, points: vec![0,1,2,3,4,5,6,7] },
                Cell { id: 1, attribute_id: 2, geo_ndim: 3, points: vec![2,8,3,6] },
                Cell { id: 2, attribute_id: 2, geo_ndim: 2, points: vec![3,9,10,7] },
                Cell { id: 3, attribute_id: 2, geo_ndim: 2, points: vec![8,9,3] },
                Cell { id: 4, attribute_id: 3, geo_ndim: 1, points: vec![1,11,12] },
            ],
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

    #[test]
    fn samples_work() {
        let mesh = Samples::two_quads_horizontal();
        assert_eq!(mesh.space_ndim, 2);
        assert_eq!(mesh.points.len(), 6);
        assert_eq!(mesh.cells.len(), 2);

        let mesh = Samples::two_cubes_vertical();
        assert_eq!(mesh.space_ndim, 3);
        assert_eq!(mesh.points.len(), 12);
        assert_eq!(mesh.cells.len(), 2);

        let mesh = Samples::mixed_shapes_2d();
        assert_eq!(mesh.space_ndim, 2);
        assert_eq!(mesh.points.len(), 5);
        assert_eq!(mesh.cells.len(), 2);

        let mesh = Samples::mixed_shapes_3d();
        assert_eq!(mesh.space_ndim, 3);
        assert_eq!(mesh.points.len(), 13);
        assert_eq!(mesh.cells.len(), 5);
    }
}
<commit_msg>Add note<commit_after>use super::{Cell, Mesh, Point};

/// Holds samples of meshes
pub struct Samples;

impl Samples {
    /// Returns two quadrilaterals along the horizontal
    ///
    /// ```text
    /// 1.0  3-----------2-----------5
    ///      |           |           |
    ///      |    [0]    |    [1]    |  [*] indicates id
    ///      |    (1)    |    (2)    |  (*) indicates attribute_id
    ///      |           |           |
    /// 0.0  0-----------1-----------4
    ///     0.0         1.0         2.0
    /// ```
    #[rustfmt::skip]
    pub fn two_quads_horizontal() -> Mesh {
        Mesh {
            space_ndim: 2,
            points: vec![
                Point { id: 0, coords: vec![0.0, 0.0] },
                Point { id: 1, coords: vec![1.0, 0.0] },
                Point { id: 2, coords: vec![1.0, 1.0] },
                Point { id: 3, coords: vec![0.0, 1.0] },
                Point { id: 4, coords: vec![2.0, 0.0] },
                Point { id: 5, coords: vec![2.0, 1.0] },
            ],
            cells: vec![
                Cell { id: 0, attribute_id: 1, geo_ndim: 2, points: vec![0, 1, 2, 3] },
                Cell { id: 1, attribute_id: 2, geo_ndim: 2, points: vec![1, 4, 5, 2] },
            ],
        }
    }

    /// Returns two cubes along the vertical
    ///
    /// ```text
    ///           8-------------11
    ///          /.             /|
    ///         / .            / |
    ///        /  .           /  |
    ///       /   .          /   |       id = 1
    /// 2.0  9-------------10    |       attribute_id = 2
    ///      |    .         |    |
    ///      |    4---------|----7
    ///      |   /.         |   /|
    ///      |  / .         |  / |
    ///      | /  .         | /  |
    ///      |/   .         |/   |
    /// 1.0  5--------------6    |       id = 0
    ///      |    .         |    |       attribute_id = 1
    ///      |    0---------|----3  0.0
    ///      |   /          |   /
    ///      |  /           |  /
    ///      | /            | /
    ///      |/             |/
    /// 0.0  1--------------2   1.0
    ///     0.0            1.0
    /// ```
    #[rustfmt::skip]
    pub fn two_cubes_vertical() -> Mesh {
        Mesh {
            space_ndim: 3,
            points: vec![
                Point { id:  0, coords: vec![0.0, 0.0, 0.0] },
                Point { id:  1, coords: vec![1.0, 0.0, 0.0] },
                Point { id:  2, coords: vec![1.0, 1.0, 0.0] },
                Point { id:  3, coords: vec![0.0, 1.0, 0.0] },
                Point { id:  4, coords: vec![0.0, 0.0, 1.0] },
                Point { id:  5, coords: vec![1.0, 0.0, 1.0] },
                Point { id:  6, coords: vec![1.0, 1.0, 1.0] },
                Point { id:  7, coords: vec![0.0, 1.0, 1.0] },
                Point { id:  8, coords: vec![0.0, 0.0, 2.0] },
                Point { id:  9, coords: vec![1.0, 0.0, 2.0] },
                Point { id: 10, coords: vec![1.0, 1.0, 2.0] },
                Point { id: 11, coords: vec![0.0, 1.0, 2.0] },
            ],
            cells: vec![
                Cell { id: 0, attribute_id: 1, geo_ndim: 3, points: vec![0,1,2,3, 4,5,6,7] },
                Cell { id: 1, attribute_id: 2, geo_ndim: 3, points: vec![4,5,6,7, 8,9,10,11] },
            ],
        }
    }

    /// Returns a mesh with mixed shapes in 2D
    ///
    /// ```text
    /// 1.0              4-----------3
    ///                  |           |
    ///                  |    [1]    |   [*] indicates id
    ///                  |    (2)    |   (*) indicates attribute_id
    ///                  |           |
    /// 0.0  0-----------1-----------2
    ///           [0]
    ///           (1)
    ///
    ///     0.0         1.0         2.0
    /// ```
    #[rustfmt::skip]
    pub fn mixed_shapes_2d() -> Mesh {
        Mesh {
            space_ndim: 2,
            points: vec![
                Point { id: 0, coords: vec![0.0, 0.0] },
                Point { id: 1, coords: vec![1.0, 0.0] },
                Point { id: 2, coords: vec![2.0, 0.0] },
                Point { id: 3, coords: vec![2.0, 1.0] },
                Point { id: 4, coords: vec![1.0, 1.0] },
            ],
            cells: vec![
                Cell { id: 0, attribute_id: 1, geo_ndim: 1, points: vec![0, 1] },
                Cell { id: 1, attribute_id: 2, geo_ndim: 2, points: vec![1, 2, 3, 4] },
            ],
        }
    }

    /// Returns a mesh with mixed shapes in 3D
    ///
    /// ```text
    /// Note: the tetrahedron (2,8,3,6) is incompatible
    ///                       4------------7-----------10
    ///                      /.           /|            |
    ///                     / .          / |            |
    ///                    /  .         /  |            |
    ///                   /   .        /   |            |
    ///                  5------------6    |            |
    ///                  |    .       |`.  |            |
    ///                  |    0-------|--`.3------------9
    ///                  |   /        |   /`.          /
    ///                  |  /         |  /   `.       /
    ///                  | /          | /      `.    /
    ///                  |/           |/         `. /
    ///  12-----11-------1------------2------------8
    /// ```
    #[rustfmt::skip]
    pub fn mixed_shapes_3d() -> Mesh {
        Mesh {
            space_ndim: 3,
            points: vec![
                Point { id: 0, coords: vec![0.0, 0.0, 0.0] },
                Point { id: 1, coords: vec![1.0, 0.0, 0.0] },
                Point { id: 2, coords: vec![1.0, 1.0, 0.0] },
                Point { id: 3, coords: vec![0.0, 1.0, 0.0] },
                Point { id: 4, coords: vec![0.0, 0.0, 1.0] },
                Point { id: 5, coords: vec![1.0, 0.0, 1.0] },
                Point { id: 6, coords: vec![1.0, 1.0, 1.0] },
                Point { id: 7, coords: vec![0.0, 1.0, 1.0] },
                Point { id: 8, coords: vec![1.0, 2.0, 0.0] },
                Point { id: 9, coords: vec![0.0, 2.0, 0.0] },
                Point { id:10, coords: vec![0.0, 2.0, 1.0] },
                Point { id:11, coords: vec![1.0,-0.5, 0.0] },
                Point { id:12, coords: vec![1.0,-1.0, 0.0] },
            ],
            cells: vec![
                Cell { id: 0, attribute_id: 1, geo_ndim: 3, points: vec![0,1,2,3,4,5,6,7] },
                Cell { id: 1, attribute_id: 2, geo_ndim: 3, points: vec![2,8,3,6] },
                Cell { id: 2, attribute_id: 2, geo_ndim: 2, points: vec![3,9,10,7] },
                Cell { id: 3, attribute_id: 2, geo_ndim: 2, points: vec![8,9,3] },
                Cell { id: 4, attribute_id: 3, geo_ndim: 1, points: vec![1,11,12] },
            ],
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

    #[test]
    fn samples_work() {
        let mesh = Samples::two_quads_horizontal();
        assert_eq!(mesh.space_ndim, 2);
        assert_eq!(mesh.points.len(), 6);
        assert_eq!(mesh.cells.len(), 2);

        let mesh = Samples::two_cubes_vertical();
        assert_eq!(mesh.space_ndim, 3);
        assert_eq!(mesh.points.len(), 12);
        assert_eq!(mesh.cells.len(), 2);

        let mesh = Samples::mixed_shapes_2d();
        assert_eq!(mesh.space_ndim, 2);
        assert_eq!(mesh.points.len(), 5);
        assert_eq!(mesh.cells.len(), 2);

        let mesh = Samples::mixed_shapes_3d();
        assert_eq!(mesh.space_ndim, 3);
        assert_eq!(mesh.points.len(), 13);
        assert_eq!(mesh.cells.len(), 5);
    }
}
<|endoftext|>


<commit_before>use super::{NeuronConfig, Num};

/// At which potential the neuron's potential is reset to `c`.
const RESET_THRESHOLD: Num = 30.0;

/// Represents the state of a neuron.
#[derive(Copy, Clone, Debug)]
pub struct NeuronState {
    /// membrane potential of neuron (in mV)
    v: Num,

    /// recovery variable
    u: Num,
}

#[inline(always)]
fn dv(u: Num, v: Num, i_syn: Num) -> Num {
    (0.04 * v + 5.0) * v + 140.0 - u + i_syn
}

#[inline(always)]
fn du(u: Num, v: Num, a: Num, b: Num) -> Num {
    a * (b * v - u)
}

impl NeuronState {
    pub fn new() -> NeuronState {
        NeuronState { v: -70.0, u: -14.0 }
    }

    pub fn potential(&self) -> Num {
        if self.v < RESET_THRESHOLD {
            self.v
        } else {
            RESET_THRESHOLD
        }
    }

    pub fn recovery(&self) -> Num {
        self.u
    }

    #[inline(always)]
    fn calc(self, dt: Num, i_syn: Num, config: &NeuronConfig) -> NeuronState {
        NeuronState {
            v: self.v + dt * dv(self.u, self.v, i_syn),
            u: self.u + dt * du(self.u, self.v, config.a, config.b),
        }
    }

    /// Calculate the new state after 1 ms.
    #[inline]
    pub fn step_1ms(self, i_syn: Num, config: &NeuronConfig) -> (NeuronState, bool) {
        if self.v < RESET_THRESHOLD {
            (
                self.calc(0.5, i_syn, config).calc(0.5, i_syn, config),
                false,
            )
        } else {
            (
                NeuronState {
                    v: config.c,
                    u: self.u + config.d,
                },
                true,
            )
        }
    }
}
<commit_msg>Add some comments<commit_after>use super::{NeuronConfig, Num};

/// At which potential the neuron's potential is reset to `c`.
const RESET_THRESHOLD: Num = 30.0;

/// Represents the state of a neuron.
#[derive(Copy, Clone, Debug)]
pub struct NeuronState {
    /// membrane potential of neuron (in mV)
    v: Num,

    /// recovery variable
    u: Num,
}

#[inline(always)]
fn dv(u: Num, v: Num, i_syn: Num) -> Num {
    (0.04 * v + 5.0) * v + 140.0 - u + i_syn
}

#[inline(always)]
fn du(u: Num, v: Num, a: Num, b: Num) -> Num {
    a * (b * v - u)
}

impl NeuronState {
    pub fn new() -> NeuronState {
        NeuronState { v: -70.0, u: -14.0 }
    }

    pub fn potential(&self) -> Num {
        if self.v < RESET_THRESHOLD {
            self.v
        } else {
            RESET_THRESHOLD
        }
    }

    pub fn recovery(&self) -> Num {
        self.u
    }

    #[inline(always)]
    fn calc(self, dt: Num, i_syn: Num, config: &NeuronConfig) -> NeuronState {
        NeuronState {
            v: self.v + dt * dv(self.u, self.v, i_syn),
            u: self.u + dt * du(self.u, self.v, config.a, config.b),
        }
    }

    /// Calculate the new state after 1 ms.
    #[inline]
    pub fn step_1ms(self, i_syn: Num, config: &NeuronConfig) -> (NeuronState, bool) {
        if self.v < RESET_THRESHOLD {
            (
                // Split into two half-steps (0.5ms) to improve numerical stability
                self.calc(0.5, i_syn, config).calc(0.5, i_syn, config),
                false, // Neuron does not fire
            )
        } else {
            (
                NeuronState {
                    v: config.c,
                    u: self.u + config.d,
                },
                true, // Neuron fires
            )
        }
    }
}
<|endoftext|>


<commit_before>use std::path::Path;

use daemonize::Daemonize;
use log::error;

/// Daemonize a server process in a *nix standard way
///
/// This function will redirect `stdout`, `stderr` to `/dev/null`,
/// and follow the exact behavior in shadowsocks-libev
pub fn daemonize<F: AsRef<Path>>(pid_path: Option<F>) {
    let mut d = Daemonize::new().umask(0);
    if let Some(p) = pid_path {
        d = d.pid_file(p);
    }

    if let Err(err) = d.start() {
        error!("failed to daemonize, {:?} ({})", err, err);
    }
}
<commit_msg>Revert "remove chroot when daemonizing (#640)"<commit_after>use std::path::Path;

use daemonize::Daemonize;
use log::error;

/// Daemonize a server process in a *nix standard way
///
/// This function will redirect `stdout`, `stderr` to `/dev/null`,
/// and follow the exact behavior in shadowsocks-libev
pub fn daemonize<F: AsRef<Path>>(pid_path: Option<F>) {
    let mut d = Daemonize::new().umask(0).chroot("/");
    if let Some(p) = pid_path {
        d = d.pid_file(p);
    }

    if let Err(err) = d.start() {
        error!("failed to daemonize, {:?} ({})", err, err);
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The noise-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

//! An implementation of Ken Perlin's [Improved Noise]
//! (http://mrl.nyu.edu/~perlin/noise/) algorithm.

use std::num::{cast, mul_add};
use std::rand::{IsaacRng, Rng, weak_rng};

/// A perlin noise generator
pub struct Perlin {
    // The permutation table used for generating the noise values
    priv ptable: ~[u8]//[uint, ..512],
}

impl Perlin {
    /// Create a new perlin noise generator using the given seed.
    ///
    /// # Example
    ///
    /// ~~~rust
    /// let perlin = Perlin::new();
    /// ~~~
    ///
    pub fn new() -> Perlin {
        Perlin::from_rng(&mut weak_rng())
    }

    /// Create a new perlin noise generator using the given seed.
    ///
    /// # Example
    ///
    /// ~~~rust
    /// let perlin = Perlin::from_seed(std::rand::seed());
    /// let perlin = Perlin::from_seed("Bananas!".into_bytes());
    /// ~~~
    ///
    pub fn from_seed(seed: &[u8]) -> Perlin {
        Perlin::from_rng(&mut IsaacRng::new_seeded(seed))
    }

    /// Create a new perlin noise generator using the given random number
    /// generator to create the initial permutation table.
    ///
    /// # Example
    ///
    /// ~~~rust
    /// let perlin = Perlin::from_seed(&mut std::rand::weak_rng());
    /// ~~~
    ///
    #[inline]
    pub fn from_rng<R: Rng>(rng: &mut R) -> Perlin {
        Perlin { ptable: rng.gen_vec::<u8>(512) }
    }

    /// Generate a new perlin noise value based on a given 1, 2 or
    /// 3-dimensional coordinte.
    ///
    /// `pos` can be of the following coordinate types, where `T: Float`:
    ///
    /// - `[T, ..1]`
    /// - `[T, ..2]`
    /// - `[T, ..3]`
    /// - `&[T, ..1]`
    /// - `&[T, ..2]`
    /// - `&[T, ..3]`
    ///
    /// # Examples
    ///
    /// ~~~rust
    /// let perlin = Perlin::new();
    /// let a = perlin.gen([1.0]);
    /// let b = perlin.gen([2.0, 3.0, 4.0]);
    ///
    /// let v = [3.0, 4.0];
    /// let c = perlin.gen(&v);
    /// ~~~
    ///
    #[inline]
    pub fn gen<T: Float, G: Gen<T>>(&self, pos: G) -> T {
        pos.gen(self)
    }
}

/// Internal trait used for implementing the perlin noise generation algorithm
/// for various coordinate types. The `Gen::gen` method should not be accessed
/// directly - use the generic `Perlin::gen` method instead.
trait Gen<T> {
    fn gen(&self, ctx: &Perlin) -> T;
}

impl<'self, T: Float> Gen<T> for &'self [T, ..1] {
    fn gen(&self, ctx: &Perlin) -> T {
        let X = self[0].floor().to_uint() as u8;

        let x = self[0] - self[0].floor();

        let u = fade(x.clone());

        let A  = ctx.ptable[X    ];
        let AA = ctx.ptable[A    ];
        let B  = ctx.ptable[X + 1];
        let BA = ctx.ptable[B    ];

        lerp(u.clone(), grad(ctx.ptable[AA], x.clone(), cast(0), cast(0)),
                        grad(ctx.ptable[BA], x-cast(1), cast(0), cast(0)))
    }
}

impl<'self, T: Float> Gen<T> for &'self [T, ..2] {
    fn gen(&self, ctx: &Perlin) -> T {
        let X = self[0].floor().to_uint() as u8;
        let Y = self[1].floor().to_uint() as u8;

        let x = self[0] - self[0].floor();
        let y = self[1] - self[1].floor();

        let u = fade(x.clone());
        let v = fade(y.clone());

        let A  = ctx.ptable[X    ] + Y;
        let AA = ctx.ptable[A    ];
        let AB = ctx.ptable[A + 1];
        let B  = ctx.ptable[X + 1] + Y;
        let BA = ctx.ptable[B    ];
        let BB = ctx.ptable[B + 1];

        lerp(v.clone(), lerp(u.clone(), grad(ctx.ptable[AA], x.clone(), y.clone(), cast(0)),
                                        grad(ctx.ptable[BA], x-cast(1), y.clone(), cast(0))),
                        lerp(u.clone(), grad(ctx.ptable[AB], x.clone(), y-cast(1), cast(0)),
                                        grad(ctx.ptable[BB], x-cast(1), y-cast(1), cast(0))))
    }
}

impl<'self, T: Float> Gen<T> for &'self [T, ..3] {
    fn gen(&self, ctx: &Perlin) -> T {
        // Find the unit cube that contains the point
        let X = self[0].floor().to_uint() as u8;
        let Y = self[1].floor().to_uint() as u8;
        let Z = self[2].floor().to_uint() as u8;

        // Find the relative X, Y, Z of point in the cube
        let x = self[0] - self[0].floor();
        let y = self[1] - self[1].floor();
        let z = self[2] - self[2].floor();

        // Compute the fade curves for X, Y, Z
        let u = fade(x.clone());
        let v = fade(y.clone());
        let w = fade(z.clone());

        // Hash coordinates of the 8 cube corners
        let A  = ctx.ptable[X    ] + Y;
        let AA = ctx.ptable[A    ] + Z;
        let AB = ctx.ptable[A + 1] + Z;
        let B  = ctx.ptable[X + 1] + Y;
        let BA = ctx.ptable[B    ] + Z;
        let BB = ctx.ptable[B + 1] + Z;

        // Add the blended results from the 8 corners of the cube
        lerp(w, lerp(v.clone(), lerp(u.clone(), grad(ctx.ptable[AA    ], x.clone(), y.clone(), z.clone()),
                                                grad(ctx.ptable[BA    ], x-cast(1), y.clone(), z.clone())),
                                lerp(u.clone(), grad(ctx.ptable[AB    ], x.clone(), y-cast(1), z.clone()),
                                                grad(ctx.ptable[BB    ], x-cast(1), y-cast(1), z.clone()))),
                lerp(v.clone(), lerp(u.clone(), grad(ctx.ptable[AA + 1], x.clone(), y.clone(), z-cast(1)),
                                                grad(ctx.ptable[BA + 1], x-cast(1), y.clone(), z-cast(1))),
                                lerp(u.clone(), grad(ctx.ptable[AB + 1], x.clone(), y-cast(1), z-cast(1)),
                                                grad(ctx.ptable[BB + 1], x-cast(1), y-cast(1), z-cast(1)))))
    }
}

impl<T: Float> Gen<T> for [T, ..1] {
    #[inline] fn gen(&self, ctx: &Perlin) -> T { ctx.gen(self) }
}

impl<T: Float> Gen<T> for [T, ..2] {
    #[inline] fn gen(&self, ctx: &Perlin) -> T { ctx.gen(self) }
}

impl<T: Float> Gen<T> for [T, ..3] {
    #[inline] fn gen(&self, ctx: &Perlin) -> T { ctx.gen(self) }
}

#[inline]
fn fade<T: Float>(t: T) -> T {
    t * t * t * (t * (t * cast(6) - cast(15)) + cast(10))
}

#[inline]
fn lerp<T: Float>(t: T, a: T, b: T) -> T {
    mul_add(t, b - a, a)
}

fn grad<T: Float>(hash: u8, x: T, y: T, z: T) -> T {
    let h = hash & 15;

    let u = match h {
        0..7 => x.clone(),
        _    => y.clone(),
    };
    let v = match h {
        0..3    => y.clone(),
        12 | 14 => x.clone(),
        _       => z.clone(),
    };

    (if (h & 1) == 0 { u } else { -u }) +
    (if (h & 2) == 0 { v } else { -v })
}

<commit_msg>Restore the default permutation table for Perlin::new<commit_after>// Copyright 2013 The noise-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

//! An implementation of Ken Perlin's [Improved Noise]
//! (http://mrl.nyu.edu/~perlin/noise/) algorithm.

use std::num::{cast, mul_add};
use std::rand::{IsaacRng, Rng};
use std::vec;

/// A perlin noise generator
pub struct Perlin {
    // The permutation table used for generating the noise values
    priv ptable: ~[u8/*, ..512*/],
}

impl Perlin {
    /// Create a new perlin noise generator using the default permutation
    /// table.
    ///
    /// # Example
    ///
    /// ~~~rust
    /// let perlin = Perlin::new();
    /// ~~~
    ///
    pub fn new() -> Perlin {
        Perlin { ptable: DEFAULT_PERMUTAIONS.to_owned() }
    }

    /// Create a new perlin noise generator using the given seed.
    ///
    /// # Example
    ///
    /// ~~~rust
    /// let perlin = Perlin::from_seed(std::rand::seed());
    /// let perlin = Perlin::from_seed("Bananas!".into_bytes());
    /// ~~~
    ///
    pub fn from_seed(seed: &[u8]) -> Perlin {
        Perlin::from_rng(&mut IsaacRng::new_seeded(seed))
    }

    /// Create a new perlin noise generator using the given random number
    /// generator to create the initial permutation table.
    ///
    /// # Example
    ///
    /// ~~~rust
    /// let perlin = Perlin::from_seed(&mut std::rand::weak_rng());
    /// ~~~
    ///
    #[inline]
    pub fn from_rng<R: Rng>(rng: &mut R) -> Perlin {
        Perlin { ptable: rng.shuffle(vec::from_fn(512, |i| i as u8)) }
    }

    /// Generate a new perlin noise value based on a given 1, 2 or
    /// 3-dimensional coordinte.
    ///
    /// `pos` can be of the following coordinate types, where `T: Float`:
    ///
    /// - `[T, ..1]`
    /// - `[T, ..2]`
    /// - `[T, ..3]`
    /// - `&[T, ..1]`
    /// - `&[T, ..2]`
    /// - `&[T, ..3]`
    ///
    /// # Examples
    ///
    /// ~~~rust
    /// let perlin = Perlin::new();
    /// let a = perlin.gen([1.0]);
    /// let b = perlin.gen([2.0, 3.0, 4.0]);
    ///
    /// let v = [3.0, 4.0];
    /// let c = perlin.gen(&v);
    /// ~~~
    ///
    #[inline]
    pub fn gen<T: Float, G: Gen<T>>(&self, pos: G) -> T {
        pos.gen(self)
    }
}

/// Internal trait used for implementing the perlin noise generation algorithm
/// for various coordinate types. The `Gen::gen` method should not be accessed
/// directly - use the generic `Perlin::gen` method instead.
trait Gen<T> {
    fn gen(&self, ctx: &Perlin) -> T;
}

impl<'self, T: Float> Gen<T> for &'self [T, ..1] {
    fn gen(&self, ctx: &Perlin) -> T {
        let X = self[0].floor().to_uint() as u8;

        let x = self[0] - self[0].floor();

        let u = fade(x.clone());

        let A  = ctx.ptable[X    ];
        let AA = ctx.ptable[A    ];
        let B  = ctx.ptable[X + 1];
        let BA = ctx.ptable[B    ];

        lerp(u.clone(), grad(ctx.ptable[AA], x.clone(), cast(0), cast(0)),
                        grad(ctx.ptable[BA], x-cast(1), cast(0), cast(0)))
    }
}

impl<'self, T: Float> Gen<T> for &'self [T, ..2] {
    fn gen(&self, ctx: &Perlin) -> T {
        let X = self[0].floor().to_uint() as u8;
        let Y = self[1].floor().to_uint() as u8;

        let x = self[0] - self[0].floor();
        let y = self[1] - self[1].floor();

        let u = fade(x.clone());
        let v = fade(y.clone());

        let A  = ctx.ptable[X    ] + Y;
        let AA = ctx.ptable[A    ];
        let AB = ctx.ptable[A + 1];
        let B  = ctx.ptable[X + 1] + Y;
        let BA = ctx.ptable[B    ];
        let BB = ctx.ptable[B + 1];

        lerp(v.clone(), lerp(u.clone(), grad(ctx.ptable[AA], x.clone(), y.clone(), cast(0)),
                                        grad(ctx.ptable[BA], x-cast(1), y.clone(), cast(0))),
                        lerp(u.clone(), grad(ctx.ptable[AB], x.clone(), y-cast(1), cast(0)),
                                        grad(ctx.ptable[BB], x-cast(1), y-cast(1), cast(0))))
    }
}

impl<'self, T: Float> Gen<T> for &'self [T, ..3] {
    fn gen(&self, ctx: &Perlin) -> T {
        // Find the unit cube that contains the point
        let X = self[0].floor().to_uint() as u8;
        let Y = self[1].floor().to_uint() as u8;
        let Z = self[2].floor().to_uint() as u8;

        // Find the relative X, Y, Z of point in the cube
        let x = self[0] - self[0].floor();
        let y = self[1] - self[1].floor();
        let z = self[2] - self[2].floor();

        // Compute the fade curves for X, Y, Z
        let u = fade(x.clone());
        let v = fade(y.clone());
        let w = fade(z.clone());

        // Hash coordinates of the 8 cube corners
        let A  = ctx.ptable[X    ] + Y;
        let AA = ctx.ptable[A    ] + Z;
        let AB = ctx.ptable[A + 1] + Z;
        let B  = ctx.ptable[X + 1] + Y;
        let BA = ctx.ptable[B    ] + Z;
        let BB = ctx.ptable[B + 1] + Z;

        // Add the blended results from the 8 corners of the cube
        lerp(w, lerp(v.clone(), lerp(u.clone(), grad(ctx.ptable[AA    ], x.clone(), y.clone(), z.clone()),
                                                grad(ctx.ptable[BA    ], x-cast(1), y.clone(), z.clone())),
                                lerp(u.clone(), grad(ctx.ptable[AB    ], x.clone(), y-cast(1), z.clone()),
                                                grad(ctx.ptable[BB    ], x-cast(1), y-cast(1), z.clone()))),
                lerp(v.clone(), lerp(u.clone(), grad(ctx.ptable[AA + 1], x.clone(), y.clone(), z-cast(1)),
                                                grad(ctx.ptable[BA + 1], x-cast(1), y.clone(), z-cast(1))),
                                lerp(u.clone(), grad(ctx.ptable[AB + 1], x.clone(), y-cast(1), z-cast(1)),
                                                grad(ctx.ptable[BB + 1], x-cast(1), y-cast(1), z-cast(1)))))
    }
}

impl<T: Float> Gen<T> for [T, ..1] {
    #[inline] fn gen(&self, ctx: &Perlin) -> T { ctx.gen(self) }
}

impl<T: Float> Gen<T> for [T, ..2] {
    #[inline] fn gen(&self, ctx: &Perlin) -> T { ctx.gen(self) }
}

impl<T: Float> Gen<T> for [T, ..3] {
    #[inline] fn gen(&self, ctx: &Perlin) -> T { ctx.gen(self) }
}

#[inline]
fn fade<T: Float>(t: T) -> T {
    t * t * t * (t * (t * cast(6) - cast(15)) + cast(10))
}

#[inline]
fn lerp<T: Float>(t: T, a: T, b: T) -> T {
    mul_add(t, b - a, a)
}

fn grad<T: Float>(hash: u8, x: T, y: T, z: T) -> T {
    let h = hash & 15;

    let u = match h {
        0..7 => x.clone(),
        _    => y.clone(),
    };
    let v = match h {
        0..3    => y.clone(),
        12 | 14 => x.clone(),
        _       => z.clone(),
    };

    (if (h & 1) == 0 { u } else { -u }) +
    (if (h & 2) == 0 { v } else { -v })
}

/// The default permutation table found at Ken Perlin's [Improved Noise page]
/// (http://mrl.nyu.edu/~perlin/noise/).
static DEFAULT_PERMUTAIONS: &'static [u8/*, ..512*/] = &'static [
    151, 160, 137,  91,  90,  15, 131,  13, 201,  95,  96,  53, 194, 233,   7, 225,
    140,  36, 103,  30,  69, 142,   8,  99,  37, 240,  21,  10,  23, 190,   6, 148,
    247, 120, 234,  75,   0,  26, 197,  62,  94, 252, 219, 203, 117,  35,  11,  32,
     57, 177,  33,  88, 237, 149,  56,  87, 174,  20, 125, 136, 171, 168,  68, 175,
     74, 165,  71, 134, 139,  48,  27, 166,  77, 146, 158, 231,  83, 111, 229, 122,
     60, 211, 133, 230, 220, 105,  92,  41,  55,  46, 245,  40, 244, 102, 143,  54,
     65,  25,  63, 161,   1, 216,  80,  73, 209,  76, 132, 187, 208,  89,  18, 169,
    200, 196, 135, 130, 116, 188, 159,  86, 164, 100, 109, 198, 173, 186,   3,  64,
     52, 217, 226, 250, 124, 123,   5, 202,  38, 147, 118, 126, 255,  82,  85, 212,
    207, 206,  59, 227,  47,  16,  58,  17, 182, 189,  28,  42, 223, 183, 170, 213,
    119, 248, 152,   2,  44, 154, 163,  70, 221, 153, 101, 155, 167,  43, 172,   9,
    129,  22,  39, 253,  19,  98, 108, 110,  79, 113, 224, 232, 178, 185, 112, 104,
    218, 246,  97, 228, 251,  34, 242, 193, 238, 210, 144,  12, 191, 179, 162, 241,
     81,  51, 145, 235, 249,  14, 239, 107,  49, 192, 214,  31, 181, 199, 106, 157,
    184,  84, 204, 176, 115, 121,  50,  45, 127,   4, 150, 254, 138, 236, 205,  93,
    222, 114,  67,  29,  24,  72, 243, 141, 128, 195,  78,  66, 215,  61, 156, 180,
    151, 160, 137,  91,  90,  15, 131,  13, 201,  95,  96,  53, 194, 233,   7, 225,
    140,  36, 103,  30,  69, 142,   8,  99,  37, 240,  21,  10,  23, 190,   6, 148,
    247, 120, 234,  75,   0,  26, 197,  62,  94, 252, 219, 203, 117,  35,  11,  32,
     57, 177,  33,  88, 237, 149,  56,  87, 174,  20, 125, 136, 171, 168,  68, 175,
     74, 165,  71, 134, 139,  48,  27, 166,  77, 146, 158, 231,  83, 111, 229, 122,
     60, 211, 133, 230, 220, 105,  92,  41,  55,  46, 245,  40, 244, 102, 143,  54,
     65,  25,  63, 161,   1, 216,  80,  73, 209,  76, 132, 187, 208,  89,  18, 169,
    200, 196, 135, 130, 116, 188, 159,  86, 164, 100, 109, 198, 173, 186,   3,  64,
     52, 217, 226, 250, 124, 123,   5, 202,  38, 147, 118, 126, 255,  82,  85, 212,
    207, 206,  59, 227,  47,  16,  58,  17, 182, 189,  28,  42, 223, 183, 170, 213,
    119, 248, 152,   2,  44, 154, 163,  70, 221, 153, 101, 155, 167,  43, 172,   9,
    129,  22,  39, 253,  19,  98, 108, 110,  79, 113, 224, 232, 178, 185, 112, 104,
    218, 246,  97, 228, 251,  34, 242, 193, 238, 210, 144,  12, 191, 179, 162, 241,
     81,  51, 145, 235, 249,  14, 239, 107,  49, 192, 214,  31, 181, 199, 106, 157,
    184,  84, 204, 176, 115, 121,  50,  45, 127,   4, 150, 254, 138, 236, 205,  93,
    222, 114,  67,  29,  24,  72, 243, 141, 128, 195,  78,  66, 215,  61, 156, 180,
];
<|endoftext|>


<commit_before>#![allow(unused_imports)]
#![allow(non_snake_case)]

use std::cmp::{max, min, Ordering};
use std::collections::*;
use std::io::*;
use std::ops::*;
use std::*;

// -----------------------------------------------
// Framework
// -----------------------------------------------

#[allow(unused)]
fn rl() -> String {
    let mut buf = String::new();
    io::stdin().read_line(&mut buf).unwrap();
    buf.trim_right().to_owned()
}

#[allow(unused)]
fn rw<T>() -> Vec<T>
where
    T: std::str::FromStr,
    T::Err: std::fmt::Debug,
{
    let mut buf = String::new();
    io::stdin().read_line(&mut buf).unwrap();
    buf.split_whitespace()
        .map(|word| T::from_str(word).unwrap())
        .collect()
}

#[allow(unused_macros)]
macro_rules! read {
    ([$t:ty] ; $n:expr) => {
        (0..$n).map(|_| read!([$t])).collect::<Vec<_>>()
    };
    ($($t:ty),+ ; $n:expr) => {
        (0..$n).map(|_| read!($($t),+)).collect::<Vec<_>>()
    };
    ([$t:ty]) => {{
        rl()
            .split_whitespace()
            .map(|word| word.parse().unwrap())
            .collect::<Vec<$t>>()
    }};
    ($t:ty) => {
        rl().parse::<$t>().unwrap()
    };
    ($($t:ty),*) => {{
        let buf = rl();
        let mut w = buf.split_whitespace().into_iter();
        ($(w.next().unwrap().parse::<$t>().unwrap()),*)
    }};
}

trait IteratorExt: Iterator + Sized {
    fn vec(self) -> Vec<Self::Item> {
        self.collect()
    }
}

impl<T: Iterator> IteratorExt for T {}

#[allow(unused)]
macro_rules! debug {
    ($($arg:expr),*) => {
        #[cfg(debug_assertions)]
        {
            let entries = &[
                $((
                    &stringify!($arg).to_string() as &fmt::Debug,
                    &($arg) as &fmt::Debug,
                )),*
            ];
            eprintln!("{:?}", DebugMap(entries));
        }
    };
}

#[allow(unused)]
struct DebugMap<'a>(&'a [(&'a fmt::Debug, &'a fmt::Debug)]);

impl<'a> std::fmt::Debug for DebugMap<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let mut m = fmt.debug_map();
        for &(key, value) in self.0.iter() {
            m.entry(key, value);
        }
        m.finish()
    }
}

// -----------------------------------------------
// Polyfill
// -----------------------------------------------

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Rev<T>(pub T);

impl<T: PartialOrd> PartialOrd for Rev<T> {
    fn partial_cmp(&self, other: &Rev<T>) -> Option<Ordering> {
        other.0.partial_cmp(&self.0)
    }
}

impl<T: Ord> Ord for Rev<T> {
    fn cmp(&self, other: &Rev<T>) -> Ordering {
        other.0.cmp(&self.0)
    }
}

#[allow(unused)]
macro_rules! eprintln {
    ($($arg:expr),*) => { _eprintln(format_args!($($arg),*)) }
}

fn _eprintln(args: fmt::Arguments) {
    let err = std::io::stderr();
    let mut err = err.lock();
    err.write_fmt(args).unwrap();
    err.write(b"\n").unwrap();
}

// -----------------------------------------------
// Solution
// -----------------------------------------------

pub fn main() {
    return;
}

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

    #[test]
    fn test_ok() {
        assert_eq!(7, 1 + 2 * 3);
    }
}
<commit_msg>Remove rw<commit_after>#![allow(unused_imports)]
#![allow(non_snake_case)]

use std::cmp::{max, min, Ordering};
use std::collections::*;
use std::io::*;
use std::ops::*;
use std::*;

// -----------------------------------------------
// Framework
// -----------------------------------------------

#[allow(unused)]
fn rl() -> String {
    let mut buf = String::new();
    io::stdin().read_line(&mut buf).unwrap();
    buf.trim_right().to_owned()
}

#[allow(unused_macros)]
macro_rules! read {
    ([$t:ty] ; $n:expr) => {
        (0..$n).map(|_| read!([$t])).collect::<Vec<_>>()
    };
    ($($t:ty),+ ; $n:expr) => {
        (0..$n).map(|_| read!($($t),+)).collect::<Vec<_>>()
    };
    ([$t:ty]) => {{
        rl()
            .split_whitespace()
            .map(|word| word.parse().unwrap())
            .collect::<Vec<$t>>()
    }};
    ($t:ty) => {
        rl().parse::<$t>().unwrap()
    };
    ($($t:ty),*) => {{
        let buf = rl();
        let mut w = buf.split_whitespace().into_iter();
        ($(w.next().unwrap().parse::<$t>().unwrap()),*)
    }};
}

trait IteratorExt: Iterator + Sized {
    fn vec(self) -> Vec<Self::Item> {
        self.collect()
    }
}

impl<T: Iterator> IteratorExt for T {}

#[allow(unused)]
macro_rules! debug {
    ($($arg:expr),*) => {
        #[cfg(debug_assertions)]
        {
            let entries = &[
                $((
                    &stringify!($arg).to_string() as &fmt::Debug,
                    &($arg) as &fmt::Debug,
                )),*
            ];
            eprintln!("{:?}", DebugMap(entries));
        }
    };
}

#[allow(unused)]
struct DebugMap<'a>(&'a [(&'a fmt::Debug, &'a fmt::Debug)]);

impl<'a> std::fmt::Debug for DebugMap<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let mut m = fmt.debug_map();
        for &(key, value) in self.0.iter() {
            m.entry(key, value);
        }
        m.finish()
    }
}

// -----------------------------------------------
// Polyfill
// -----------------------------------------------

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Rev<T>(pub T);

impl<T: PartialOrd> PartialOrd for Rev<T> {
    fn partial_cmp(&self, other: &Rev<T>) -> Option<Ordering> {
        other.0.partial_cmp(&self.0)
    }
}

impl<T: Ord> Ord for Rev<T> {
    fn cmp(&self, other: &Rev<T>) -> Ordering {
        other.0.cmp(&self.0)
    }
}

#[allow(unused)]
macro_rules! eprintln {
    ($($arg:expr),*) => { _eprintln(format_args!($($arg),*)) }
}

fn _eprintln(args: fmt::Arguments) {
    let err = std::io::stderr();
    let mut err = err.lock();
    err.write_fmt(args).unwrap();
    err.write(b"\n").unwrap();
}

// -----------------------------------------------
// Solution
// -----------------------------------------------

pub fn main() {
    return;
}

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

    #[test]
    fn test_ok() {
        assert_eq!(7, 1 + 2 * 3);
    }
}
<|endoftext|>


<commit_before>extern crate bio;
extern crate argparse;
use std::io;
use std::io::Write;
use std::cmp;
use bio::io::fasta;
use std::fmt;
use std::fs::File;
use argparse::{ArgumentParser, StoreTrue, Store, Print, Collect};

const EXIT_FILE_IO_ERROR: i32 = 1;
const EXIT_COMMAND_LINE_ERROR: i32 = 2;
const EXIT_FASTA_PARSE_ERROR: i32 = 3;
static PROGRAM_NAME: &'static str = "biotool";

fn exit_with_error(status :i32, message: &String) -> () {
   writeln!(&mut std::io::stderr(), "{} ERROR: {}!", PROGRAM_NAME, message).unwrap();
   std::process::exit(status);
}

#[derive(Debug)]
pub struct FastaStats {
   min_len: u64,
   average_len: u64,
   max_len: u64,
   total: u64,
   num_seqs: u64,
}

#[derive(Debug)]
pub enum StatsResult {
   StatsNone,
   StatsSome(FastaStats),
   StatsError(io::Error)
}

impl FastaStats {
   pub fn new<R: io::Read>(minlen: u64, reader: R) -> StatsResult {
      let fasta_reader = fasta::Reader::new(reader);
      let mut num_seqs:u64 = 0;
      let mut total:u64 = 0;
      let mut max_len:u64 = 0;
      let mut min_len:u64 = 0;
      let mut this_len:u64;

      for next in fasta_reader.records() {
         match next {
            Ok(record) => {
               this_len = record.seq().len() as u64;
               if this_len >= minlen {
                  num_seqs += 1;
                  total += this_len;
                  if num_seqs == 1 {
                     max_len = this_len;
                     min_len = this_len;
                  }
                  else {
                     max_len = cmp::max(max_len, this_len);
                     min_len = cmp::min(min_len, this_len);
                  }
               }
            },
            Err(error) => return StatsResult::StatsError(error)
         }
      }
      if num_seqs > 0 {
         let average_len = ((total as f64) / (num_seqs as f64)).floor() as u64;
         StatsResult::StatsSome(FastaStats { min_len: min_len,
                           average_len: average_len,
                           max_len: max_len,
                           total: total,
                           num_seqs: num_seqs })
      }
      else {
         StatsResult::StatsNone
      }
   }
}

impl fmt::Display for FastaStats {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      write!(f, "{}\t{}\t{}\t{}\t{}", self.num_seqs, self.total,
         self.min_len, self.average_len, self.max_len)
   }
}

struct Options {
    verbose: bool,
    minlen: u64,
    fasta_files: Vec<String>,
}

fn parse_options() -> Options {
   let mut options = Options { verbose: false, minlen: 0, fasta_files: Vec::new() };
   {  let mut ap = ArgumentParser::new();
      ap.set_description("Print fasta stats");
      ap.refer(&mut options.verbose)
         .add_option(&["-v", "--verbose"], StoreTrue,
         "Print more stuff about what's happening");
      ap.refer(&mut options.minlen)
         .add_option(&["--minlen"], Store,
         "Minimum length sequence to include in stats");
      ap.refer(&mut options.fasta_files)
         .add_argument(&"fasta_files", Collect,
         "Input FASTA files");
      ap.add_option(&["--version"],
         Print(env!("CARGO_PKG_VERSION").to_string()), "Show version");
      match ap.parse_args() {
         Ok(()) => (),
         Err(0) => {
            // Help and version commands
            std::process::exit(0);
         },
         Err(_error_code) => {
            // Parse error
            std::process::exit(EXIT_COMMAND_LINE_ERROR);
         }
      }
   }
   return options
}

fn compute_print_stats<R: io::Read>(options: &Options, filename: &String, reader: R) -> () {
   match FastaStats::new(options.minlen, reader) {
      StatsResult::StatsSome(stats) => {
         println!("{}\t{}", filename, stats);
      },
      StatsResult::StatsNone => {
         println!("{}\t0\t0\t-\t-\t-", filename);
      }
      StatsResult::StatsError(error) => {
         exit_with_error(EXIT_FASTA_PARSE_ERROR, &format!("{}", error))
      }
   }
}

fn main() {
   let options = parse_options();
   println!("FILENAME\tTOTAL\tNUMSEQ\tMIN\tAVG\tMAX");
   if options.fasta_files.len() == 0 {
      compute_print_stats(&options, &String::from("stdin"), io::stdin());
   }
   else {
      for filename in &options.fasta_files {
         match File::open(filename) {
            Ok(file) => {
               compute_print_stats(&options, filename, file);
            },
            Err(error) => {
               exit_with_error(EXIT_FILE_IO_ERROR, &format!("{}", error))
            }
         }
      }
   }
}

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

   #[test]
   fn test_zero_byte_input() {
      match FastaStats::new(0, "".as_bytes()) {
         StatsResult::StatsNone => (),
         other => panic!(format!("expected StatsNone, got {:?}", other))
      }
   }

   #[test]
   fn test_single_newline_input() {
      match FastaStats::new(0, "\n".as_bytes()) {
         StatsResult::StatsError(_error) => (),
         other => panic!(format!("expected StatsError, got {:?}", other))
      }
   }

   #[test]
   fn test_single_greater_than_input() {
      match FastaStats::new(0, ">".as_bytes()) {
         StatsResult::StatsSome(FastaStats{min_len :0, average_len :0, max_len :0, total :0, num_seqs :1}) => (),
         other => panic!(format!("expected FastaStats(0,0,0,0,1), got {:?}", other))
      }
   }

   #[test]
   fn one_sequence() {
      match FastaStats::new(0, ">header\nATGC\nA".as_bytes()) {
         StatsResult::StatsSome(FastaStats{min_len :5, average_len :5, max_len :5, total :5, num_seqs :1}) => (),
         other => panic!(format!("expected FastaStats(5,5,5,5,1), got {:?}", other))
      }
   }

   #[test]
   fn two_sequence() {
      match FastaStats::new(0, ">header1\nATGC\nAGG\n>header2\nTT\n".as_bytes()) {
         StatsResult::StatsSome(FastaStats{min_len :2, average_len :4, max_len :7, total :9, num_seqs :2}) => (),
         other => panic!(format!("expected FastaStats(2,4,7,9,2), got {:?}", other))
      }
   }

   #[test]
   fn no_header() {
      match FastaStats::new(0, "no header\n".as_bytes()) {
         StatsResult::StatsError(_error) => (),
         other => panic!(format!("expected StatsError, got {:?}", other))
      }
   }

   #[test]
   fn minlen_less_than_all() {
      match FastaStats::new(2, ">header1\nATGC\nAGG\n>header2\nTT\n".as_bytes()) {
         StatsResult::StatsSome(FastaStats{min_len :2, average_len :4, max_len :7, total :9, num_seqs :2}) => (),
         other => panic!(format!("expected FastaStats(2,4,7,9,2), got {:?}", other))
      }
   }

   #[test]
   fn minlen_greater_than_one() {
      match FastaStats::new(3, ">header1\nATGC\nAGG\n>header2\nTT\n".as_bytes()) {
         StatsResult::StatsSome(FastaStats{min_len :7, average_len :7, max_len :7, total :7, num_seqs :1}) => (),
         other => panic!(format!("expected FastaStats(2,4,7,9,2), got {:?}", other))
      }
   }

   #[test]
   fn minlen_greater_than_all() {
      match FastaStats::new(8, ">header1\nATGC\nAGG\n>header2\nTT\n".as_bytes()) {
         StatsResult::StatsNone => (),
         other => panic!(format!("expected StatsNone, got {:?}", other))
      }
   }
}
<commit_msg>Refactor test cases to avoid repeated code<commit_after>extern crate bio;
extern crate argparse;
use std::io;
use std::io::Write;
use std::cmp;
use bio::io::fasta;
use std::fmt;
use std::fs::File;
use argparse::{ArgumentParser, StoreTrue, Store, Print, Collect};

const EXIT_FILE_IO_ERROR: i32 = 1;
const EXIT_COMMAND_LINE_ERROR: i32 = 2;
const EXIT_FASTA_PARSE_ERROR: i32 = 3;
static PROGRAM_NAME: &'static str = "biotool";

fn exit_with_error(status :i32, message: &String) -> () {
   writeln!(&mut std::io::stderr(), "{} ERROR: {}!", PROGRAM_NAME, message).unwrap();
   std::process::exit(status);
}

#[derive(Debug, PartialEq)]
pub struct FastaStats {
   min_len: u64,
   average_len: u64,
   max_len: u64,
   total: u64,
   num_seqs: u64,
}

#[derive(Debug)]
pub enum StatsResult {
   StatsNone,
   StatsSome(FastaStats),
   StatsError(io::Error)
}

impl FastaStats {
   pub fn new<R: io::Read>(minlen: u64, reader: R) -> Result<Option<FastaStats>, io::Error> {
      let fasta_reader = fasta::Reader::new(reader);
      let mut num_seqs:u64 = 0;
      let mut total:u64 = 0;
      let mut max_len:u64 = 0;
      let mut min_len:u64 = 0;
      let mut this_len:u64;

      for next in fasta_reader.records() {
         match next {
            Ok(record) => {
               this_len = record.seq().len() as u64;
               if this_len >= minlen {
                  num_seqs += 1;
                  total += this_len;
                  if num_seqs == 1 {
                     max_len = this_len;
                     min_len = this_len;
                  }
                  else {
                     max_len = cmp::max(max_len, this_len);
                     min_len = cmp::min(min_len, this_len);
                  }
               }
            },
            //Err(error) => return StatsResult::StatsError(error)
            Err(error) => return Err(error)
         }
      }
      if num_seqs > 0 {
         let average_len = ((total as f64) / (num_seqs as f64)).floor() as u64;
         Ok(Some(FastaStats { min_len: min_len,
            average_len: average_len,
            max_len: max_len,
            total: total,
            num_seqs: num_seqs }))
      }
      else {
         Ok(None)
      }
   }
}

impl fmt::Display for FastaStats {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      write!(f, "{}\t{}\t{}\t{}\t{}", self.num_seqs, self.total,
         self.min_len, self.average_len, self.max_len)
   }
}

struct Options {
    verbose: bool,
    minlen: u64,
    fasta_files: Vec<String>,
}

fn parse_options() -> Options {
   let mut options = Options { verbose: false, minlen: 0, fasta_files: Vec::new() };
   {  let mut ap = ArgumentParser::new();
      ap.set_description("Print fasta stats");
      ap.refer(&mut options.verbose)
         .add_option(&["-v", "--verbose"], StoreTrue,
         "Print more stuff about what's happening");
      ap.refer(&mut options.minlen)
         .add_option(&["--minlen"], Store,
         "Minimum length sequence to include in stats");
      ap.refer(&mut options.fasta_files)
         .add_argument(&"fasta_files", Collect,
         "Input FASTA files");
      ap.add_option(&["--version"],
         Print(env!("CARGO_PKG_VERSION").to_string()), "Show version");
      match ap.parse_args() {
         Ok(()) => (),
         Err(0) => {
            // Help and version commands
            std::process::exit(0);
         },
         Err(_error_code) => {
            // Parse error
            std::process::exit(EXIT_COMMAND_LINE_ERROR);
         }
      }
   }
   return options
}

fn compute_print_stats<R: io::Read>(options: &Options, filename: &String, reader: R) -> () {
   match FastaStats::new(options.minlen, reader) {
      //StatsResult::StatsSome(stats) => {
      Ok(Some(stats)) => {
         println!("{}\t{}", filename, stats);
      },
      Ok(None) => {
         println!("{}\t0\t0\t-\t-\t-", filename);
      }
      Err(error) => {
         exit_with_error(EXIT_FASTA_PARSE_ERROR, &format!("{}", error))
      }
   }
}

fn main() {
   let options = parse_options();
   println!("FILENAME\tTOTAL\tNUMSEQ\tMIN\tAVG\tMAX");
   if options.fasta_files.len() == 0 {
      compute_print_stats(&options, &String::from("stdin"), io::stdin());
   }
   else {
      for filename in &options.fasta_files {
         match File::open(filename) {
            Ok(file) => {
               compute_print_stats(&options, filename, file);
            },
            Err(error) => {
               exit_with_error(EXIT_FILE_IO_ERROR, &format!("{}", error))
            }
         }
      }
   }
}

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

   fn test_fastastats_ok(minlen: u64, input: &String, expected :Option<FastaStats>) -> () {
      match FastaStats::new(minlen, input.as_bytes()) {
         Ok(result) => {
            if result != expected {
               panic!(format!("expected {:?} got {:?}", expected, result))
            }
         },
         Err(_error) => {
            panic!(format!("expected {:?} got Err(..)", expected))
         }
      }
   }

   // io::Error does not currently implement PartialEq, so we resort to
   // just checking for the existence of an error, not its actual content.
   // Hopefully this will be fixed in Rust soon:
   // https://github.com/rust-lang/rust/issues/34158
   fn test_fastastats_err(minlen: u64, input: &String) -> () {
      let comp = FastaStats::new(minlen, input.as_bytes());
      match comp {
         Ok(result) => panic!(format!("expected Err(..) got {:?}", result)),
         Err(_error) => ()
      }
   }

   #[test]
   fn test_zero_byte_input() {
      test_fastastats_ok(0, &String::from(""), None)
   }

   #[test]
   fn test_single_newline_input() {
      test_fastastats_err(0, &String::from("\n"))
   }

   #[test]
   fn test_single_greater_than_input() {
      test_fastastats_ok(0, &String::from(">"),
         Some(FastaStats{min_len :0, average_len :0, max_len :0, total :0, num_seqs :1}))
   }

   #[test]
   fn one_sequence() {
      test_fastastats_ok(0, &String::from(">header\nATGC\nA"),
         Some(FastaStats{min_len :5, average_len :5, max_len :5, total :5, num_seqs :1}))
   }

   #[test]
   fn two_sequence() {
      test_fastastats_ok(0, &String::from(">header1\nATGC\nAGG\n>header2\nTT\n"),
         Some(FastaStats{min_len :2, average_len :4, max_len :7, total :9, num_seqs :2}))
   }

   #[test]
   fn no_header() {
      test_fastastats_err(0, &String::from("no header\n"))
   }

   #[test]
   fn minlen_less_than_all() {
      test_fastastats_ok(2, &String::from(">header1\nATGC\nAGG\n>header2\nTT\n"),
         Some(FastaStats{min_len :2, average_len :4, max_len :7, total :9, num_seqs :2}))
   }

   #[test]
   fn minlen_greater_than_one() {
      test_fastastats_ok(3, &String::from(">header1\nATGC\nAGG\n>header2\nTT\n"),
         Some(FastaStats{min_len :7, average_len :7, max_len :7, total :7, num_seqs :1}))
   }

   #[test]
   fn minlen_greater_than_all() {
      test_fastastats_ok(8, &String::from(">header1\nATGC\nAGG\n>header2\nTT\n"), None)
   }
}
<|endoftext|>


<commit_before>use std::env::var_os;

use getopts;

use output::Colours;
use output::{Grid, Details, GridDetails, Lines};
use options::{FileFilter, DirAction, Misfire};
use output::column::{Columns, TimeTypes, SizeFormat};
use term::dimensions;
use fs::feature::xattr;

/// The **view** contains all information about how to format output.
#[derive(PartialEq, Debug, Clone)]
pub enum View {
    Details(Details),
    Grid(Grid),
    GridDetails(GridDetails),
    Lines(Lines),
}

impl View {

    /// Determine which view to use and all of that view’s arguments.
    pub fn deduce(matches: &getopts::Matches, filter: FileFilter, dir_action: DirAction) -> Result<View, Misfire> {
        use options::misfire::Misfire::*;

        let colour_scale = || {
            matches.opt_present("color-scale") || matches.opt_present("colour-scale")
        };

        let long = || {
            if matches.opt_present("across") && !matches.opt_present("grid") {
                Err(Useless("across", true, "long"))
            }
            else if matches.opt_present("oneline") {
                Err(Useless("oneline", true, "long"))
            }
            else {
                let term_colours = TerminalColours::deduce(matches)?;
                let colours = match term_colours {
                    TerminalColours::Always    => Colours::colourful(colour_scale()),
                    TerminalColours::Never     => Colours::plain(),
                    TerminalColours::Automatic => {
                        if dimensions().is_some() {
                            Colours::colourful(colour_scale())
                        }
                        else {
                            Colours::plain()
                        }
                    },
                };

                let details = Details {
                    columns: Some(Columns::deduce(matches)?),
                    header: matches.opt_present("header"),
                    recurse: dir_action.recurse_options(),
                    filter: filter.clone(),
                    xattr: xattr::ENABLED && matches.opt_present("extended"),
                    colours: colours,
                };

                Ok(details)
            }
        };

        let long_options_scan = || {
            for option in &[ "binary", "bytes", "inode", "links", "header", "blocks", "time", "group" ] {
                if matches.opt_present(option) {
                    return Err(Useless(option, false, "long"));
                }
            }

            if cfg!(feature="git") && matches.opt_present("git") {
                Err(Useless("git", false, "long"))
            }
            else if matches.opt_present("level") && !matches.opt_present("recurse") && !matches.opt_present("tree") {
                Err(Useless2("level", "recurse", "tree"))
            }
            else if xattr::ENABLED && matches.opt_present("extended") {
                Err(Useless("extended", false, "long"))
            }
            else {
                Ok(())
            }
        };

        let other_options_scan = || {
            let term_colours = TerminalColours::deduce(matches)?;
            let term_width   = TerminalWidth::deduce()?;

            if let Some(&width) = term_width.as_ref() {
                let colours = match term_colours {
                    TerminalColours::Always
                    | TerminalColours::Automatic => Colours::colourful(colour_scale()),
                    TerminalColours::Never     => Colours::plain(),
                };

                if matches.opt_present("oneline") {
                    if matches.opt_present("across") {
                        Err(Useless("across", true, "oneline"))
                    }
                    else {
                        let lines = Lines {
                             colours: colours,
                        };

                        Ok(View::Lines(lines))
                    }
                }
                else if matches.opt_present("tree") {
                    let details = Details {
                        columns: None,
                        header: false,
                        recurse: dir_action.recurse_options(),
                        filter: filter.clone(),  // TODO: clone
                        xattr: false,
                        colours: colours,
                    };

                    Ok(View::Details(details))
                }
                else {
                    let grid = Grid {
                        across: matches.opt_present("across"),
                        console_width: width,
                        colours: colours,
                    };

                    Ok(View::Grid(grid))
                }
            }
            else {
                // If the terminal width couldn’t be matched for some reason, such
                // as the program’s stdout being connected to a file, then
                // fallback to the lines view.

                let colours = match term_colours {
                    TerminalColours::Always    => Colours::colourful(colour_scale()),
                    TerminalColours::Never | TerminalColours::Automatic => Colours::plain(),
                };

                if matches.opt_present("tree") {
                    let details = Details {
                        columns: None,
                        header: false,
                        recurse: dir_action.recurse_options(),
                        filter: filter.clone(),
                        xattr: false,
                        colours: colours,
                    };

                    Ok(View::Details(details))
                }
                else {
                    let lines = Lines {
                         colours: colours,
                    };

                    Ok(View::Lines(lines))
                }
            }
        };

        if matches.opt_present("long") {
            let long_options = long()?;

            if matches.opt_present("grid") {
                match other_options_scan() {
                    Ok(View::Grid(grid)) => return Ok(View::GridDetails(GridDetails { grid: grid, details: long_options })),
                    Ok(lines)            => return Ok(lines),
                    Err(e)               => return Err(e),
                };
            }
            else {
                return Ok(View::Details(long_options));
            }
        }

        long_options_scan()?;

        other_options_scan()
    }
}

/// The width of the terminal requested by the user.
#[derive(PartialEq, Debug)]
enum TerminalWidth {

    /// The user requested this specific number of columns.
    Set(usize),

    /// The terminal was found to have this number of columns.
    Terminal(usize),

    /// The user didn’t request any particular terminal width.
    Unset,
}

impl TerminalWidth {

    /// Determine a requested terminal width from the command-line arguments.
    ///
    /// Returns an error if a requested width doesn’t parse to an integer.
    fn deduce() -> Result<TerminalWidth, Misfire> {
        if let Some(columns) = var_os("COLUMNS").and_then(|s| s.into_string().ok()) {
            match columns.parse() {
                Ok(width)  => Ok(TerminalWidth::Set(width)),
                Err(e)     => Err(Misfire::FailedParse(e)),
            }
        }
        else if let Some((width, _)) = dimensions() {
            Ok(TerminalWidth::Terminal(width))
        }
        else {
            Ok(TerminalWidth::Unset)
        }
    }

    fn as_ref(&self) -> Option<&usize> {
        match *self {
            TerminalWidth::Set(ref width)
            | TerminalWidth::Terminal(ref width)    => Some(width),
            TerminalWidth::Unset                    => None,
        }
    }
}

impl Columns {
    fn deduce(matches: &getopts::Matches) -> Result<Columns, Misfire> {
        Ok(Columns {
            size_format: SizeFormat::deduce(matches)?,
            time_types:  TimeTypes::deduce(matches)?,
            inode:  matches.opt_present("inode"),
            links:  matches.opt_present("links"),
            blocks: matches.opt_present("blocks"),
            group:  matches.opt_present("group"),
            git:    cfg!(feature="git") && matches.opt_present("git"),
        })
    }
}

impl SizeFormat {

    /// Determine which file size to use in the file size column based on
    /// the user’s options.
    ///
    /// The default mode is to use the decimal prefixes, as they are the
    /// most commonly-understood, and don’t involve trying to parse large
    /// strings of digits in your head. Changing the format to anything else
    /// involves the `--binary` or `--bytes` flags, and these conflict with
    /// each other.
    fn deduce(matches: &getopts::Matches) -> Result<SizeFormat, Misfire> {
        let binary = matches.opt_present("binary");
        let bytes  = matches.opt_present("bytes");

        match (binary, bytes) {
            (true,  true )  => Err(Misfire::Conflict("binary", "bytes")),
            (true,  false)  => Ok(SizeFormat::BinaryBytes),
            (false, true )  => Ok(SizeFormat::JustBytes),
            (false, false)  => Ok(SizeFormat::DecimalBytes),
        }
    }
}

impl TimeTypes {

    /// Determine which of a file’s time fields should be displayed for it
    /// based on the user’s options.
    ///
    /// There are two separate ways to pick which fields to show: with a
    /// flag (such as `--modified`) or with a parameter (such as
    /// `--time=modified`). An error is signaled if both ways are used.
    ///
    /// It’s valid to show more than one column by passing in more than one
    /// option, but passing *no* options means that the user just wants to
    /// see the default set.
    fn deduce(matches: &getopts::Matches) -> Result<TimeTypes, Misfire> {
        let possible_word = matches.opt_str("time");
        let modified = matches.opt_present("modified");
        let created  = matches.opt_present("created");
        let accessed = matches.opt_present("accessed");

        if let Some(word) = possible_word {
            if modified {
                return Err(Misfire::Useless("modified", true, "time"));
            }
            else if created {
                return Err(Misfire::Useless("created", true, "time"));
            }
            else if accessed {
                return Err(Misfire::Useless("accessed", true, "time"));
            }

            match &*word {
                "mod" | "modified"  => Ok(TimeTypes { accessed: false, modified: true,  created: false }),
                "acc" | "accessed"  => Ok(TimeTypes { accessed: true,  modified: false, created: false }),
                "cr"  | "created"   => Ok(TimeTypes { accessed: false, modified: false, created: true  }),
                otherwise           => Err(Misfire::bad_argument("time", otherwise,
                                                                 &["modified", "accessed", "created"])),
            }
        }
        else if modified || created || accessed {
            Ok(TimeTypes { accessed: accessed, modified: modified, created: created })
        }
        else {
            Ok(TimeTypes::default())
        }
    }
}

/// Under what circumstances we should display coloured, rather than plain,
/// output to the terminal.
///
/// By default, we want to display the colours when stdout can display them.
/// Turning them on when output is going to, say, a pipe, would make programs
/// such as `grep` or `more` not work properly. So the `Automatic` mode does
/// this check and only displays colours when they can be truly appreciated.
#[derive(PartialEq, Debug)]
enum TerminalColours {

    /// Display them even when output isn’t going to a terminal.
    Always,

    /// Display them when output is going to a terminal, but not otherwise.
    Automatic,

    /// Never display them, even when output is going to a terminal.
    Never,
}

impl Default for TerminalColours {
    fn default() -> TerminalColours {
        TerminalColours::Automatic
    }
}

impl TerminalColours {

    /// Determine which terminal colour conditions to use.
    fn deduce(matches: &getopts::Matches) -> Result<TerminalColours, Misfire> {
        if let Some(word) = matches.opt_str("color").or(matches.opt_str("colour")) {
            match &*word {
                "always"              => Ok(TerminalColours::Always),
                "auto" | "automatic"  => Ok(TerminalColours::Automatic),
                "never"               => Ok(TerminalColours::Never),
                otherwise             => Err(Misfire::bad_argument("color", otherwise,
                                                                   &["always", "auto", "never"]))
            }
        }
        else {
            Ok(TerminalColours::default())
        }
    }
}
<commit_msg>Switch to better handling method<commit_after>use std::env::var_os;

use getopts;

use output::Colours;
use output::{Grid, Details, GridDetails, Lines};
use options::{FileFilter, DirAction, Misfire};
use output::column::{Columns, TimeTypes, SizeFormat};
use term::dimensions;
use fs::feature::xattr;

/// The **view** contains all information about how to format output.
#[derive(PartialEq, Debug, Clone)]
pub enum View {
    Details(Details),
    Grid(Grid),
    GridDetails(GridDetails),
    Lines(Lines),
}

impl View {

    /// Determine which view to use and all of that view’s arguments.
    pub fn deduce(matches: &getopts::Matches, filter: FileFilter, dir_action: DirAction) -> Result<View, Misfire> {
        use options::misfire::Misfire::*;

        let colour_scale = || {
            matches.opt_present("color-scale") || matches.opt_present("colour-scale")
        };

        let long = || {
            if matches.opt_present("across") && !matches.opt_present("grid") {
                Err(Useless("across", true, "long"))
            }
            else if matches.opt_present("oneline") {
                Err(Useless("oneline", true, "long"))
            }
            else {
                let term_colours = TerminalColours::deduce(matches)?;
                let colours = match term_colours {
                    TerminalColours::Always    => Colours::colourful(colour_scale()),
                    TerminalColours::Never     => Colours::plain(),
                    TerminalColours::Automatic => {
                        if dimensions().is_some() {
                            Colours::colourful(colour_scale())
                        }
                        else {
                            Colours::plain()
                        }
                    },
                };

                let details = Details {
                    columns: Some(Columns::deduce(matches)?),
                    header: matches.opt_present("header"),
                    recurse: dir_action.recurse_options(),
                    filter: filter.clone(),
                    xattr: xattr::ENABLED && matches.opt_present("extended"),
                    colours: colours,
                };

                Ok(details)
            }
        };

        let long_options_scan = || {
            for option in &[ "binary", "bytes", "inode", "links", "header", "blocks", "time", "group" ] {
                if matches.opt_present(option) {
                    return Err(Useless(option, false, "long"));
                }
            }

            if cfg!(feature="git") && matches.opt_present("git") {
                Err(Useless("git", false, "long"))
            }
            else if matches.opt_present("level") && !matches.opt_present("recurse") && !matches.opt_present("tree") {
                Err(Useless2("level", "recurse", "tree"))
            }
            else if xattr::ENABLED && matches.opt_present("extended") {
                Err(Useless("extended", false, "long"))
            }
            else {
                Ok(())
            }
        };

        let other_options_scan = || {
            let term_colours = TerminalColours::deduce(matches)?;
            let term_width   = TerminalWidth::deduce()?;

            if let Some(&width) = term_width.as_ref() {
                let colours = match term_colours {
                    TerminalColours::Always
                    | TerminalColours::Automatic => Colours::colourful(colour_scale()),
                    TerminalColours::Never     => Colours::plain(),
                };

                if matches.opt_present("oneline") {
                    if matches.opt_present("across") {
                        Err(Useless("across", true, "oneline"))
                    }
                    else {
                        let lines = Lines {
                             colours: colours,
                        };

                        Ok(View::Lines(lines))
                    }
                }
                else if matches.opt_present("tree") {
                    let details = Details {
                        columns: None,
                        header: false,
                        recurse: dir_action.recurse_options(),
                        filter: filter.clone(),  // TODO: clone
                        xattr: false,
                        colours: colours,
                    };

                    Ok(View::Details(details))
                }
                else {
                    let grid = Grid {
                        across: matches.opt_present("across"),
                        console_width: width,
                        colours: colours,
                    };

                    Ok(View::Grid(grid))
                }
            }
            else {
                // If the terminal width couldn’t be matched for some reason, such
                // as the program’s stdout being connected to a file, then
                // fallback to the lines view.

                let colours = match term_colours {
                    TerminalColours::Always    => Colours::colourful(colour_scale()),
                    TerminalColours::Never | TerminalColours::Automatic => Colours::plain(),
                };

                if matches.opt_present("tree") {
                    let details = Details {
                        columns: None,
                        header: false,
                        recurse: dir_action.recurse_options(),
                        filter: filter.clone(),
                        xattr: false,
                        colours: colours,
                    };

                    Ok(View::Details(details))
                }
                else {
                    let lines = Lines {
                         colours: colours,
                    };

                    Ok(View::Lines(lines))
                }
            }
        };

        if matches.opt_present("long") {
            let long_options = long()?;

            if matches.opt_present("grid") {
                match other_options_scan() {
                    Ok(View::Grid(grid)) => return Ok(View::GridDetails(GridDetails { grid: grid, details: long_options })),
                    Ok(lines)            => return Ok(lines),
                    Err(e)               => return Err(e),
                };
            }
            else {
                return Ok(View::Details(long_options));
            }
        }

        long_options_scan()?;

        other_options_scan()
    }
}

/// The width of the terminal requested by the user.
#[derive(PartialEq, Debug)]
enum TerminalWidth {

    /// The user requested this specific number of columns.
    Set(usize),

    /// The terminal was found to have this number of columns.
    Terminal(usize),

    /// The user didn’t request any particular terminal width.
    Unset,
}

impl TerminalWidth {

    /// Determine a requested terminal width from the command-line arguments.
    ///
    /// Returns an error if a requested width doesn’t parse to an integer.
    fn deduce() -> Result<TerminalWidth, Misfire> {
        if let Some(columns) = var_os("COLUMNS").and_then(|s| s.into_string().ok()) {
            match columns.parse() {
                Ok(width)  => Ok(TerminalWidth::Set(width)),
                Err(e)     => Err(Misfire::FailedParse(e)),
            }
        }
        else if let Some((width, _)) = dimensions() {
            Ok(TerminalWidth::Terminal(width))
        }
        else {
            Ok(TerminalWidth::Unset)
        }
    }

    fn as_ref(&self) -> Option<&usize> {
        match *self {
            TerminalWidth::Set(ref width)
            | TerminalWidth::Terminal(ref width)    => Some(width),
            TerminalWidth::Unset                    => None,
        }
    }
}

impl Columns {
    fn deduce(matches: &getopts::Matches) -> Result<Columns, Misfire> {
        Ok(Columns {
            size_format: SizeFormat::deduce(matches)?,
            time_types:  TimeTypes::deduce(matches)?,
            inode:  matches.opt_present("inode"),
            links:  matches.opt_present("links"),
            blocks: matches.opt_present("blocks"),
            group:  matches.opt_present("group"),
            git:    cfg!(feature="git") && matches.opt_present("git"),
        })
    }
}

impl SizeFormat {

    /// Determine which file size to use in the file size column based on
    /// the user’s options.
    ///
    /// The default mode is to use the decimal prefixes, as they are the
    /// most commonly-understood, and don’t involve trying to parse large
    /// strings of digits in your head. Changing the format to anything else
    /// involves the `--binary` or `--bytes` flags, and these conflict with
    /// each other.
    fn deduce(matches: &getopts::Matches) -> Result<SizeFormat, Misfire> {
        let binary = matches.opt_present("binary");
        let bytes  = matches.opt_present("bytes");

        match (binary, bytes) {
            (true,  true )  => Err(Misfire::Conflict("binary", "bytes")),
            (true,  false)  => Ok(SizeFormat::BinaryBytes),
            (false, true )  => Ok(SizeFormat::JustBytes),
            (false, false)  => Ok(SizeFormat::DecimalBytes),
        }
    }
}

impl TimeTypes {

    /// Determine which of a file’s time fields should be displayed for it
    /// based on the user’s options.
    ///
    /// There are two separate ways to pick which fields to show: with a
    /// flag (such as `--modified`) or with a parameter (such as
    /// `--time=modified`). An error is signaled if both ways are used.
    ///
    /// It’s valid to show more than one column by passing in more than one
    /// option, but passing *no* options means that the user just wants to
    /// see the default set.
    fn deduce(matches: &getopts::Matches) -> Result<TimeTypes, Misfire> {
        let possible_word = matches.opt_str("time");
        let modified = matches.opt_present("modified");
        let created  = matches.opt_present("created");
        let accessed = matches.opt_present("accessed");

        if let Some(word) = possible_word {
            if modified {
                return Err(Misfire::Useless("modified", true, "time"));
            }
            else if created {
                return Err(Misfire::Useless("created", true, "time"));
            }
            else if accessed {
                return Err(Misfire::Useless("accessed", true, "time"));
            }

            match &*word {
                "mod" | "modified"  => Ok(TimeTypes { accessed: false, modified: true,  created: false }),
                "acc" | "accessed"  => Ok(TimeTypes { accessed: true,  modified: false, created: false }),
                "cr"  | "created"   => Ok(TimeTypes { accessed: false, modified: false, created: true  }),
                otherwise           => Err(Misfire::bad_argument("time", otherwise,
                                                                 &["modified", "accessed", "created"])),
            }
        }
        else if modified || created || accessed {
            Ok(TimeTypes { accessed: accessed, modified: modified, created: created })
        }
        else {
            Ok(TimeTypes::default())
        }
    }
}

/// Under what circumstances we should display coloured, rather than plain,
/// output to the terminal.
///
/// By default, we want to display the colours when stdout can display them.
/// Turning them on when output is going to, say, a pipe, would make programs
/// such as `grep` or `more` not work properly. So the `Automatic` mode does
/// this check and only displays colours when they can be truly appreciated.
#[derive(PartialEq, Debug)]
enum TerminalColours {

    /// Display them even when output isn’t going to a terminal.
    Always,

    /// Display them when output is going to a terminal, but not otherwise.
    Automatic,

    /// Never display them, even when output is going to a terminal.
    Never,
}

impl Default for TerminalColours {
    fn default() -> TerminalColours {
        TerminalColours::Automatic
    }
}

impl TerminalColours {

    /// Determine which terminal colour conditions to use.
    fn deduce(matches: &getopts::Matches) -> Result<TerminalColours, Misfire> {
        if let Some(word) = matches.opt_str("color").or_else(|| matches.opt_str("colour")) {
            match &*word {
                "always"              => Ok(TerminalColours::Always),
                "auto" | "automatic"  => Ok(TerminalColours::Automatic),
                "never"               => Ok(TerminalColours::Never),
                otherwise             => Err(Misfire::bad_argument("color", otherwise,
                                                                   &["always", "auto", "never"]))
            }
        }
        else {
            Ok(TerminalColours::default())
        }
    }
}
<|endoftext|>