<commit_before>use {Result, StatsError};
use distribution::{Continuous, Distribution, Gamma, Univariate};
use rand::Rng;
use rand::distributions::{IndependentSample, Sample};
use statistics::*;

/// Implements the [Erlang](https://en.wikipedia.org/wiki/Erlang_distribution)
/// distribution
/// which is a special case of the
/// [Gamma](https://en.wikipedia.org/wiki/Gamma_distribution)
/// distribution
///
/// # Examples
///
/// ```
/// use statrs::distribution::{Erlang, Continuous};
/// use statrs::statistics::Mean;
/// use statrs::prec;
///
/// let n = Erlang::new(3, 1.0).unwrap();
/// assert_eq!(n.mean(), 3.0);
/// assert!(prec::almost_eq(n.pdf(2.0), 0.270670566473225383788, 1e-15));
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Erlang {
    g: Gamma,
}

impl Erlang {
    /// Constructs a new erlang distribution with a shape (k)
    /// of `shape` and a rate (λ) of `rate`
    ///
    /// # Errors
    ///
    /// Returns an error if `shape` or `rate` are `NaN`.
    /// Also returns an error if `shape == 0` or `rate <= 0.0`
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Erlang;
    ///
    /// let mut result = Erlang::new(3, 1.0);
    /// assert!(result.is_ok());
    ///
    /// result = Erlang::new(0, 0.0);
    /// assert!(result.is_err());
    /// ```
    pub fn new(shape: u64, rate: f64) -> Result<Erlang> {
        Gamma::new(shape as f64, rate).map(|g| Erlang { g: g })
    }

    /// Returns the shape (k) of the erlang distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Erlang;
    ///
    /// let n = Erlang::new(3, 1.0).unwrap();
    /// assert_eq!(n.shape(), 3);
    /// ```
    pub fn shape(&self) -> u64 {
        self.g.shape() as u64
    }

    /// Returns the rate (λ) of the erlang distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Erlang;
    ///
    /// let n = Erlang::new(3, 1.0).unwrap();
    /// assert_eq!(n.rate(), 1.0);
    /// ```
    pub fn rate(&self) -> f64 {
        self.g.rate()
    }
}

impl Sample<f64> for Erlang {
    /// Generate a random sample from a erlang
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn sample<R: Rng>(&mut self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl IndependentSample<f64> for Erlang {
    /// Generate a random independent sample from a erlang
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn ind_sample<R: Rng>(&self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl Distribution<f64> for Erlang {
    /// Generate a random sample from a erlang distribution using
    /// `r` as the source of randomness.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    /// use rand::StdRng;
    /// use statrs::distribution::{Erlang, Distribution};
    ///
    /// # fn main() {
    /// let mut r = rand::StdRng::new().unwrap();
    /// let n = Erlang::new(3, 1.0).unwrap();
    /// print!("{}", n.sample::<StdRng>(&mut r));
    /// # }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        self.g.sample(r)
    }
}

impl Univariate<f64, f64> for Erlang {
    /// Calculates the cumulative distribution function for the erlang
    /// distribution
    /// at `x`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// γ(k, λx)  (k - 1)!
    /// ```
    ///
    /// where `k` is the shape, `λ` is the rate, and `γ` is the lower
    /// incomplete gamma function
    fn cdf(&self, x: f64) -> f64 {
        self.g.cdf(x)
    }
}

impl Min<f64> for Erlang {
    /// Returns the minimum value in the domain of the
    /// erlang distribution representable by a double precision
    /// float
    ///
    /// # Formula
    ///
    /// ```ignore
    /// 0
    /// ```
    fn min(&self) -> f64 {
        self.g.min()
    }
}

impl Max<f64> for Erlang {
    /// Returns the maximum value in the domain of the
    /// erlang distribution representable by a double precision
    /// float
    ///
    /// # Formula
    ///
    /// ```ignore
    /// INF
    /// ```
    fn max(&self) -> f64 {
        self.g.max()
    }
}

impl Mean<f64> for Erlang {
    /// Returns the mean of the erlang distribution
    ///
    /// # Remarks
    ///
    /// Returns `shape` if `rate == f64::INFINITY`. This behavior
    /// is borrowed from the Math.NET implementation
    ///
    /// # Formula
    ///
    /// ```ignore
    /// k / λ
    /// ```
    ///
    /// where `k` is the shape and `λ` is the rate
    fn mean(&self) -> f64 {
        self.g.mean()
    }
}

impl Variance<f64> for Erlang {
    /// Returns the variance of the erlang distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// k / λ^2
    /// ```
    ///
    /// where `α` is the shape and `λ` is the rate
    fn variance(&self) -> f64 {
        self.g.variance()
    }

    /// Returns the standard deviation of the erlang distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// sqrt(k) / λ
    /// ```
    ///
    /// where `k` is the shape and `λ` is the rate
    fn std_dev(&self) -> f64 {
        self.g.std_dev()
    }
}

impl Entropy<f64> for Erlang {
    /// Returns the entropy of the erlang distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// k - ln(λ) + ln(Γ(k)) + (1 - k) * ψ(k)
    /// ```
    ///
    /// where `k` is the shape, `λ` is the rate, `Γ` is the gamma function,
    /// and `ψ` is the digamma function
    fn entropy(&self) -> f64 {
        self.g.entropy()
    }
}

impl Skewness<f64> for Erlang {
    /// Returns the skewness of the erlang distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// 2 / sqrt(k)
    /// ```
    ///
    /// where `k` is the shape
    fn skewness(&self) -> f64 {
        self.g.skewness()
    }
}

impl Mode<f64> for Erlang {
    /// Returns the mode for the erlang distribution
    ///
    /// # Remarks
    ///
    /// Returns `shape` if `rate ==f64::INFINITY`. This behavior
    /// is borrowed from the Math.NET implementation
    ///
    /// # Panics
    ///
    /// If `k < 1`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// (k - 1) / λ
    /// ```
    ///
    /// where `k` is the shape and `λ` is the rate
    fn mode(&self) -> f64 {
        assert!(
            self.g.shape() >= 1.0,
            format!("{}", StatsError::ArgGte("shape", 1.0))
        );
        self.g.mode()
    }
}

impl Continuous<f64, f64> for Erlang {
    /// Calculates the probability density function for the erlang distribution
    /// at `x`
    ///
    /// # Remarks
    ///
    /// Returns `NAN` if any of `shape` or `rate` are `INF`
    /// or if `x` is `INF`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// (λ^k / Γ(k)) * x^(k - 1) * e^(-λ * x)
    /// ```
    ///
    /// where `k` is the shape, `λ` is the rate, and `Γ` is the gamma function
    fn pdf(&self, x: f64) -> f64 {
        self.g.pdf(x)
    }

    /// Calculates the log probability density function for the erlang
    /// distribution
    /// at `x`
    ///
    /// # Remarks
    ///
    /// Returns `NAN` if any of `shape` or `rate` are `INF`
    /// or if `x` is `INF`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// ln((λ^k / Γ(k)) * x^(k - 1) * e ^(-λ * x))
    /// ```
    ///
    /// where `k` is the shape, `λ` is the rate, and `Γ` is the gamma function
    fn ln_pdf(&self, x: f64) -> f64 {
        self.g.ln_pdf(x)
    }
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[cfg(test)]
mod test {
    use std::f64;
    use distribution::Erlang;
    use distribution::internal::*;

    fn try_create(shape: u64, rate: f64) -> Erlang {
        let n = Erlang::new(shape, rate);
        assert!(n.is_ok());
        n.unwrap()
    }

    fn create_case(shape: u64, rate: f64) {
        let n = try_create(shape, rate);
        assert_eq!(shape, n.shape());
        assert_eq!(rate, n.rate());
    }

    fn bad_create_case(shape: u64, rate: f64) {
        let n = Erlang::new(shape, rate);
        assert!(n.is_err());
    }

    #[test]
    fn test_create() {
        create_case(1, 0.1);
        create_case(1, 1.0);
        create_case(10, 10.0);
        create_case(10, 1.0);
        create_case(10, f64::INFINITY);
    }

    #[test]
    fn test_bad_create() {
        bad_create_case(0, 1.0);
        bad_create_case(1, 0.0);
        bad_create_case(1, f64::NAN);
        bad_create_case(1, -1.0);
    }

    #[test]
    fn test_continuous() {
        test::check_continuous_distribution(&try_create(1, 2.5), 0.0, 20.0);
        test::check_continuous_distribution(&try_create(2, 1.5), 0.0, 20.0);
        test::check_continuous_distribution(&try_create(3, 0.5), 0.0, 20.0);
    }
}
<commit_msg>fix: remove panic from mode as case is impossible<commit_after>use {Result, StatsError};
use distribution::{Continuous, Distribution, Gamma, Univariate};
use rand::Rng;
use rand::distributions::{IndependentSample, Sample};
use statistics::*;

/// Implements the [Erlang](https://en.wikipedia.org/wiki/Erlang_distribution)
/// distribution
/// which is a special case of the
/// [Gamma](https://en.wikipedia.org/wiki/Gamma_distribution)
/// distribution
///
/// # Examples
///
/// ```
/// use statrs::distribution::{Erlang, Continuous};
/// use statrs::statistics::Mean;
/// use statrs::prec;
///
/// let n = Erlang::new(3, 1.0).unwrap();
/// assert_eq!(n.mean(), 3.0);
/// assert!(prec::almost_eq(n.pdf(2.0), 0.270670566473225383788, 1e-15));
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Erlang {
    g: Gamma,
}

impl Erlang {
    /// Constructs a new erlang distribution with a shape (k)
    /// of `shape` and a rate (λ) of `rate`
    ///
    /// # Errors
    ///
    /// Returns an error if `shape` or `rate` are `NaN`.
    /// Also returns an error if `shape == 0` or `rate <= 0.0`
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Erlang;
    ///
    /// let mut result = Erlang::new(3, 1.0);
    /// assert!(result.is_ok());
    ///
    /// result = Erlang::new(0, 0.0);
    /// assert!(result.is_err());
    /// ```
    pub fn new(shape: u64, rate: f64) -> Result<Erlang> {
        Gamma::new(shape as f64, rate).map(|g| Erlang { g: g })
    }

    /// Returns the shape (k) of the erlang distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Erlang;
    ///
    /// let n = Erlang::new(3, 1.0).unwrap();
    /// assert_eq!(n.shape(), 3);
    /// ```
    pub fn shape(&self) -> u64 {
        self.g.shape() as u64
    }

    /// Returns the rate (λ) of the erlang distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Erlang;
    ///
    /// let n = Erlang::new(3, 1.0).unwrap();
    /// assert_eq!(n.rate(), 1.0);
    /// ```
    pub fn rate(&self) -> f64 {
        self.g.rate()
    }
}

impl Sample<f64> for Erlang {
    /// Generate a random sample from a erlang
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn sample<R: Rng>(&mut self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl IndependentSample<f64> for Erlang {
    /// Generate a random independent sample from a erlang
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn ind_sample<R: Rng>(&self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl Distribution<f64> for Erlang {
    /// Generate a random sample from a erlang distribution using
    /// `r` as the source of randomness.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    /// use rand::StdRng;
    /// use statrs::distribution::{Erlang, Distribution};
    ///
    /// # fn main() {
    /// let mut r = rand::StdRng::new().unwrap();
    /// let n = Erlang::new(3, 1.0).unwrap();
    /// print!("{}", n.sample::<StdRng>(&mut r));
    /// # }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        self.g.sample(r)
    }
}

impl Univariate<f64, f64> for Erlang {
    /// Calculates the cumulative distribution function for the erlang
    /// distribution
    /// at `x`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// γ(k, λx)  (k - 1)!
    /// ```
    ///
    /// where `k` is the shape, `λ` is the rate, and `γ` is the lower
    /// incomplete gamma function
    fn cdf(&self, x: f64) -> f64 {
        self.g.cdf(x)
    }
}

impl Min<f64> for Erlang {
    /// Returns the minimum value in the domain of the
    /// erlang distribution representable by a double precision
    /// float
    ///
    /// # Formula
    ///
    /// ```ignore
    /// 0
    /// ```
    fn min(&self) -> f64 {
        self.g.min()
    }
}

impl Max<f64> for Erlang {
    /// Returns the maximum value in the domain of the
    /// erlang distribution representable by a double precision
    /// float
    ///
    /// # Formula
    ///
    /// ```ignore
    /// INF
    /// ```
    fn max(&self) -> f64 {
        self.g.max()
    }
}

impl Mean<f64> for Erlang {
    /// Returns the mean of the erlang distribution
    ///
    /// # Remarks
    ///
    /// Returns `shape` if `rate == f64::INFINITY`. This behavior
    /// is borrowed from the Math.NET implementation
    ///
    /// # Formula
    ///
    /// ```ignore
    /// k / λ
    /// ```
    ///
    /// where `k` is the shape and `λ` is the rate
    fn mean(&self) -> f64 {
        self.g.mean()
    }
}

impl Variance<f64> for Erlang {
    /// Returns the variance of the erlang distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// k / λ^2
    /// ```
    ///
    /// where `α` is the shape and `λ` is the rate
    fn variance(&self) -> f64 {
        self.g.variance()
    }

    /// Returns the standard deviation of the erlang distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// sqrt(k) / λ
    /// ```
    ///
    /// where `k` is the shape and `λ` is the rate
    fn std_dev(&self) -> f64 {
        self.g.std_dev()
    }
}

impl Entropy<f64> for Erlang {
    /// Returns the entropy of the erlang distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// k - ln(λ) + ln(Γ(k)) + (1 - k) * ψ(k)
    /// ```
    ///
    /// where `k` is the shape, `λ` is the rate, `Γ` is the gamma function,
    /// and `ψ` is the digamma function
    fn entropy(&self) -> f64 {
        self.g.entropy()
    }
}

impl Skewness<f64> for Erlang {
    /// Returns the skewness of the erlang distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// 2 / sqrt(k)
    /// ```
    ///
    /// where `k` is the shape
    fn skewness(&self) -> f64 {
        self.g.skewness()
    }
}

impl Mode<f64> for Erlang {
    /// Returns the mode for the erlang distribution
    ///
    /// # Remarks
    ///
    /// Returns `shape` if `rate ==f64::INFINITY`. This behavior
    /// is borrowed from the Math.NET implementation
    ///
    /// # Formula
    ///
    /// ```ignore
    /// (k - 1) / λ
    /// ```
    ///
    /// where `k` is the shape and `λ` is the rate
    fn mode(&self) -> f64 {
        self.g.mode()
    }
}

impl Continuous<f64, f64> for Erlang {
    /// Calculates the probability density function for the erlang distribution
    /// at `x`
    ///
    /// # Remarks
    ///
    /// Returns `NAN` if any of `shape` or `rate` are `INF`
    /// or if `x` is `INF`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// (λ^k / Γ(k)) * x^(k - 1) * e^(-λ * x)
    /// ```
    ///
    /// where `k` is the shape, `λ` is the rate, and `Γ` is the gamma function
    fn pdf(&self, x: f64) -> f64 {
        self.g.pdf(x)
    }

    /// Calculates the log probability density function for the erlang
    /// distribution
    /// at `x`
    ///
    /// # Remarks
    ///
    /// Returns `NAN` if any of `shape` or `rate` are `INF`
    /// or if `x` is `INF`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// ln((λ^k / Γ(k)) * x^(k - 1) * e ^(-λ * x))
    /// ```
    ///
    /// where `k` is the shape, `λ` is the rate, and `Γ` is the gamma function
    fn ln_pdf(&self, x: f64) -> f64 {
        self.g.ln_pdf(x)
    }
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[cfg(test)]
mod test {
    use std::f64;
    use distribution::Erlang;
    use distribution::internal::*;

    fn try_create(shape: u64, rate: f64) -> Erlang {
        let n = Erlang::new(shape, rate);
        assert!(n.is_ok());
        n.unwrap()
    }

    fn create_case(shape: u64, rate: f64) {
        let n = try_create(shape, rate);
        assert_eq!(shape, n.shape());
        assert_eq!(rate, n.rate());
    }

    fn bad_create_case(shape: u64, rate: f64) {
        let n = Erlang::new(shape, rate);
        assert!(n.is_err());
    }

    #[test]
    fn test_create() {
        create_case(1, 0.1);
        create_case(1, 1.0);
        create_case(10, 10.0);
        create_case(10, 1.0);
        create_case(10, f64::INFINITY);
    }

    #[test]
    fn test_bad_create() {
        bad_create_case(0, 1.0);
        bad_create_case(1, 0.0);
        bad_create_case(1, f64::NAN);
        bad_create_case(1, -1.0);
    }

    #[test]
    fn test_continuous() {
        test::check_continuous_distribution(&try_create(1, 2.5), 0.0, 20.0);
        test::check_continuous_distribution(&try_create(2, 1.5), 0.0, 20.0);
        test::check_continuous_distribution(&try_create(3, 0.5), 0.0, 20.0);
    }
}
<|endoftext|>


<commit_before>//! This module provides implementations for basic decoders: little endian and big endian.
//!

use super::BasicDecode;
use byteordered::{ByteOrdered, Endianness};
use error::Result;
use std::io::Read;

/// A basic decoder of DICOM primitive elements in little endian.
#[derive(Debug, Default, Clone, PartialEq)]
pub struct LittleEndianBasicDecoder;

impl BasicDecode for LittleEndianBasicDecoder {
    fn endianness(&self) -> Endianness {
        Endianness::Little
    }

    fn decode_us<S>(&self, source: S) -> Result<u16>
    where
        S: Read,
    {
        ByteOrdered::le(source).read_u16().map_err(Into::into)
    }

    fn decode_ul<S>(&self, source: S) -> Result<u32>
    where
        S: Read,
    {
        ByteOrdered::le(source).read_u32().map_err(Into::into)
    }

    fn decode_ss<S>(&self, source: S) -> Result<i16>
    where
        S: Read,
    {
        ByteOrdered::le(source).read_i16().map_err(Into::into)
    }

    fn decode_sl<S>(&self, source: S) -> Result<i32>
    where
        S: Read,
    {
        ByteOrdered::le(source).read_i32().map_err(Into::into)
    }

    fn decode_fl<S>(&self, source: S) -> Result<f32>
    where
        S: Read,
    {
        ByteOrdered::le(source).read_f32().map_err(Into::into)
    }

    fn decode_fd<S>(&self, source: S) -> Result<f64>
    where
        S: Read,
    {
        ByteOrdered::le(source).read_f64().map_err(Into::into)
    }
}

/// A basic decoder of DICOM primitive elements in big endian.
#[derive(Debug, Default, Clone, PartialEq)]
pub struct BigEndianBasicDecoder;

impl BasicDecode for BigEndianBasicDecoder {
    fn endianness(&self) -> Endianness {
        Endianness::Big
    }

    fn decode_us<S>(&self, source: S) -> Result<u16>
    where
        S: Read,
    {
        ByteOrdered::be(source).read_u16().map_err(Into::into)
    }

    fn decode_ul<S>(&self, source: S) -> Result<u32>
    where
        S: Read,
    {
        ByteOrdered::be(source).read_u32().map_err(Into::into)
    }

    fn decode_ss<S>(&self, source: S) -> Result<i16>
    where
        S: Read,
    {
        ByteOrdered::be(source).read_i16().map_err(Into::into)
    }

    fn decode_sl<S>(&self, source: S) -> Result<i32>
    where
        S: Read,
    {
        ByteOrdered::be(source).read_i32().map_err(Into::into)
    }

    fn decode_fl<S>(&self, source: S) -> Result<f32>
    where
        S: Read,
    {
        ByteOrdered::be(source).read_f32().map_err(Into::into)
    }

    fn decode_fd<S>(&self, source: S) -> Result<f64>
    where
        S: Read,
    {
        ByteOrdered::be(source).read_f64().map_err(Into::into)
    }
}

/// A basic decoder with support for both Little Endian an Big Endian
/// encoding, decided at run-time. Since only two values are possible,
/// this enum may become more efficient than the use of a trait object.
#[derive(Debug, Clone, PartialEq)]
pub enum BasicDecoder {
    /// Decode in Little Endian
    LE(LittleEndianBasicDecoder),
    /// Decode in Big Endian
    BE(BigEndianBasicDecoder),
}

use self::BasicDecoder::{BE, LE};

impl From<Endianness> for BasicDecoder {
    fn from(endianness: Endianness) -> BasicDecoder {
        match endianness {
            Endianness::Little => LE(LittleEndianBasicDecoder::default()),
            Endianness::Big => BE(BigEndianBasicDecoder::default()),
        }
    }
}

macro_rules! for_both {
    ($s: expr, |$e: ident| $f: expr) => {
        match *$s {
            LE(ref $e) => $f,
            BE(ref $e) => $f
        }
    }
}

impl BasicDecode for BasicDecoder {
    fn endianness(&self) -> Endianness {
        match *self {
            LE(_) => Endianness::Little,
            BE(_) => Endianness::Big,
        }
    }

    fn decode_us<S>(&self, source: S) -> Result<u16>
    where
        S: Read,
    {
        for_both!(self, |e| e.decode_us(source))
    }

    fn decode_ul<S>(&self, source: S) -> Result<u32>
    where
        S: Read,
    {
        for_both!(self, |e| e.decode_ul(source))
    }

    fn decode_ss<S>(&self, source: S) -> Result<i16>
    where
        S: Read,
    {
        for_both!(self, |e| e.decode_ss(source))
    }

    fn decode_sl<S>(&self, source: S) -> Result<i32>
    where
        S: Read,
    {
        for_both!(self, |e| e.decode_sl(source))
    }

    fn decode_fl<S>(&self, source: S) -> Result<f32>
    where
        S: Read,
    {
        for_both!(self, |e| e.decode_fl(source))
    }

    fn decode_fd<S>(&self, source: S) -> Result<f64>
    where
        S: Read,
    {
        for_both!(self, |e| e.decode_fd(source))
    }
}
<commit_msg>[parse] Improve + test basic decoder<commit_after>//! This module provides implementations for basic decoders: little endian and big endian.
//!

use super::BasicDecode;
use byteordered::{ByteOrdered, Endianness};
use error::Result;
use std::io::Read;

/// A basic decoder of DICOM primitive elements in little endian.
#[derive(Debug, Default, Clone, PartialEq)]
pub struct LittleEndianBasicDecoder;

impl BasicDecode for LittleEndianBasicDecoder {
    fn endianness(&self) -> Endianness {
        Endianness::Little
    }

    fn decode_us<S>(&self, source: S) -> Result<u16>
    where
        S: Read,
    {
        ByteOrdered::le(source).read_u16().map_err(Into::into)
    }

    fn decode_ul<S>(&self, source: S) -> Result<u32>
    where
        S: Read,
    {
        ByteOrdered::le(source).read_u32().map_err(Into::into)
    }

    fn decode_ss<S>(&self, source: S) -> Result<i16>
    where
        S: Read,
    {
        ByteOrdered::le(source).read_i16().map_err(Into::into)
    }

    fn decode_sl<S>(&self, source: S) -> Result<i32>
    where
        S: Read,
    {
        ByteOrdered::le(source).read_i32().map_err(Into::into)
    }

    fn decode_fl<S>(&self, source: S) -> Result<f32>
    where
        S: Read,
    {
        ByteOrdered::le(source).read_f32().map_err(Into::into)
    }

    fn decode_fd<S>(&self, source: S) -> Result<f64>
    where
        S: Read,
    {
        ByteOrdered::le(source).read_f64().map_err(Into::into)
    }
}

/// A basic decoder of DICOM primitive elements in big endian.
#[derive(Debug, Default, Clone, PartialEq)]
pub struct BigEndianBasicDecoder;

impl BasicDecode for BigEndianBasicDecoder {
    fn endianness(&self) -> Endianness {
        Endianness::Big
    }

    fn decode_us<S>(&self, source: S) -> Result<u16>
    where
        S: Read,
    {
        ByteOrdered::be(source).read_u16().map_err(Into::into)
    }

    fn decode_ul<S>(&self, source: S) -> Result<u32>
    where
        S: Read,
    {
        ByteOrdered::be(source).read_u32().map_err(Into::into)
    }

    fn decode_ss<S>(&self, source: S) -> Result<i16>
    where
        S: Read,
    {
        ByteOrdered::be(source).read_i16().map_err(Into::into)
    }

    fn decode_sl<S>(&self, source: S) -> Result<i32>
    where
        S: Read,
    {
        ByteOrdered::be(source).read_i32().map_err(Into::into)
    }

    fn decode_fl<S>(&self, source: S) -> Result<f32>
    where
        S: Read,
    {
        ByteOrdered::be(source).read_f32().map_err(Into::into)
    }

    fn decode_fd<S>(&self, source: S) -> Result<f64>
    where
        S: Read,
    {
        ByteOrdered::be(source).read_f64().map_err(Into::into)
    }
}

/// A basic decoder with support for both Little Endian an Big Endian
/// encoding, decided at run-time. Since only two values are possible,
/// this enum may become more efficient than the use of a trait object.
#[derive(Debug, Clone, PartialEq)]
pub enum BasicDecoder {
    /// Decode in Little Endian
    LE(LittleEndianBasicDecoder),
    /// Decode in Big Endian
    BE(BigEndianBasicDecoder),
}

impl BasicDecoder {
    pub fn new(endianness: Endianness) -> Self {
        match endianness {
            Endianness::Little => LE(LittleEndianBasicDecoder::default()),
            Endianness::Big => BE(BigEndianBasicDecoder::default()),
        }
    }
}

use self::BasicDecoder::{BE, LE};

impl From<Endianness> for BasicDecoder {
    fn from(endianness: Endianness) -> Self {
        BasicDecoder::new(endianness)
    }
}

macro_rules! for_both {
    ($s: expr, |$e: ident| $f: expr) => {
        match *$s {
            LE(ref $e) => $f,
            BE(ref $e) => $f
        }
    }
}

impl BasicDecode for BasicDecoder {
    fn endianness(&self) -> Endianness {
        match *self {
            LE(_) => Endianness::Little,
            BE(_) => Endianness::Big,
        }
    }

    fn decode_us<S>(&self, source: S) -> Result<u16>
    where
        S: Read,
    {
        for_both!(self, |e| e.decode_us(source))
    }

    fn decode_ul<S>(&self, source: S) -> Result<u32>
    where
        S: Read,
    {
        for_both!(self, |e| e.decode_ul(source))
    }

    fn decode_ss<S>(&self, source: S) -> Result<i16>
    where
        S: Read,
    {
        for_both!(self, |e| e.decode_ss(source))
    }

    fn decode_sl<S>(&self, source: S) -> Result<i32>
    where
        S: Read,
    {
        for_both!(self, |e| e.decode_sl(source))
    }

    fn decode_fl<S>(&self, source: S) -> Result<f32>
    where
        S: Read,
    {
        for_both!(self, |e| e.decode_fl(source))
    }

    fn decode_fd<S>(&self, source: S) -> Result<f64>
    where
        S: Read,
    {
        for_both!(self, |e| e.decode_fd(source))
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_read_integers() {
        let data: &[u8] = &[
            0xC3, 0x3C, 0x33, 0xCC
        ];

        let le = LittleEndianBasicDecoder;
        let be = BigEndianBasicDecoder;

        assert_eq!(le.decode_us(data).unwrap(), 0x3CC3);
        assert_eq!(be.decode_us(data).unwrap(), 0xC33C);
        assert_eq!(le.decode_ul(data).unwrap(), 0xCC333CC3);
        assert_eq!(be.decode_ul(data).unwrap(), 0xC33C33CC);

        let le = BasicDecoder::new(Endianness::Little);
        let be = BasicDecoder::new(Endianness::Big);

        assert_eq!(le.decode_us(data).unwrap(), 0x3CC3);
        assert_eq!(be.decode_us(data).unwrap(), 0xC33C);
        assert_eq!(le.decode_ul(data).unwrap(), 0xCC333CC3);
        assert_eq!(be.decode_ul(data).unwrap(), 0xC33C33CC);
    }
}<|endoftext|>


<commit_before>//! FIXME: write short doc here

mod load_cargo;
mod analysis_stats;
mod analysis_bench;
mod progress_report;

use std::{error::Error, fmt::Write, io::Read, path::PathBuf};

use pico_args::Arguments;
use ra_ide::{file_structure, Analysis};
use ra_prof::profile;
use ra_syntax::{AstNode, SourceFile};

type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>;

fn main() -> Result<()> {
    env_logger::try_init()?;

    let command = Command::from_args()?;
    command.run()?;

    Ok(())
}

#[derive(Clone, Copy)]
pub enum Verbosity {
    Spammy,
    Verbose,
    Normal,
    Quiet,
}

impl Verbosity {
    fn is_verbose(self) -> bool {
        match self {
            Verbosity::Verbose | Verbosity::Spammy => true,
            _ => false,
        }
    }
    fn is_spammy(self) -> bool {
        match self {
            Verbosity::Spammy => true,
            _ => false,
        }
    }
}

enum Command {
    Parse {
        no_dump: bool,
    },
    Symbols,
    Highlight {
        rainbow: bool,
    },
    Stats {
        verbosity: Verbosity,
        randomize: bool,
        memory_usage: bool,
        only: Option<String>,
        with_deps: bool,
        path: PathBuf,
    },
    Bench {
        verbose: bool,
        path: PathBuf,
        op: analysis_bench::Op,
    },
    HelpPrinted,
}

impl Command {
    fn from_args() -> Result<Command> {
        let mut matches = Arguments::from_env();
        let subcommand = matches.subcommand()?.unwrap_or_default();

        let command = match subcommand.as_str() {
            "parse" => {
                if matches.contains(["-h", "--help"]) {
                    eprintln!(
                        "\
ra-cli-parse

USAGE:
    ra_cli parse [FLAGS]

FLAGS:
    -h, --help       Prints help inforamtion
        --no-dump"
                    );
                    return Ok(Command::HelpPrinted);
                }

                let no_dump = matches.contains("--no-dump");
                matches.finish().or_else(handle_extra_flags)?;
                Command::Parse { no_dump }
            }
            "symbols" => {
                if matches.contains(["-h", "--help"]) {
                    eprintln!(
                        "\
ra-cli-symbols

USAGE:
    ra_cli highlight [FLAGS]

FLAGS:
    -h, --help    Prints help inforamtion"
                    );
                    return Ok(Command::HelpPrinted);
                }

                matches.finish().or_else(handle_extra_flags)?;

                Command::Symbols
            }
            "highlight" => {
                if matches.contains(["-h", "--help"]) {
                    eprintln!(
                        "\
ra-cli-highlight

USAGE:
    ra_cli highlight [FLAGS]

FLAGS:
    -h, --help       Prints help information
    -r, --rainbow"
                    );
                    return Ok(Command::HelpPrinted);
                }

                let rainbow = matches.contains(["-r", "--rainbow"]);
                matches.finish().or_else(handle_extra_flags)?;
                Command::Highlight { rainbow }
            }
            "analysis-stats" => {
                if matches.contains(["-h", "--help"]) {
                    eprintln!(
                        "\
ra-cli-analysis-stats

USAGE:
    ra_cli analysis-stats [FLAGS] [OPTIONS] [PATH]

FLAGS:
    -h, --help            Prints help information
        --memory-usage
    -v, --verbose
    -q, --quiet

OPTIONS:
    -o <ONLY>

ARGS:
    <PATH>"
                    );
                    return Ok(Command::HelpPrinted);
                }

                let verbosity = match (
                    matches.contains(["-vv", "--spammy"]),
                    matches.contains(["-v", "--verbose"]),
                    matches.contains(["-q", "--quiet"]),
                ) {
                    (true, _, true) => Err("Invalid flags: -q conflicts with -vv")?,
                    (true, _, false) => Verbosity::Spammy,
                    (false, false, false) => Verbosity::Normal,
                    (false, false, true) => Verbosity::Quiet,
                    (false, true, false) => Verbosity::Verbose,
                    (false, true, true) => Err("Invalid flags: -q conflicts with -v")?,
                };
                let randomize = matches.contains("--randomize");
                let memory_usage = matches.contains("--memory-usage");
                let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?;
                let with_deps: bool = matches.contains("--with-deps");
                let path = {
                    let mut trailing = matches.free()?;
                    if trailing.len() != 1 {
                        Err("Invalid flags")?;
                    }
                    trailing.pop().unwrap().into()
                };

                Command::Stats { verbosity, randomize, memory_usage, only, with_deps, path }
            }
            "analysis-bench" => {
                if matches.contains(["-h", "--help"]) {
                    eprintln!(
                        "\
ra_cli-analysis-bench

USAGE:
    ra_cli analysis-bench [FLAGS] [OPTIONS] [PATH]

FLAGS:
    -h, --help        Prints help information
    -v, --verbose

OPTIONS:
    --complete <PATH:LINE:COLUMN>    Compute completions at this location
    --highlight <PATH>               Hightlight this file

ARGS:
    <PATH>    Project to analyse"
                    );
                    return Ok(Command::HelpPrinted);
                }

                let verbose = matches.contains(["-v", "--verbose"]);
                let path: PathBuf = matches.opt_value_from_str("--path")?.unwrap_or_default();
                let highlight_path: Option<String> = matches.opt_value_from_str("--highlight")?;
                let complete_path: Option<String> = matches.opt_value_from_str("--complete")?;
                let goto_def_path: Option<String> = matches.opt_value_from_str("--goto-def")?;
                let op = match (highlight_path, complete_path, goto_def_path) {
                    (Some(path), None, None) => analysis_bench::Op::Highlight { path: path.into() },
                    (None, Some(position), None) => analysis_bench::Op::Complete(position.parse()?),
                    (None, None, Some(position)) => analysis_bench::Op::GotoDef(position.parse()?),
                    _ => panic!(
                        "exactly one of  `--highlight`, `--complete` or `--goto-def` must be set"
                    ),
                };
                Command::Bench { verbose, path, op }
            }
            _ => {
                eprintln!(
                    "\
ra-cli

USAGE:
    ra_cli <SUBCOMMAND>

FLAGS:
    -h, --help        Prints help information

SUBCOMMANDS:
    analysis-bench
    analysis-stats
    highlight
    parse
    symbols"
                );
                return Ok(Command::HelpPrinted);
            }
        };
        Ok(command)
    }

    fn run(self) -> Result<()> {
        match self {
            Command::Parse { no_dump } => {
                let _p = profile("parsing");
                let file = file()?;
                if !no_dump {
                    println!("{:#?}", file.syntax());
                }
                std::mem::forget(file);
            }
            Command::Symbols => {
                let file = file()?;
                for s in file_structure(&file) {
                    println!("{:?}", s);
                }
            }
            Command::Highlight { rainbow } => {
                let (analysis, file_id) = Analysis::from_single_file(read_stdin()?);
                let html = analysis.highlight_as_html(file_id, rainbow).unwrap();
                println!("{}", html);
            }
            Command::Stats { verbosity, randomize, memory_usage, only, with_deps, path } => {
                analysis_stats::run(
                    verbosity,
                    memory_usage,
                    path.as_ref(),
                    only.as_ref().map(String::as_ref),
                    with_deps,
                    randomize,
                )?;
            }
            Command::Bench { verbose, path, op } => {
                analysis_bench::run(verbose, path.as_ref(), op)?;
            }
            Command::HelpPrinted => (),
        }
        Ok(())
    }
}

fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
    if let pico_args::Error::UnusedArgsLeft(flags) = e {
        let mut invalid_flags = String::new();
        for flag in flags {
            write!(&mut invalid_flags, "{}, ", flag)?;
        }
        let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2);
        Err(format!("Invalid flags: {}", invalid_flags).into())
    } else {
        Err(e.to_string().into())
    }
}

fn file() -> Result<SourceFile> {
    let text = read_stdin()?;
    Ok(SourceFile::parse(&text).tree())
}

fn read_stdin() -> Result<String> {
    let mut buff = String::new();
    std::io::stdin().read_to_string(&mut buff)?;
    Ok(buff)
}
<commit_msg>Move interesting stuff to main<commit_after>//! FIXME: write short doc here

mod load_cargo;
mod analysis_stats;
mod analysis_bench;
mod progress_report;

use std::{error::Error, fmt::Write, io::Read, path::PathBuf};

use pico_args::Arguments;
use ra_ide::{file_structure, Analysis};
use ra_prof::profile;
use ra_syntax::{AstNode, SourceFile};

type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>;

fn main() -> Result<()> {
    env_logger::try_init()?;

    let command = Command::from_args()?;
    match command {
        Command::Parse { no_dump } => {
            let _p = profile("parsing");
            let file = file()?;
            if !no_dump {
                println!("{:#?}", file.syntax());
            }
            std::mem::forget(file);
        }
        Command::Symbols => {
            let file = file()?;
            for s in file_structure(&file) {
                println!("{:?}", s);
            }
        }
        Command::Highlight { rainbow } => {
            let (analysis, file_id) = Analysis::from_single_file(read_stdin()?);
            let html = analysis.highlight_as_html(file_id, rainbow).unwrap();
            println!("{}", html);
        }
        Command::Stats { verbosity, randomize, memory_usage, only, with_deps, path } => {
            analysis_stats::run(
                verbosity,
                memory_usage,
                path.as_ref(),
                only.as_ref().map(String::as_ref),
                with_deps,
                randomize,
            )?;
        }
        Command::Bench { verbose, path, op } => {
            analysis_bench::run(verbose, path.as_ref(), op)?;
        }
        Command::HelpPrinted => (),
    }

    Ok(())
}

#[derive(Clone, Copy)]
pub enum Verbosity {
    Spammy,
    Verbose,
    Normal,
    Quiet,
}

impl Verbosity {
    fn is_verbose(self) -> bool {
        match self {
            Verbosity::Verbose | Verbosity::Spammy => true,
            _ => false,
        }
    }
    fn is_spammy(self) -> bool {
        match self {
            Verbosity::Spammy => true,
            _ => false,
        }
    }
}

enum Command {
    Parse {
        no_dump: bool,
    },
    Symbols,
    Highlight {
        rainbow: bool,
    },
    Stats {
        verbosity: Verbosity,
        randomize: bool,
        memory_usage: bool,
        only: Option<String>,
        with_deps: bool,
        path: PathBuf,
    },
    Bench {
        verbose: bool,
        path: PathBuf,
        op: analysis_bench::Op,
    },
    HelpPrinted,
}

impl Command {
    fn from_args() -> Result<Command> {
        let mut matches = Arguments::from_env();
        let subcommand = matches.subcommand()?.unwrap_or_default();

        let command = match subcommand.as_str() {
            "parse" => {
                if matches.contains(["-h", "--help"]) {
                    eprintln!(
                        "\
ra-cli-parse

USAGE:
    ra_cli parse [FLAGS]

FLAGS:
    -h, --help       Prints help inforamtion
        --no-dump"
                    );
                    return Ok(Command::HelpPrinted);
                }

                let no_dump = matches.contains("--no-dump");
                matches.finish().or_else(handle_extra_flags)?;
                Command::Parse { no_dump }
            }
            "symbols" => {
                if matches.contains(["-h", "--help"]) {
                    eprintln!(
                        "\
ra-cli-symbols

USAGE:
    ra_cli highlight [FLAGS]

FLAGS:
    -h, --help    Prints help inforamtion"
                    );
                    return Ok(Command::HelpPrinted);
                }

                matches.finish().or_else(handle_extra_flags)?;

                Command::Symbols
            }
            "highlight" => {
                if matches.contains(["-h", "--help"]) {
                    eprintln!(
                        "\
ra-cli-highlight

USAGE:
    ra_cli highlight [FLAGS]

FLAGS:
    -h, --help       Prints help information
    -r, --rainbow"
                    );
                    return Ok(Command::HelpPrinted);
                }

                let rainbow = matches.contains(["-r", "--rainbow"]);
                matches.finish().or_else(handle_extra_flags)?;
                Command::Highlight { rainbow }
            }
            "analysis-stats" => {
                if matches.contains(["-h", "--help"]) {
                    eprintln!(
                        "\
ra-cli-analysis-stats

USAGE:
    ra_cli analysis-stats [FLAGS] [OPTIONS] [PATH]

FLAGS:
    -h, --help            Prints help information
        --memory-usage
    -v, --verbose
    -q, --quiet

OPTIONS:
    -o <ONLY>

ARGS:
    <PATH>"
                    );
                    return Ok(Command::HelpPrinted);
                }

                let verbosity = match (
                    matches.contains(["-vv", "--spammy"]),
                    matches.contains(["-v", "--verbose"]),
                    matches.contains(["-q", "--quiet"]),
                ) {
                    (true, _, true) => Err("Invalid flags: -q conflicts with -vv")?,
                    (true, _, false) => Verbosity::Spammy,
                    (false, false, false) => Verbosity::Normal,
                    (false, false, true) => Verbosity::Quiet,
                    (false, true, false) => Verbosity::Verbose,
                    (false, true, true) => Err("Invalid flags: -q conflicts with -v")?,
                };
                let randomize = matches.contains("--randomize");
                let memory_usage = matches.contains("--memory-usage");
                let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?;
                let with_deps: bool = matches.contains("--with-deps");
                let path = {
                    let mut trailing = matches.free()?;
                    if trailing.len() != 1 {
                        Err("Invalid flags")?;
                    }
                    trailing.pop().unwrap().into()
                };

                Command::Stats { verbosity, randomize, memory_usage, only, with_deps, path }
            }
            "analysis-bench" => {
                if matches.contains(["-h", "--help"]) {
                    eprintln!(
                        "\
ra_cli-analysis-bench

USAGE:
    ra_cli analysis-bench [FLAGS] [OPTIONS] [PATH]

FLAGS:
    -h, --help        Prints help information
    -v, --verbose

OPTIONS:
    --complete <PATH:LINE:COLUMN>    Compute completions at this location
    --highlight <PATH>               Hightlight this file

ARGS:
    <PATH>    Project to analyse"
                    );
                    return Ok(Command::HelpPrinted);
                }

                let verbose = matches.contains(["-v", "--verbose"]);
                let path: PathBuf = matches.opt_value_from_str("--path")?.unwrap_or_default();
                let highlight_path: Option<String> = matches.opt_value_from_str("--highlight")?;
                let complete_path: Option<String> = matches.opt_value_from_str("--complete")?;
                let goto_def_path: Option<String> = matches.opt_value_from_str("--goto-def")?;
                let op = match (highlight_path, complete_path, goto_def_path) {
                    (Some(path), None, None) => analysis_bench::Op::Highlight { path: path.into() },
                    (None, Some(position), None) => analysis_bench::Op::Complete(position.parse()?),
                    (None, None, Some(position)) => analysis_bench::Op::GotoDef(position.parse()?),
                    _ => panic!(
                        "exactly one of  `--highlight`, `--complete` or `--goto-def` must be set"
                    ),
                };
                Command::Bench { verbose, path, op }
            }
            _ => {
                eprintln!(
                    "\
ra-cli

USAGE:
    ra_cli <SUBCOMMAND>

FLAGS:
    -h, --help        Prints help information

SUBCOMMANDS:
    analysis-bench
    analysis-stats
    highlight
    parse
    symbols"
                );
                return Ok(Command::HelpPrinted);
            }
        };
        Ok(command)
    }
}

fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
    if let pico_args::Error::UnusedArgsLeft(flags) = e {
        let mut invalid_flags = String::new();
        for flag in flags {
            write!(&mut invalid_flags, "{}, ", flag)?;
        }
        let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2);
        Err(format!("Invalid flags: {}", invalid_flags).into())
    } else {
        Err(e.to_string().into())
    }
}

fn file() -> Result<SourceFile> {
    let text = read_stdin()?;
    Ok(SourceFile::parse(&text).tree())
}

fn read_stdin() -> Result<String> {
    let mut buff = String::new();
    std::io::stdin().read_to_string(&mut buff)?;
    Ok(buff)
}
<|endoftext|>


<commit_before>// Copyright © 2017-2018 Mozilla Foundation
//
// This program is made available under an ISC-style license.  See the
// accompanying file LICENSE for details.

use {ChannelLayout, DeviceCollection, DeviceId, DeviceType, Result, Stream, StreamParamsRef};
use ffi;
use std::{ptr, str};
use std::ffi::CStr;
use std::os::raw::c_void;
use util::opt_bytes;

macro_rules! as_ptr {
    ($e:expr) => { $e.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut()) }
}

ffi_type_heap! {
    type CType = ffi::cubeb;
    fn drop = ffi::cubeb_destroy;
    pub struct Context;
    pub struct ContextRef;
}

impl Context {
    pub fn init(context_name: Option<&CStr>, backend_name: Option<&CStr>) -> Result<Context> {
        let mut context: *mut ffi::cubeb = ptr::null_mut();
        let context_name = as_ptr!(context_name);
        let backend_name = as_ptr!(backend_name);
        unsafe {
            ffi::cubeb_init(&mut context, context_name, backend_name);
            Ok(Context::from_ptr(context))
        }
    }
}

impl ContextRef {
    pub fn backend_id(&self) -> &str {
        str::from_utf8(self.backend_id_bytes()).unwrap()
    }

    pub fn backend_id_bytes(&self) -> &[u8] {
        unsafe { opt_bytes(ffi::cubeb_get_backend_id(self.as_ptr())).unwrap() }
    }

    pub fn max_channel_count(&self) -> Result<u32> {
        let mut channel_count = 0u32;
        unsafe {
            let _ = try_call!(ffi::cubeb_get_max_channel_count(
                self.as_ptr(),
                &mut channel_count
            ));
        }
        Ok(channel_count)
    }

    pub fn min_latency(&self, params: &StreamParamsRef) -> Result<u32> {
        let mut latency = 0u32;
        unsafe {
            let _ = try_call!(ffi::cubeb_get_min_latency(
                self.as_ptr(),
                params.as_ptr(),
                &mut latency
            ));
        }
        Ok(latency)
    }

    pub fn preferred_sample_rate(&self) -> Result<u32> {
        let mut rate = 0u32;
        unsafe {
            let _ = try_call!(ffi::cubeb_get_preferred_sample_rate(
                self.as_ptr(),
                &mut rate
            ));
        }
        Ok(rate)
    }

    pub fn preferred_channel_layout(&self) -> Result<ChannelLayout> {
        let mut layout: ffi::cubeb_channel_layout = ffi::CUBEB_LAYOUT_UNDEFINED;
        unsafe {
            let _ = try_call!(ffi::cubeb_get_preferred_channel_layout(
                self.as_ptr(),
                &mut layout
            ));
        }
        Ok(ChannelLayout::from(layout))
    }

    #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
    pub unsafe fn stream_init(
        &self,
        stream_name: Option<&CStr>,
        input_device: DeviceId,
        input_stream_params: Option<&StreamParamsRef>,
        output_device: DeviceId,
        output_stream_params: Option<&StreamParamsRef>,
        latency_frames: u32,
        data_callback: ffi::cubeb_data_callback,
        state_callback: ffi::cubeb_state_callback,
        user_ptr: *mut c_void,
    ) -> Result<Stream> {
        let mut stm: *mut ffi::cubeb_stream = ptr::null_mut();

        let stream_name = as_ptr!(stream_name);
        let input_stream_params = as_ptr!(input_stream_params);
        let output_stream_params = as_ptr!(output_stream_params);

        let _ = try_call!(ffi::cubeb_stream_init(
            self.as_ptr(),
            &mut stm,
            stream_name,
            input_device,
            input_stream_params,
            output_device,
            output_stream_params,
            latency_frames,
            data_callback,
            state_callback,
            user_ptr
        ));
        Ok(Stream::from_ptr(stm))
    }

    pub fn enumerate_devices(&self, devtype: DeviceType) -> Result<DeviceCollection> {
        let mut coll = ffi::cubeb_device_collection::default();
        unsafe {
            let _ = try_call!(ffi::cubeb_enumerate_devices(
                self.as_ptr(),
                devtype.bits(),
                &mut coll
            ));
        }
        Ok(DeviceCollection::init_with_ctx(self, coll))
    }

    pub unsafe fn register_device_collection_changed(
        &self,
        devtype: DeviceType,
        callback: ffi::cubeb_device_collection_changed_callback,
        user_ptr: *mut c_void,
    ) -> Result<()> {
        let _ = try_call!(ffi::cubeb_register_device_collection_changed(
            self.as_ptr(),
            devtype.bits(),
            callback,
            user_ptr
        ));

        Ok(())
    }
}
<commit_msg>cubeb-core: Handle cubeb_init failure.<commit_after>// Copyright © 2017-2018 Mozilla Foundation
//
// This program is made available under an ISC-style license.  See the
// accompanying file LICENSE for details.

use {ChannelLayout, DeviceCollection, DeviceId, DeviceType, Result, Stream, StreamParamsRef};
use ffi;
use std::{ptr, str};
use std::ffi::CStr;
use std::os::raw::c_void;
use util::opt_bytes;

macro_rules! as_ptr {
    ($e:expr) => { $e.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut()) }
}

ffi_type_heap! {
    type CType = ffi::cubeb;
    fn drop = ffi::cubeb_destroy;
    pub struct Context;
    pub struct ContextRef;
}

impl Context {
    pub fn init(context_name: Option<&CStr>, backend_name: Option<&CStr>) -> Result<Context> {
        let mut context: *mut ffi::cubeb = ptr::null_mut();
        let context_name = as_ptr!(context_name);
        let backend_name = as_ptr!(backend_name);
        unsafe {
            try_call!(ffi::cubeb_init(&mut context, context_name, backend_name));
            Ok(Context::from_ptr(context))
        }
    }
}

impl ContextRef {
    pub fn backend_id(&self) -> &str {
        str::from_utf8(self.backend_id_bytes()).unwrap()
    }

    pub fn backend_id_bytes(&self) -> &[u8] {
        unsafe { opt_bytes(ffi::cubeb_get_backend_id(self.as_ptr())).unwrap() }
    }

    pub fn max_channel_count(&self) -> Result<u32> {
        let mut channel_count = 0u32;
        unsafe {
            let _ = try_call!(ffi::cubeb_get_max_channel_count(
                self.as_ptr(),
                &mut channel_count
            ));
        }
        Ok(channel_count)
    }

    pub fn min_latency(&self, params: &StreamParamsRef) -> Result<u32> {
        let mut latency = 0u32;
        unsafe {
            let _ = try_call!(ffi::cubeb_get_min_latency(
                self.as_ptr(),
                params.as_ptr(),
                &mut latency
            ));
        }
        Ok(latency)
    }

    pub fn preferred_sample_rate(&self) -> Result<u32> {
        let mut rate = 0u32;
        unsafe {
            let _ = try_call!(ffi::cubeb_get_preferred_sample_rate(
                self.as_ptr(),
                &mut rate
            ));
        }
        Ok(rate)
    }

    pub fn preferred_channel_layout(&self) -> Result<ChannelLayout> {
        let mut layout: ffi::cubeb_channel_layout = ffi::CUBEB_LAYOUT_UNDEFINED;
        unsafe {
            let _ = try_call!(ffi::cubeb_get_preferred_channel_layout(
                self.as_ptr(),
                &mut layout
            ));
        }
        Ok(ChannelLayout::from(layout))
    }

    #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
    pub unsafe fn stream_init(
        &self,
        stream_name: Option<&CStr>,
        input_device: DeviceId,
        input_stream_params: Option<&StreamParamsRef>,
        output_device: DeviceId,
        output_stream_params: Option<&StreamParamsRef>,
        latency_frames: u32,
        data_callback: ffi::cubeb_data_callback,
        state_callback: ffi::cubeb_state_callback,
        user_ptr: *mut c_void,
    ) -> Result<Stream> {
        let mut stm: *mut ffi::cubeb_stream = ptr::null_mut();

        let stream_name = as_ptr!(stream_name);
        let input_stream_params = as_ptr!(input_stream_params);
        let output_stream_params = as_ptr!(output_stream_params);

        let _ = try_call!(ffi::cubeb_stream_init(
            self.as_ptr(),
            &mut stm,
            stream_name,
            input_device,
            input_stream_params,
            output_device,
            output_stream_params,
            latency_frames,
            data_callback,
            state_callback,
            user_ptr
        ));
        Ok(Stream::from_ptr(stm))
    }

    pub fn enumerate_devices(&self, devtype: DeviceType) -> Result<DeviceCollection> {
        let mut coll = ffi::cubeb_device_collection::default();
        unsafe {
            let _ = try_call!(ffi::cubeb_enumerate_devices(
                self.as_ptr(),
                devtype.bits(),
                &mut coll
            ));
        }
        Ok(DeviceCollection::init_with_ctx(self, coll))
    }

    pub unsafe fn register_device_collection_changed(
        &self,
        devtype: DeviceType,
        callback: ffi::cubeb_device_collection_changed_callback,
        user_ptr: *mut c_void,
    ) -> Result<()> {
        let _ = try_call!(ffi::cubeb_register_device_collection_changed(
            self.as_ptr(),
            devtype.bits(),
            callback,
            user_ptr
        ));

        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Tests individual commands via `reply`

use std::collections::HashSet;

use rustc_serialize::json::{Json, ToJson};

use super::*;
use super::super::channel;

use registry;
use registry::tests as regtests;

const PING: &'static str =     r#"{ "type":"ping" }"#;
const COMMANDS: &'static str = r#"{ "type":"commands" }"#;
const VERSION: &'static str =  r#"{ "type":"version" }"#;

const RUN_COMMAND: &'static str =     r#"{"type":"run", "key":"command" }"#;
const RUN_PANIC_COMMAND: &'static str=r#"{"type":"run","key":"panic_command"}"#;
const RUN_BAD_KEY: &'static str =     r#"{"type":"run", "key":"non_command" }"#;
const RUN_NO_KEY: &'static str =      r#"{"type":"run" }"#;

const GET_OBJECT: &'static str =     r#"{ "type":"get", "key":"point" }"#;
const GET_PROP: &'static str =       r#"{ "type":"get", "key":"get_prop" }"#;
const GET_READONLY: &'static str =   r#"{ "type":"get", "key":"readonly" }"#;
const GET_WRITEONLY: &'static str =  r#"{ "type":"get", "key":"writeonly" }"#;
const GET_PROP_WRITE: &'static str = r#"{ "type":"get", "key":"set_prop" }"#;
const GET_NO_KEY: &'static str =     r#"{ "type":"get" }"#;
const GET_BAD_KEY: &'static str =   r#"{ "type":"get", "key":"novalue" }"#;

const SET_OBJECT: &'static str
    = r#"{ "type":"set", "key":"ipc_test_bool", "value":false }"#;
const SET_PROP: &'static str
    = r#"{ "type":"set", "key":"prop", "value":null }"#;
const SET_READONLY: &'static str
    = r#"{ "type":"set", "key":"readonly", "value":12 }"#;
const SET_WRITEONLY: &'static str
    = r#"{ "type":"set", "key":"ipc_test_writeonly", "value":11 }"#;
const SET_PROP_READ: &'static str
    = r#"{ "type":"set", "key":"prop_read", "value":"asdf" }"#;
const SET_NEW_KEY: &'static str
    = r#"{ "type":"set", "key":"new_key", "value":"value" }"#;
const SET_NO_PERMS: &'static str
    = r#"{ "type":"set", "key":"noperms", "value":"something" }"#;
const SET_NO_KEY: &'static str
    = r#"{ "type":"set", "value":12 }"#;
const SET_NO_VALUE: &'static str
    = r#"{ "type":"set", "key":"foo" }"#;
const SET_BAD_KEY_TYPE: &'static str
    = r#"{ "type":"set", "key":12 }"#;

const EXISTS_OBJECT_RW: &'static str =  r#"{"type":"exists","key":"null" }"#;
const EXISTS_PROP: &'static str =       r#"{"type":"exists","key":"prop" }"#;
const EXISTS_PROP_READ: &'static str =  r#"{"type":"exists","key":"get_prop"}"#;
const EXISTS_PROP_WRITE: &'static str = r#"{"type":"exists","key":"set_prop"}"#;
const EXISTS_OBJECT_READ:&'static str = r#"{"type":"exists","key":"readonly"}"#;
const EXISTS_OBJECT_WRITE:&'static str= r#"{"type":"exists","key":"writeonly"}"#;
const EXISTS_BAD_KEY: &'static str =    r#"{"type":"exists","key": "nope"}"#;

const BAD_NO_REQUEST: &'static str = r#"{ "key":"foo", "value":"bar" }"#;
const BAD_INVALID_REQUEST: &'static str = r#"{ "type":"foo" }"#;
const BAD_SET_NO_KEY: &'static str = r#"{ "type":"set", "value":12 }"#;
const BAD_SET_NO_VALUE: &'static str = r#"{ "type":"set", "key":"f64" }"#;
const BAD_RUN_NO_COMMAND: &'static str = r#"{ "type":"run" }"#;
const BAD_RUN_EXTRA_FIELDS: &'static str =
    r#"{ "type":"run", "key":"command", "foo":"bar" }"#;
const BAD_RUN_U64_COMMAND: &'static str = r#"{ "type":"run", "key":12 }"#;
const BAD_GET_OBJECT_KEY: &'static str = r#"{ "type":"get", "key": 12 }"#;
const BAD_REQUEST_IS_A_NUMBER: &'static str = r#"23"#;

macro_rules! reply {
    ($json:expr) => {
        super::super::command::reply(Json::from_str($json)
                                           .expect("Couldn't parse json"))
            .unwrap_or_else(|j| j)
    }
}

#[test]
fn ping() {
    let reply = reply!(PING);
    assert_eq!(reply, channel::success_json());
}

#[test]
fn commands() {
    let mut reply = reply!(COMMANDS);

    let mut obj = reply.as_object_mut()
        .expect("commands: reply not object");
    let mut value = obj.remove("value")
        .expect("commands: reply: no 'value'");
    let val_arr = value.as_array_mut()
        .expect("commands: reply: 'value' not array");
    let mut set = HashSet::new();
    for val in val_arr {
        set.insert(val.as_string()
                   .expect("commands: reply: 'value' not string array"));
    }
    assert_eq!(set.len(), 7);
    let desired = &["get", "set", "exists", "run", "version", "commands", "ping"];
    for com in desired.iter() {
        assert!(set.contains(com), "Missing command {}", com);
    }
}

#[test]
fn version() {
    let mut reply = reply!(VERSION);
    let version = reply.as_object_mut().expect("version: reply not object")
        .remove("value").expect("version: reply: no 'value'")
        .as_u64().expect("version: reply not u64");

    assert_eq!(version, super::super::VERSION);
}

#[test]
fn run_command() {
    let reply = reply!(RUN_COMMAND);
    assert_eq!(reply, channel::success_json());
}

// Note: If a command were to panic in way-cooler, the thread servicing that
// IPC connection would shut down. However, reply! is routing around that and
// everything is being run in each test thread. This is more of a general way
// of making sure commands are being run and we are aware of them.

#[test]
#[should_panic(reason = "panic_command panic")]
fn run_panic_command() {
    let reply = reply!(RUN_PANIC_COMMAND);
}

#[test]
fn command_bad_args() {
    assert_eq!(reply!(RUN_BAD_KEY), Json::Object(json_object!{
        "type" => "error",
        "reason" => "command not found"
    }));
    assert_eq!(reply!(RUN_NO_KEY), Json::Object(json_object!{
        "type" => "error",
        "reason" => "missing message field",
        "missing" => "key",
        "expected" => "String"
    }));
}

#[test]
fn get_stuff() {
    assert_eq!(reply!(GET_OBJECT),
               channel::value_json(registry::tests::POINT.to_json()));
    assert_eq!(reply!(GET_PROP),
               channel::value_json(json!(registry::tests::PROP_GET_RESULT)));
    assert_eq!(reply!(GET_READONLY),
               channel::value_json(json!(registry::tests::READONLY)));
    assert_eq!(reply!(GET_WRITEONLY),
               channel::value_json(json!(registry::tests::WRITEONLY)));
    assert_eq!(reply!(GET_PROP_WRITE),
               channel::error_json("cannot get that key".to_string()));
    assert_eq!(reply!(GET_NO_KEY),
               channel::error_expecting_key("key", "String"));
    assert_eq!(reply!(GET_BAD_KEY),
               channel::error_json("key not found".to_string()));
}

#[test]
fn set_stuff() {
    use registry::AccessFlags;
    let error_set = channel::error_json("cannot set that key".to_string());
    registry::insert_json("ipc_test_bool".to_string(),
                          AccessFlags::all(),
                          true.to_json());
    registry::insert_json("ipc_test_writeonly".to_string(),
                          AccessFlags::WRITE(),
                          false.to_json());
    assert_eq!(reply!(SET_OBJECT), channel::success_json());
    assert_eq!(reply!(SET_PROP), channel::success_json());
    assert_eq!(reply!(SET_READONLY), error_set);
    assert_eq!(reply!(SET_WRITEONLY), channel::success_json());
    assert_eq!(reply!(SET_PROP_READ), error_set);
    assert_eq!(reply!(SET_NO_PERMS), error_set);
    assert_eq!(reply!(SET_NEW_KEY),
               channel::error_json("key not found".to_string()));
    assert_eq!(reply!(SET_NO_KEY),
               channel::error_expecting_key("key", "String"));
    assert_eq!(reply!(SET_BAD_KEY_TYPE),
               channel::error_expecting_key("key", "String"));
    assert_eq!(reply!(SET_NO_VALUE),
               channel::error_expecting_key("Value", "any"));
}
<commit_msg>Command individual tests<commit_after>//! Tests individual commands via `reply`

use std::collections::{HashSet, BTreeMap};

use rustc_serialize::json::{Json, ToJson};

use super::*;
use super::super::channel;

use registry;

const PING: &'static str =     r#"{ "type":"ping" }"#;
const COMMANDS: &'static str = r#"{ "type":"commands" }"#;
const VERSION: &'static str =  r#"{ "type":"version" }"#;

const RUN_COMMAND: &'static str =     r#"{"type":"run", "key":"command" }"#;
const RUN_PANIC_COMMAND: &'static str=r#"{"type":"run","key":"panic_command"}"#;
const RUN_BAD_KEY: &'static str =     r#"{"type":"run", "key":"non_command" }"#;
const RUN_NO_KEY: &'static str =      r#"{"type":"run" }"#;

const GET_OBJECT: &'static str =     r#"{ "type":"get", "key":"point" }"#;
const GET_PROP: &'static str =       r#"{ "type":"get", "key":"get_prop" }"#;
const GET_READONLY: &'static str =   r#"{ "type":"get", "key":"readonly" }"#;
const GET_WRITEONLY: &'static str =  r#"{ "type":"get", "key":"writeonly" }"#;
const GET_PROP_WRITE: &'static str = r#"{ "type":"get", "key":"set_prop" }"#;
const GET_NO_KEY: &'static str =     r#"{ "type":"get" }"#;
const GET_BAD_KEY: &'static str =   r#"{ "type":"get", "key":"novalue" }"#;

const SET_OBJECT: &'static str
    = r#"{ "type":"set", "key":"ipc_test_bool", "value":false }"#;
const SET_PROP: &'static str
    = r#"{ "type":"set", "key":"prop", "value":null }"#;
const SET_READONLY: &'static str
    = r#"{ "type":"set", "key":"readonly", "value":12 }"#;
const SET_WRITEONLY: &'static str
    = r#"{ "type":"set", "key":"ipc_test_writeonly", "value":11 }"#;
const SET_PROP_READ: &'static str
    = r#"{ "type":"set", "key":"get_prop", "value":"asdf" }"#;
const SET_NEW_KEY: &'static str
    = r#"{ "type":"set", "key":"new_key", "value":"value" }"#;
const SET_NO_PERMS: &'static str
    = r#"{ "type":"set", "key":"noperms", "value":"something" }"#;
const SET_NO_KEY: &'static str
    = r#"{ "type":"set", "value":12 }"#;
const SET_NO_VALUE: &'static str
    = r#"{ "type":"set", "key":"foo" }"#;
const SET_BAD_KEY_TYPE: &'static str
    = r#"{ "type":"set", "key":12 }"#;

const EXISTS_OBJECT_RW: &'static str =  r#"{"type":"exists","key":"null" }"#;
const EXISTS_PROP: &'static str =       r#"{"type":"exists","key":"prop" }"#;
const EXISTS_PROP_READ: &'static str =  r#"{"type":"exists","key":"get_prop"}"#;
const EXISTS_PROP_WRITE: &'static str = r#"{"type":"exists","key":"set_prop"}"#;
const EXISTS_OBJECT_READ:&'static str = r#"{"type":"exists","key":"readonly"}"#;
const EXISTS_OBJECT_WRITE:&'static str= r#"{"type":"exists","key":"writeonly"}"#;
const EXISTS_BAD_KEY: &'static str =    r#"{"type":"exists","key": "nope"}"#;
const EXISTS_NO_KEY: &'static str =     r#"{"type":"exists"}"#;

const BAD_NO_REQUEST: &'static str = r#"{ "key":"foo", "value":"bar" }"#;
const BAD_INVALID_REQUEST: &'static str = r#"{ "type":"foo" }"#;
const BAD_REQUEST_IS_A_NUMBER: &'static str = r#"23"#;

macro_rules! reply {
    ($json:expr) => {
        super::super::command::reply(Json::from_str($json)
                                           .expect("Couldn't parse json"))
            .unwrap_or_else(|j| j)
    }
}

#[test]
fn ping() {
    let reply = reply!(PING);
    assert_eq!(reply, channel::success_json());
}

#[test]
fn commands() {
    let mut reply = reply!(COMMANDS);

    let mut obj = reply.as_object_mut()
        .expect("commands: reply not object");
    let mut value = obj.remove("value")
        .expect("commands: reply: no 'value'");
    let val_arr = value.as_array_mut()
        .expect("commands: reply: 'value' not array");
    let mut set = HashSet::new();
    for val in val_arr {
        set.insert(val.as_string()
                   .expect("commands: reply: 'value' not string array"));
    }
    assert_eq!(set.len(), 7);
    let desired = &["get", "set", "exists", "run", "version", "commands", "ping"];
    for com in desired.iter() {
        assert!(set.contains(com), "Missing command {}", com);
    }
}

#[test]
fn version() {
    let mut reply = reply!(VERSION);
    let version = reply.as_object_mut().expect("version: reply not object")
        .remove("value").expect("version: reply: no 'value'")
        .as_u64().expect("version: reply not u64");

    assert_eq!(version, super::super::VERSION);
}

#[test]
fn run_command() {
    let reply = reply!(RUN_COMMAND);
    assert_eq!(reply, channel::success_json());
}

// Note: If a command were to panic in way-cooler, the thread servicing that
// IPC connection would shut down. However, reply! is routing around that and
// everything is being run in each test thread. This is more of a general way
// of making sure commands are being run and we are aware of them.

#[test]
#[should_panic(reason = "panic_command panic")]
fn run_panic_command() {
    let _reply = reply!(RUN_PANIC_COMMAND);
}

#[test]
fn command_bad_args() {
    assert_eq!(reply!(RUN_BAD_KEY), Json::Object(json_object!{
        "type" => "error",
        "reason" => "command not found"
    }));
    assert_eq!(reply!(RUN_NO_KEY), Json::Object(json_object!{
        "type" => "error",
        "reason" => "missing message field",
        "missing" => "key",
        "expected" => "String"
    }));
}

#[test]
fn get_stuff() {
    assert_eq!(reply!(GET_OBJECT),
               channel::value_json(registry::tests::POINT.to_json()));
    assert_eq!(reply!(GET_PROP),
               channel::value_json(json!(registry::tests::PROP_GET_RESULT)));
    assert_eq!(reply!(GET_READONLY),
               channel::value_json(json!(registry::tests::READONLY)));
    assert_eq!(reply!(GET_WRITEONLY),
               channel::value_json(json!(registry::tests::WRITEONLY)));
    assert_eq!(reply!(GET_PROP_WRITE),
               channel::error_json("cannot get that key".to_string()));
    assert_eq!(reply!(GET_NO_KEY),
               channel::error_expecting_key("key", "String"));
    assert_eq!(reply!(GET_BAD_KEY),
               channel::error_json("key not found".to_string()));
}

#[test]
fn set_stuff() {
    use registry::AccessFlags;
    let error_set = channel::error_json("cannot set that key".to_string());
    registry::insert_json("ipc_test_bool".to_string(),
                          AccessFlags::all(),
                          true.to_json());
    registry::insert_json("ipc_test_writeonly".to_string(),
                          AccessFlags::WRITE(),
                          false.to_json());
    assert_eq!(reply!(SET_OBJECT), channel::success_json());
    assert_eq!(reply!(SET_PROP), channel::success_json());
    assert_eq!(reply!(SET_READONLY), error_set);
    assert_eq!(reply!(SET_WRITEONLY), channel::success_json());
    assert_eq!(reply!(SET_PROP_READ), error_set);
    assert_eq!(reply!(SET_NO_PERMS), error_set);
    assert_eq!(reply!(SET_NEW_KEY),
               channel::error_json("key not found, use insert".to_string()));
    assert_eq!(reply!(SET_NO_KEY),
               channel::error_expecting_key("key", "String"));
    assert_eq!(reply!(SET_BAD_KEY_TYPE),
               channel::error_expecting_key("key", "String"));
    assert_eq!(reply!(SET_NO_VALUE),
               channel::error_expecting_key("value", "any"));
}

#[test]
fn exists() {
    fn exists_json(mut others: BTreeMap<String, Json>) -> Json {
        others.insert("exists".to_string(), Json::Boolean(true));
        channel::success_json_with(others)
    }

    assert_eq!(reply!(EXISTS_OBJECT_RW),
               exists_json(json_object!{
                   "flags" => (json!([ "read".to_json(), "write".to_json()])),
                   "type" => ("Object".to_json())
               }));
    assert_eq!(reply!(EXISTS_PROP),
               exists_json(json_object!{
                   "flags" => (json!([ "read".to_json(), "write".to_json()])),
                   "type" => ("Property".to_json())
               }));
    assert_eq!(reply!(EXISTS_PROP_READ),
               exists_json(json_object!{
                   "flags" => (json!([ "read".to_json() ])),
                   "type" => ("Property".to_json())
               }));
    assert_eq!(reply!(EXISTS_PROP_WRITE),
               exists_json(json_object!{
                   "flags" => (json!([ "write".to_json() ])),
                   "type" => ("Property".to_json())
               }));
    assert_eq!(reply!(EXISTS_OBJECT_READ),
               exists_json(json_object!{
                   "flags" => (json!([ "read".to_json() ])),
                   "type" => ("Object".to_json())
               }));
    assert_eq!(reply!(EXISTS_OBJECT_WRITE),
               exists_json(json_object!{
                   "flags" => (json!([ "write".to_json()])),
                   "type" => ("Object".to_json())
               }));
    assert_eq!(reply!(EXISTS_BAD_KEY),
               channel::success_json_with(json_object!{
                   "exists" => false
               }));
    assert_eq!(reply!(EXISTS_NO_KEY),
               channel::error_expecting_key("key", "String"));
}

#[test]
fn bad_requests() {
    assert_eq!(reply!(BAD_NO_REQUEST),
               channel::error_expecting_key("type", "String"));
    assert_eq!(reply!(BAD_INVALID_REQUEST),
               channel::error_json("invalid request; see 'commands'".to_string()));
    assert_eq!(reply!(BAD_REQUEST_IS_A_NUMBER),
               channel::error_json("invalid format - object required".to_string()));
}
<|endoftext|>


<commit_before>use rustc_errors::struct_span_err;
use rustc_middle::mir;

use super::FunctionCx;
use super::LocalRef;
use super::OperandValue;
use crate::traits::BuilderMethods;
use crate::traits::*;

impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
    pub fn codegen_statement(&mut self, mut bx: Bx, statement: &mir::Statement<'tcx>) -> Bx {
        debug!("codegen_statement(statement={:?})", statement);

        self.set_debug_loc(&mut bx, statement.source_info);
        match statement.kind {
            mir::StatementKind::Assign(box (ref place, ref rvalue)) => {
                if let Some(index) = place.as_local() {
                    match self.locals[index] {
                        LocalRef::Place(cg_dest) => self.codegen_rvalue(bx, cg_dest, rvalue),
                        LocalRef::UnsizedPlace(cg_indirect_dest) => {
                            self.codegen_rvalue_unsized(bx, cg_indirect_dest, rvalue)
                        }
                        LocalRef::Operand(None) => {
                            let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue);
                            self.locals[index] = LocalRef::Operand(Some(operand));
                            self.debug_introduce_local(&mut bx, index);
                            bx
                        }
                        LocalRef::Operand(Some(op)) => {
                            if !op.layout.is_zst() {
                                span_bug!(
                                    statement.source_info.span,
                                    "operand {:?} already assigned",
                                    rvalue
                                );
                            }

                            // If the type is zero-sized, it's already been set here,
                            // but we still need to make sure we codegen the operand
                            self.codegen_rvalue_operand(bx, rvalue).0
                        }
                    }
                } else {
                    let cg_dest = self.codegen_place(&mut bx, place.as_ref());
                    self.codegen_rvalue(bx, cg_dest, rvalue)
                }
            }
            mir::StatementKind::SetDiscriminant { box ref place, variant_index } => {
                self.codegen_place(&mut bx, place.as_ref())
                    .codegen_set_discr(&mut bx, variant_index);
                bx
            }
            mir::StatementKind::StorageLive(local) => {
                if let LocalRef::Place(cg_place) = self.locals[local] {
                    cg_place.storage_live(&mut bx);
                } else if let LocalRef::UnsizedPlace(cg_indirect_place) = self.locals[local] {
                    cg_indirect_place.storage_live(&mut bx);
                }
                bx
            }
            mir::StatementKind::StorageDead(local) => {
                if let LocalRef::Place(cg_place) = self.locals[local] {
                    cg_place.storage_dead(&mut bx);
                } else if let LocalRef::UnsizedPlace(cg_indirect_place) = self.locals[local] {
                    cg_indirect_place.storage_dead(&mut bx);
                }
                bx
            }
            mir::StatementKind::LlvmInlineAsm(ref asm) => {
                let outputs = asm
                    .outputs
                    .iter()
                    .map(|output| self.codegen_place(&mut bx, output.as_ref()))
                    .collect();

                let input_vals = asm.inputs.iter().fold(
                    Vec::with_capacity(asm.inputs.len()),
                    |mut acc, (span, input)| {
                        let op = self.codegen_operand(&mut bx, input);
                        if let OperandValue::Immediate(_) = op.val {
                            acc.push(op.immediate());
                        } else {
                            struct_span_err!(
                                bx.sess(),
                                span.to_owned(),
                                E0669,
                                "invalid value for constraint in inline assembly"
                            )
                            .emit();
                        }
                        acc
                    },
                );

                if input_vals.len() == asm.inputs.len() {
                    let res = bx.codegen_llvm_inline_asm(
                        &asm.asm,
                        outputs,
                        input_vals,
                        statement.source_info.span,
                    );
                    if !res {
                        struct_span_err!(
                            bx.sess(),
                            statement.source_info.span,
                            E0668,
                            "malformed inline assembly"
                        )
                        .emit();
                    }
                }
                bx
            }
            mir::StatementKind::Coverage(box ref coverage) => {
                self.codegen_coverage(&mut bx, coverage.clone(), statement.source_info.scope);
                bx
            }
            mir::StatementKind::CopyNonOverlapping(box mir::CopyNonOverlapping {
                ref src,
                ref dst,
                ref count,
            }) => {
                let dst_val = self.codegen_operand(&mut bx, dst);
                let src_val = self.codegen_operand(&mut bx, src);
                let count = self.codegen_operand(&mut bx, count).immediate();
                let pointee_layout = dst_val
                    .layout
                    .pointee_info_at(&mut bx, rustc_target::abi::Size::ZERO)
                    .expect("Expected pointer");
                let bytes = bx.mul(count, bx.const_usize(pointee_layout.size.bytes()));

                let align = pointee_layout.align;
                let dst = dst_val.immediate();
                let src = src_val.immediate();
                bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty());
                bx
            }
            mir::StatementKind::FakeRead(..)
            | mir::StatementKind::Retag { .. }
            | mir::StatementKind::AscribeUserType(..)
            | mir::StatementKind::Nop => bx,
        }
    }
}
<commit_msg>pointee_info_at() does not need mutable access<commit_after>use rustc_errors::struct_span_err;
use rustc_middle::mir;

use super::FunctionCx;
use super::LocalRef;
use super::OperandValue;
use crate::traits::BuilderMethods;
use crate::traits::*;

impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
    pub fn codegen_statement(&mut self, mut bx: Bx, statement: &mir::Statement<'tcx>) -> Bx {
        debug!("codegen_statement(statement={:?})", statement);

        self.set_debug_loc(&mut bx, statement.source_info);
        match statement.kind {
            mir::StatementKind::Assign(box (ref place, ref rvalue)) => {
                if let Some(index) = place.as_local() {
                    match self.locals[index] {
                        LocalRef::Place(cg_dest) => self.codegen_rvalue(bx, cg_dest, rvalue),
                        LocalRef::UnsizedPlace(cg_indirect_dest) => {
                            self.codegen_rvalue_unsized(bx, cg_indirect_dest, rvalue)
                        }
                        LocalRef::Operand(None) => {
                            let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue);
                            self.locals[index] = LocalRef::Operand(Some(operand));
                            self.debug_introduce_local(&mut bx, index);
                            bx
                        }
                        LocalRef::Operand(Some(op)) => {
                            if !op.layout.is_zst() {
                                span_bug!(
                                    statement.source_info.span,
                                    "operand {:?} already assigned",
                                    rvalue
                                );
                            }

                            // If the type is zero-sized, it's already been set here,
                            // but we still need to make sure we codegen the operand
                            self.codegen_rvalue_operand(bx, rvalue).0
                        }
                    }
                } else {
                    let cg_dest = self.codegen_place(&mut bx, place.as_ref());
                    self.codegen_rvalue(bx, cg_dest, rvalue)
                }
            }
            mir::StatementKind::SetDiscriminant { box ref place, variant_index } => {
                self.codegen_place(&mut bx, place.as_ref())
                    .codegen_set_discr(&mut bx, variant_index);
                bx
            }
            mir::StatementKind::StorageLive(local) => {
                if let LocalRef::Place(cg_place) = self.locals[local] {
                    cg_place.storage_live(&mut bx);
                } else if let LocalRef::UnsizedPlace(cg_indirect_place) = self.locals[local] {
                    cg_indirect_place.storage_live(&mut bx);
                }
                bx
            }
            mir::StatementKind::StorageDead(local) => {
                if let LocalRef::Place(cg_place) = self.locals[local] {
                    cg_place.storage_dead(&mut bx);
                } else if let LocalRef::UnsizedPlace(cg_indirect_place) = self.locals[local] {
                    cg_indirect_place.storage_dead(&mut bx);
                }
                bx
            }
            mir::StatementKind::LlvmInlineAsm(ref asm) => {
                let outputs = asm
                    .outputs
                    .iter()
                    .map(|output| self.codegen_place(&mut bx, output.as_ref()))
                    .collect();

                let input_vals = asm.inputs.iter().fold(
                    Vec::with_capacity(asm.inputs.len()),
                    |mut acc, (span, input)| {
                        let op = self.codegen_operand(&mut bx, input);
                        if let OperandValue::Immediate(_) = op.val {
                            acc.push(op.immediate());
                        } else {
                            struct_span_err!(
                                bx.sess(),
                                span.to_owned(),
                                E0669,
                                "invalid value for constraint in inline assembly"
                            )
                            .emit();
                        }
                        acc
                    },
                );

                if input_vals.len() == asm.inputs.len() {
                    let res = bx.codegen_llvm_inline_asm(
                        &asm.asm,
                        outputs,
                        input_vals,
                        statement.source_info.span,
                    );
                    if !res {
                        struct_span_err!(
                            bx.sess(),
                            statement.source_info.span,
                            E0668,
                            "malformed inline assembly"
                        )
                        .emit();
                    }
                }
                bx
            }
            mir::StatementKind::Coverage(box ref coverage) => {
                self.codegen_coverage(&mut bx, coverage.clone(), statement.source_info.scope);
                bx
            }
            mir::StatementKind::CopyNonOverlapping(box mir::CopyNonOverlapping {
                ref src,
                ref dst,
                ref count,
            }) => {
                let dst_val = self.codegen_operand(&mut bx, dst);
                let src_val = self.codegen_operand(&mut bx, src);
                let count = self.codegen_operand(&mut bx, count).immediate();
                let pointee_layout = dst_val
                    .layout
                    .pointee_info_at(&bx, rustc_target::abi::Size::ZERO)
                    .expect("Expected pointer");
                let bytes = bx.mul(count, bx.const_usize(pointee_layout.size.bytes()));

                let align = pointee_layout.align;
                let dst = dst_val.immediate();
                let src = src_val.immediate();
                bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty());
                bx
            }
            mir::StatementKind::FakeRead(..)
            | mir::StatementKind::Retag { .. }
            | mir::StatementKind::AscribeUserType(..)
            | mir::StatementKind::Nop => bx,
        }
    }
}
<|endoftext|>


<commit_before>extern crate chrono;

use self::chrono::{DateTime, Duration, Local};
use self::chrono::offset::TimeZone;

use constant::STORAGE_DIR_NAME;
use lib::fs::*;
use lib::io::*;
use std::fs::{self, OpenOptions};
use std::io::{Error as IoError, ErrorKind as IoErrorKind, Write};
use std::path::{Path, PathBuf};

pub struct Storage {
    now     : DateTime<Local>,
    date    : String,
    log_file: Option<String>,
}

impl Storage {
    fn path() -> PathBuf {
        path_buf![super::working_dir(), STORAGE_DIR_NAME]
    }

    pub fn exist() -> bool {
        Self::path().is_dir()
    }

    pub fn create() -> Result<(), IoError> {
        print_with_tag(Tag::Info, format!("Create \"{}\" directory", STORAGE_DIR_NAME));

        super::create_essential_dir(Self::path())
    }

    pub fn new() -> Self {
        let now  = Local::now();
        let date = now.format("%Y-%m-%d").to_string();
        Storage { now: now, date: date, log_file: None }
    }

    fn path_to_box(&self) -> PathBuf {
        path_buf![Storage::path(), &self.date]
    }

    fn path_to_dust_box(&self) -> PathBuf {
        path_buf![self.path_to_box(), "dusts"]
    }

    fn create_box(&self) -> Result<(), IoError> {
        print_with_tag(Tag::Info, format!(r#"Create "{}" directory in "{}""#, self.date, Self::path().display()));

        fs::create_dir_all(self.path_to_dust_box())
    }

    fn path_to_log(&self) -> PathBuf {
        let file_name = match &self.log_file {
            &Some(ref s) => s,
            &None        => unreachable!("Wrong to use path_to_log()"),
        };
        path_buf![self.path_to_box(), &file_name]
    }

    fn write_log<S: AsRef<str>>(&self, content: S) -> Result<usize, IoError> {
        let file = OpenOptions::new()
            .create(true)
            .append(true)
            .open(self.path_to_log());
        let mut file = try!(file);

        file.write(format!("{}\n", content.as_ref()).as_bytes())
    }

    fn start_mark_for_log(&self) -> String {
        let datetime = self.now.format("%H:%M:%S").to_string();
        format!(
            "############
# {} #
############",
            datetime,
        )
    }

    fn create_log_file(mut self, file_name: &str) -> Result<Self, IoError> {
        let file_name = format!("{}.log", file_name);

        print_with_tag(Tag::Info, format!(r#"Create "{}" file in "{}""#, file_name, self.path_to_box().display()));

        self.log_file = Some(file_name);

        try!(self.write_log(self.start_mark_for_log()));

        Ok(self)
    }

    pub fn create_box_with_log(self, file_name: &str) -> Result<Self, IoError> {
        try!(self.create_box());
        self.create_log_file(file_name)
    }

    pub fn squeeze_dusts<P: AsRef<Path>>(&self, paths_to_dust: Vec<P>) -> Result<(), IoError> {
        let path_to_dust_box = self.path_to_dust_box();

        self.print_and_log(format!("Move dusts to \"{}\"", path_to_dust_box.display()));

        for path_to_dust in &paths_to_dust {
            let path_to_dust = path_to_dust.as_ref();
            let target_file  = match path_to_dust.file_name() {
                Some(f) => f,
                None    => unreachable!("Cannot get file name from path!!"),
            };
            let target_base = match path_to_dust.parent() {
                Some(b) => b,
                None    => unreachable!("Cannot get base name from path!!"),
            };

            let to = path_buf![&path_to_dust_box, target_base];

            self.print_and_log(format!("  => \"{}\"", path_to_dust.display()));

            try!(fs::create_dir_all(&to));

            // forcedly overwrite if the file exists with same name.
            match fs::rename(path_to_dust, path_buf![to, target_file]) {
                Ok(_)  => (),
                Err(e) => match e.kind() {
                    IoErrorKind::PermissionDenied => self.print_and_log("     Interrupted for permission"),
                    _                             => return Err(From::from(e)),
                },
            };
        }

        Ok(())
    }

    pub fn squeeze_empty_dirs_only<P: AsRef<Path>>(&self, paths_to_dir: Vec<P>) -> Result<(), IoError> {
        let path_to_dust_box = self.path_to_dust_box();

        self.print_and_log(format!("Move empty dirs to \"{}\"", path_to_dust_box.display()));

        for path_to_dir in &paths_to_dir {
            if is_empty_dir(path_to_dir) {
                let path_to_dir = path_to_dir.as_ref();

                self.print_and_log(format!("  => \"{}\"", path_to_dir.display()));

                match fs::remove_dir(path_to_dir) {
                    Ok(_)  => try!(fs::create_dir_all(path_buf![&path_to_dust_box, path_to_dir])),
                    Err(e) => match e.kind() {
                        IoErrorKind::PermissionDenied => self.print_and_log("     Interrupted for permission"),
                        _                             => return Err(From::from(e)),
                    },
                };
            }
        }

        Ok(())
    }

    pub fn delete_expired_boxes(&self, moratorium: Duration) -> Result<(), IoError> {
        let path_to_storage = Self::path();

        self.print_and_log("Delete expired dusts");

        let target_boxes = try!(ls(&path_to_storage))
            .into_iter()
            .filter(|date| match Local.datetime_from_str(format!("{} 00:00:00", date).as_ref(), "%Y-%m-%d %H:%M:%S") {
                Ok(created_date) => created_date + moratorium < self.now,
                Err(_)           => false,
            })
            .map(|dir| path_to_storage.join(dir))
            .collect::<Vec<PathBuf>>();

        for target_box in &target_boxes {
            self.print_and_log(format!("  => \"{}\"", target_box.display()));
            try!(fs::remove_dir_all(target_box));
        };

        Ok(())
    }

    fn print_and_log<S: AsRef<str>>(&self, message: S) {
        let message = message.as_ref();
        print_with_tag(Tag::Info, message);
        if self.log_file.is_some() {
            self.write_log(message).ok();
        }
    }
}
<commit_msg>[Remedy] Storage.print_and_log() return "Result"<commit_after>extern crate chrono;

use self::chrono::{DateTime, Duration, Local};
use self::chrono::offset::TimeZone;

use constant::STORAGE_DIR_NAME;
use lib::fs::*;
use lib::io::*;
use std::fs::{self, OpenOptions};
use std::io::{Error as IoError, ErrorKind as IoErrorKind, Write};
use std::path::{Path, PathBuf};

pub struct Storage {
    now     : DateTime<Local>,
    date    : String,
    log_file: Option<String>,
}

impl Storage {
    fn path() -> PathBuf {
        path_buf![super::working_dir(), STORAGE_DIR_NAME]
    }

    pub fn exist() -> bool {
        Self::path().is_dir()
    }

    pub fn create() -> Result<(), IoError> {
        print_with_tag(Tag::Info, format!("Create \"{}\" directory", STORAGE_DIR_NAME));

        super::create_essential_dir(Self::path())
    }

    pub fn new() -> Self {
        let now  = Local::now();
        let date = now.format("%Y-%m-%d").to_string();
        Storage { now: now, date: date, log_file: None }
    }

    fn path_to_box(&self) -> PathBuf {
        path_buf![Storage::path(), &self.date]
    }

    fn path_to_dust_box(&self) -> PathBuf {
        path_buf![self.path_to_box(), "dusts"]
    }

    fn create_box(&self) -> Result<(), IoError> {
        print_with_tag(Tag::Info, format!(r#"Create "{}" directory in "{}""#, self.date, Self::path().display()));

        fs::create_dir_all(self.path_to_dust_box())
    }

    fn path_to_log(&self) -> PathBuf {
        let file_name = match &self.log_file {
            &Some(ref s) => s,
            &None        => unreachable!("Wrong to use path_to_log()"),
        };
        path_buf![self.path_to_box(), &file_name]
    }

    fn write_log<S: AsRef<str>>(&self, content: S) -> Result<usize, IoError> {
        let file = OpenOptions::new()
            .create(true)
            .append(true)
            .open(self.path_to_log());
        let mut file = try!(file);

        file.write(format!("{}\n", content.as_ref()).as_bytes())
    }

    fn start_mark_for_log(&self) -> String {
        let datetime = self.now.format("%H:%M:%S").to_string();
        format!(
            "############
# {} #
############",
            datetime,
        )
    }

    fn create_log_file(mut self, file_name: &str) -> Result<Self, IoError> {
        let file_name = format!("{}.log", file_name);

        print_with_tag(Tag::Info, format!(r#"Create "{}" file in "{}""#, file_name, self.path_to_box().display()));

        self.log_file = Some(file_name);

        try!(self.write_log(self.start_mark_for_log()));

        Ok(self)
    }

    pub fn create_box_with_log(self, file_name: &str) -> Result<Self, IoError> {
        try!(self.create_box());
        self.create_log_file(file_name)
    }

    pub fn squeeze_dusts<P: AsRef<Path>>(&self, paths_to_dust: Vec<P>) -> Result<(), IoError> {
        let path_to_dust_box = self.path_to_dust_box();

        let message = format!("Move dusts to \"{}\"", path_to_dust_box.display());
        try!(self.print_and_log(message));

        for path_to_dust in &paths_to_dust {
            let path_to_dust = path_to_dust.as_ref();
            let target_file  = match path_to_dust.file_name() {
                Some(f) => f,
                None    => unreachable!("Cannot get file name from path!!"),
            };
            let target_base = match path_to_dust.parent() {
                Some(b) => b,
                None    => unreachable!("Cannot get base name from path!!"),
            };

            let to = path_buf![&path_to_dust_box, target_base];

            let message = format!("  => \"{}\"", path_to_dust.display());
            try!(self.print_and_log(message));

            try!(fs::create_dir_all(&to));

            // forcedly overwrite if the file exists with same name.
            match fs::rename(path_to_dust, path_buf![to, target_file]) {
                Ok(_)  => (),
                Err(e) => match e.kind() {
                    IoErrorKind::PermissionDenied => try!(self.print_and_log("     Interrupted for permission")),
                    _                             => return Err(From::from(e)),
                },
            };
        }

        Ok(())
    }

    pub fn squeeze_empty_dirs_only<P: AsRef<Path>>(&self, paths_to_dir: Vec<P>) -> Result<(), IoError> {
        let path_to_dust_box = self.path_to_dust_box();

        let message = format!("Move empty dirs to \"{}\"", path_to_dust_box.display());
        try!(self.print_and_log(message));

        for path_to_dir in &paths_to_dir {
            if is_empty_dir(path_to_dir) {
                let path_to_dir = path_to_dir.as_ref();

                let message = format!("  => \"{}\"", path_to_dir.display());
                try!(self.print_and_log(message));

                match fs::remove_dir(path_to_dir) {
                    Ok(_)  => try!(fs::create_dir_all(path_buf![&path_to_dust_box, path_to_dir])),
                    Err(e) => match e.kind() {
                        IoErrorKind::PermissionDenied => try!(self.print_and_log("     Interrupted for permission")),
                        _                             => return Err(From::from(e)),
                    },
                };
            }
        }

        Ok(())
    }

    pub fn delete_expired_boxes(&self, moratorium: Duration) -> Result<(), IoError> {
        let path_to_storage = Self::path();

        try!(self.print_and_log("Delete expired dusts"));

        let target_boxes = try!(ls(&path_to_storage))
            .into_iter()
            .filter(|date| match Local.datetime_from_str(format!("{} 00:00:00", date).as_ref(), "%Y-%m-%d %H:%M:%S") {
                Ok(created_date) => created_date + moratorium < self.now,
                Err(_)           => false,
            })
            .map(|dir| path_to_storage.join(dir))
            .collect::<Vec<PathBuf>>();

        for target_box in &target_boxes {
            let message = format!("  => \"{}\"", target_box.display());
            try!(self.print_and_log(message));
            try!(fs::remove_dir_all(target_box));
        };

        Ok(())
    }

    fn print_and_log<S: AsRef<str>>(&self, message: S) -> Result<(), IoError> {
        print_with_tag(Tag::Info, message.as_ref());

        if self.log_file.is_some() {
            try!(self.write_log(message));
        }

        Ok(())
    }
}
<|endoftext|>