<commit_before>// Copyright 2014-2016 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Handling log-probabilities.

pub mod cdf;

use std::mem;
use std::f64;
use std::iter;
use std::ops::{Add, Sub, Mul, Div};

use itertools_num::linspace;
use itertools::Itertools;
use num_traits::Float;

/// A factor to convert log-probabilities to PHRED-scale (phred = p * `LOG_TO_PHRED_FACTOR`).
const LOG_TO_PHRED_FACTOR: f64 = -4.3429448190325175; // -10 * 1 / ln(10)

/// A factor to convert PHRED-scale to log-probabilities (p = phred * `PHRED_TO_LOG_FACTOR`).
const PHRED_TO_LOG_FACTOR: f64 = -0.23025850929940456; // 1 / (-10 * log10(e))

/// Calculate log(1 - p) with p given in log space without loss of precision as described in
/// http://cran.r-project.org/web/packages/Rmpfr/vignettes/log1mexp-note.pdf.
fn ln_1m_exp(p: f64) -> f64 {
    assert!(p <= 0.0);
    if p < -0.693 {
        (-p.exp()).ln_1p()
    } else {
        (-p.exp_m1()).ln()
    }
}

custom_derive! {
    /// A newtype for probabilities.
    ///
    /// # Example
    ///
    /// ```
    /// #[macro_use]
    /// extern crate approx;
    /// # extern crate bio;
    /// # fn main() {
    /// use bio::stats::Prob;
    ///
    /// let p = Prob(0.5);
    /// let q = Prob(0.2);
    ///
    /// assert_relative_eq!(*(p + q), *Prob(0.7));
    /// # }
    /// ```
    #[derive(
        NewtypeFrom,
        NewtypeDeref,
        NewtypeAdd(*),
        NewtypeSub(*),
        NewtypeMul(*),
        NewtypeDiv(*),
        PartialEq,
        PartialOrd,
        Copy,
        Clone,
        Debug,
        Default
    )]
    #[derive(Serialize, Deserialize)]
    pub struct Prob(pub f64);
}

impl Prob {
    pub fn checked(p: f64) -> Result<Self, ProbError> {
        if p >= 0.0 && p <= 1.0 {
            Ok(Prob(p))
        } else {
            Err(ProbError::InvalidProb(p))
        }
    }
}

custom_derive! {
    /// A newtype for log-scale probabilities.
    ///
    /// # Example
    ///
    /// ```
    /// #[macro_use]
    /// extern crate approx;
    /// # extern crate bio;
    /// # fn main() {
    /// use bio::stats::{LogProb, Prob};
    ///
    /// // convert from probability
    /// let p = LogProb::from(Prob(0.5));
    /// // convert manually
    /// let q = LogProb(0.2f64.ln());
    /// // obtain zero probability in log-space
    /// let o = LogProb::ln_one();
    ///
    /// assert_relative_eq!(*Prob::from(p.ln_add_exp(q) + o), *Prob(0.7));
    /// # }
    /// ```
    #[derive(
        NewtypeFrom,
        NewtypeDeref,
        NewtypeAdd(*),
        NewtypeSub(*),
        PartialEq,
        PartialOrd,
        Copy,
        Clone,
        Debug
    )]
    #[derive(Serialize, Deserialize)]
    pub struct LogProb(pub f64);
}

custom_derive! {
    /// A newtype for PHRED-scale probabilities.
    ///
    /// # Example
    ///
    /// ```
    /// #[macro_use]
    /// extern crate approx;
    /// # extern crate bio;
    /// # fn main() {
    /// use bio::stats::{PHREDProb, Prob};
    ///
    /// let p = PHREDProb::from(Prob(0.5));
    ///
    /// assert_relative_eq!(*Prob::from(p), *Prob(0.5));
    /// # }
    /// ```
    #[derive(
        NewtypeFrom,
        NewtypeDeref,
        NewtypeAdd(*),
        NewtypeSub(*),
        PartialEq,
        PartialOrd,
        Copy,
        Clone,
        Debug
    )]
    #[derive(Serialize, Deserialize)]
    pub struct PHREDProb(pub f64);
}

/// Iterator returned by scans over logprobs.
pub type ScanIter<I> = iter::Scan<<I as IntoIterator>::IntoIter,
                                  LogProb,
                                  fn(&mut LogProb, LogProb) -> Option<LogProb>>;

static LOGPROB_LN_ZERO: LogProb = LogProb(f64::NEG_INFINITY);
static LOGPROB_LN_ONE: LogProb = LogProb(0.0);

impl LogProb {
    /// Log-space representation of Pr=0
    pub fn ln_zero() -> LogProb {
        LOGPROB_LN_ZERO
    }

    /// Log-space representation of Pr=1
    pub fn ln_one() -> LogProb {
        LOGPROB_LN_ONE
    }

    /// Numerically stable calculation of 1 - p in log-space.
    pub fn ln_one_minus_exp(&self) -> LogProb {
        LogProb(ln_1m_exp(**self))
    }

    /// Numerically stable sum of probabilities in log-space.
    pub fn ln_sum_exp(probs: &[LogProb]) -> LogProb {
        if probs.is_empty() {
            Self::ln_zero()
        } else {
            let mut pmax = probs[0];
            let mut imax = 0;
            for (i, &p) in probs.iter().enumerate().skip(1) {
                if p > pmax {
                    pmax = p;
                    imax = i;
                }
            }
            if pmax == Self::ln_zero() {
                Self::ln_zero()
            } else if *pmax == f64::INFINITY {
                LogProb(f64::INFINITY)
            } else {
                // TODO use sum() once it has been stabilized: .sum::<usize>()
                pmax +
                LogProb((probs
                             .iter()
                             .enumerate()
                             .filter_map(|(i, p)| if i == imax {
                                             None
                                         } else {
                                             Some((p - pmax).exp())
                                         })
                             .fold(0.0, |s, e| s + e))
                                .ln_1p())
            }
        }
    }

    /// Numerically stable addition probabilities in log-space.
    pub fn ln_add_exp(self, other: LogProb) -> LogProb {
        let (mut p0, mut p1) = (self, other);
        if p1 > p0 {
            mem::swap(&mut p0, &mut p1);
        }
        if p0 == Self::ln_zero() {
            Self::ln_zero()
        } else if *p0 == f64::INFINITY {
            LogProb(f64::INFINITY)
        } else {
            p0 + LogProb((p1 - p0).exp().ln_1p())
        }
    }

    /// Numerically stable subtraction of probabilities in log-space.
    pub fn ln_sub_exp(self, other: LogProb) -> LogProb {
        let (p0, p1) = (self, other);
        assert!(p0 >= p1,
                "Subtraction would lead to negative probability, which is undefined in log space.");
        if *p1 == f64::NEG_INFINITY {
            p0
        } else if relative_eq!(*p0, *p1) || p0 == Self::ln_zero() {
            // the first case leads to zero,
            // in the second case p0 and p1 are -inf, which is fine
            Self::ln_zero()
        } else if *p0 == f64::INFINITY {
            LogProb(f64::INFINITY)
        } else {
            p0 + (p1 - p0).ln_one_minus_exp()
        }
    }

    /// Calculate the cumulative sum of the given probabilities in a numerically stable way (Durbin 1998).
    pub fn ln_cumsum_exp<I: IntoIterator<Item = LogProb>>(probs: I) -> ScanIter<I> {
        probs
            .into_iter()
            .scan(Self::ln_zero(), Self::scan_ln_add_exp)
    }

    /// Integrate numerically stable over given log-space density in the interval [a, b]. Uses the trapezoidal rule with n grid points.
    pub fn ln_trapezoidal_integrate_exp<T, D>(density: &D, a: T, b: T, n: usize) -> LogProb where
        T: Copy + Add<Output=T> + Sub<Output=T> + Div<Output=T> + Mul<Output=T> + Float,
        D: Fn(T) -> LogProb,
        f64: From<T>
    {
        let mut probs = linspace(a, b, n)
            .dropping(1)
            .dropping_back(1)
            .map(|v| LogProb(*density(v) + 2.0f64.ln()))
            .collect_vec();
        probs.push(density(a));
        probs.push(density(b));
        let width = f64::from(b - a);

        LogProb(*Self::ln_sum_exp(&probs) + width.ln() - (2.0 * (n - 1) as f64).ln())
    }

    /// Integrate numerically stable over given log-space density in the interval [a, b]. Uses Simpson's rule with n (odd) grid points.
    pub fn ln_simpsons_integrate_exp<T, D>(density: &D, a: T, b: T, n: usize) -> LogProb where
        T: Copy + Add<Output=T> + Sub<Output=T> + Div<Output=T> + Mul<Output=T> + Float,
        D: Fn(T) -> LogProb,
        f64: From<T>
    {
        assert_eq!(n % 2, 1, "n must be odd");
        let mut probs = linspace(a, b, n)
            .enumerate()
            .dropping(1)
            .dropping_back(1)
            .map(|(i, v)| {
                     let weight = (2 + (i % 2) * 2) as f64;
                     LogProb(*density(v) + weight.ln()) // factors alter between 2 and 4
                 })
            .collect_vec();
        probs.push(density(a));
        probs.push(density(b));
        let width = f64::from(b - a);

        LogProb(*Self::ln_sum_exp(&probs) + width.ln() - ((n - 1) as f64).ln() - 3.0f64.ln())
    }

    fn scan_ln_add_exp(s: &mut LogProb, p: LogProb) -> Option<LogProb> {
        *s = s.ln_add_exp(p);
        Some(*s)
    }
}

impl From<LogProb> for Prob {
    fn from(p: LogProb) -> Prob {
        Prob(p.exp())
    }
}

impl From<PHREDProb> for Prob {
    fn from(p: PHREDProb) -> Prob {
        Prob(10.0f64.powf(-*p / 10.0))
    }
}

impl From<Prob> for LogProb {
    fn from(p: Prob) -> LogProb {
        LogProb(p.ln())
    }
}

impl From<PHREDProb> for LogProb {
    fn from(p: PHREDProb) -> LogProb {
        LogProb(*p * PHRED_TO_LOG_FACTOR)
    }
}

impl From<Prob> for PHREDProb {
    fn from(p: Prob) -> PHREDProb {
        PHREDProb(-10.0 * p.log10())
    }
}

impl From<LogProb> for PHREDProb {
    fn from(p: LogProb) -> PHREDProb {
        PHREDProb(*p * LOG_TO_PHRED_FACTOR)
    }
}

impl Default for LogProb {
    fn default() -> LogProb {
        LogProb::ln_zero()
    }
}

impl Default for PHREDProb {
    fn default() -> PHREDProb {
        PHREDProb::from(Prob(0.0))
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum ProbError {
        InvalidProb(value: f64) {
            description("invalid probability")
            display("probabilty {} not in interval [0,1]", value)
        }
    }
}

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

    #[test]
    fn test_sum() {
        let probs = [LogProb::ln_zero(), LogProb::ln_one(), LogProb::ln_zero()];
        assert_eq!(LogProb::ln_sum_exp(&probs), LogProb::ln_one());
    }

    #[test]
    fn test_empty_sum() {
        assert_eq!(LogProb::ln_sum_exp(&[]), LogProb::ln_zero());
    }

    #[test]
    fn test_cumsum() {
        let probs = vec![LogProb::ln_zero(), LogProb(0.01f64.ln()), LogProb(0.001f64.ln())];
        assert_eq!(LogProb::ln_cumsum_exp(probs).collect_vec(),
                   [LogProb::ln_zero(), LogProb(0.01f64.ln()), LogProb(0.011f64.ln())]);
    }

    #[test]
    fn test_sub() {
        assert_eq!(
            LogProb::ln_one().ln_sub_exp(LogProb::ln_one()),
            LogProb::ln_zero()
        );
        assert_relative_eq!(
            *LogProb::ln_one().ln_sub_exp(LogProb(0.5f64.ln())),
            *LogProb(0.5f64.ln())
        );
        assert_relative_eq!(
            *LogProb(-1.6094379124341).ln_sub_exp(LogProb::ln_zero()),
            *LogProb(-1.6094379124341)
        );
    }

    #[test]
    fn test_one_minus() {
        assert_eq!(LogProb::ln_zero().ln_one_minus_exp(), LogProb::ln_one());
        assert_eq!(LogProb::ln_one().ln_one_minus_exp(), LogProb::ln_zero());
    }

    #[test]
    fn test_trapezoidal_integrate() {
        let density = |_| LogProb(0.1f64.ln());
        let prob = LogProb::ln_trapezoidal_integrate_exp(&density, 0.0, 10.0, 5);
        assert_relative_eq!(*prob, *LogProb::ln_one(), epsilon = 0.0000001);
    }

    #[test]
    fn test_simpsons_integrate() {
        let density = |_| LogProb(0.1f64.ln());
        let prob = LogProb::ln_simpsons_integrate_exp(&density, 0.0, 10.0, 5);
        assert_relative_eq!(*prob, *LogProb::ln_one(), epsilon = 0.0000001);
    }
}
<commit_msg>add LogProb::cap_numerical_overshoot() with tests (#152)<commit_after>// Copyright 2014-2016 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Handling log-probabilities.

pub mod cdf;

use std::mem;
use std::f64;
use std::iter;
use std::ops::{Add, Sub, Mul, Div};

use itertools_num::linspace;
use itertools::Itertools;
use num_traits::Float;

/// A factor to convert log-probabilities to PHRED-scale (phred = p * `LOG_TO_PHRED_FACTOR`).
const LOG_TO_PHRED_FACTOR: f64 = -4.3429448190325175; // -10 * 1 / ln(10)

/// A factor to convert PHRED-scale to log-probabilities (p = phred * `PHRED_TO_LOG_FACTOR`).
const PHRED_TO_LOG_FACTOR: f64 = -0.23025850929940456; // 1 / (-10 * log10(e))

/// Calculate log(1 - p) with p given in log space without loss of precision as described in
/// http://cran.r-project.org/web/packages/Rmpfr/vignettes/log1mexp-note.pdf.
fn ln_1m_exp(p: f64) -> f64 {
    assert!(p <= 0.0);
    if p < -0.693 {
        (-p.exp()).ln_1p()
    } else {
        (-p.exp_m1()).ln()
    }
}

custom_derive! {
    /// A newtype for probabilities.
    ///
    /// # Example
    ///
    /// ```
    /// #[macro_use]
    /// extern crate approx;
    /// # extern crate bio;
    /// # fn main() {
    /// use bio::stats::Prob;
    ///
    /// let p = Prob(0.5);
    /// let q = Prob(0.2);
    ///
    /// assert_relative_eq!(*(p + q), *Prob(0.7));
    /// # }
    /// ```
    #[derive(
        NewtypeFrom,
        NewtypeDeref,
        NewtypeAdd(*),
        NewtypeSub(*),
        NewtypeMul(*),
        NewtypeDiv(*),
        PartialEq,
        PartialOrd,
        Copy,
        Clone,
        Debug,
        Default
    )]
    #[derive(Serialize, Deserialize)]
    pub struct Prob(pub f64);
}

impl Prob {
    pub fn checked(p: f64) -> Result<Self, ProbError> {
        if p >= 0.0 && p <= 1.0 {
            Ok(Prob(p))
        } else {
            Err(ProbError::InvalidProb(p))
        }
    }
}

custom_derive! {
    /// A newtype for log-scale probabilities.
    ///
    /// # Example
    ///
    /// ```
    /// #[macro_use]
    /// extern crate approx;
    /// # extern crate bio;
    /// # fn main() {
    /// use bio::stats::{LogProb, Prob};
    ///
    /// // convert from probability
    /// let p = LogProb::from(Prob(0.5));
    /// // convert manually
    /// let q = LogProb(0.2f64.ln());
    /// // obtain zero probability in log-space
    /// let o = LogProb::ln_one();
    ///
    /// assert_relative_eq!(*Prob::from(p.ln_add_exp(q) + o), *Prob(0.7));
    /// # }
    /// ```
    #[derive(
        NewtypeFrom,
        NewtypeDeref,
        NewtypeAdd(*),
        NewtypeSub(*),
        PartialEq,
        PartialOrd,
        Copy,
        Clone,
        Debug
    )]
    #[derive(Serialize, Deserialize)]
    pub struct LogProb(pub f64);
}

custom_derive! {
    /// A newtype for PHRED-scale probabilities.
    ///
    /// # Example
    ///
    /// ```
    /// #[macro_use]
    /// extern crate approx;
    /// # extern crate bio;
    /// # fn main() {
    /// use bio::stats::{PHREDProb, Prob};
    ///
    /// let p = PHREDProb::from(Prob(0.5));
    ///
    /// assert_relative_eq!(*Prob::from(p), *Prob(0.5));
    /// # }
    /// ```
    #[derive(
        NewtypeFrom,
        NewtypeDeref,
        NewtypeAdd(*),
        NewtypeSub(*),
        PartialEq,
        PartialOrd,
        Copy,
        Clone,
        Debug
    )]
    #[derive(Serialize, Deserialize)]
    pub struct PHREDProb(pub f64);
}

/// Iterator returned by scans over logprobs.
pub type ScanIter<I> = iter::Scan<<I as IntoIterator>::IntoIter,
                                  LogProb,
                                  fn(&mut LogProb, LogProb) -> Option<LogProb>>;

static LOGPROB_LN_ZERO: LogProb = LogProb(f64::NEG_INFINITY);
static LOGPROB_LN_ONE: LogProb = LogProb(0.0);

impl LogProb {
    /// Log-space representation of Pr=0
    pub fn ln_zero() -> LogProb {
        LOGPROB_LN_ZERO
    }

    /// Log-space representation of Pr=1
    pub fn ln_one() -> LogProb {
        LOGPROB_LN_ONE
    }

    /// sums of LogProbs, e.g. with `ln_sum_exp()` can end up
    /// slightly above the maximum of `LogProb <= 0` due to
    /// numerical imprecisions -- this function can rescue such
    /// values before panics due to asserts in other functions
    /// handling LogProbs, e.g. `ln_1m_exp`
    pub fn cap_numerical_overshoot(&self, epsilon: f64) -> LogProb {
        if *self <= LogProb::ln_one() {
            return *self
        } else {
            let capped = **self - epsilon;
            if capped <= 0.0 {
                return LogProb::ln_one()
            } else {
                panic!("Cannot correct LogProb {:?} -- not within given epsilon of 0.0 ({})", **self, epsilon);
            }
        }
    }

    /// Numerically stable calculation of 1 - p in log-space.
    pub fn ln_one_minus_exp(&self) -> LogProb {
        LogProb(ln_1m_exp(**self))
    }

    /// Numerically stable sum of probabilities in log-space.
    pub fn ln_sum_exp(probs: &[LogProb]) -> LogProb {
        if probs.is_empty() {
            Self::ln_zero()
        } else {
            let mut pmax = probs[0];
            let mut imax = 0;
            for (i, &p) in probs.iter().enumerate().skip(1) {
                if p > pmax {
                    pmax = p;
                    imax = i;
                }
            }
            if pmax == Self::ln_zero() {
                Self::ln_zero()
            } else if *pmax == f64::INFINITY {
                LogProb(f64::INFINITY)
            } else {
                // TODO use sum() once it has been stabilized: .sum::<usize>()
                pmax +
                LogProb((probs
                             .iter()
                             .enumerate()
                             .filter_map(|(i, p)| if i == imax {
                                             None
                                         } else {
                                             Some((p - pmax).exp())
                                         })
                             .fold(0.0, |s, e| s + e))
                                .ln_1p())
            }
        }
    }

    /// Numerically stable addition probabilities in log-space.
    pub fn ln_add_exp(self, other: LogProb) -> LogProb {
        let (mut p0, mut p1) = (self, other);
        if p1 > p0 {
            mem::swap(&mut p0, &mut p1);
        }
        if p0 == Self::ln_zero() {
            Self::ln_zero()
        } else if *p0 == f64::INFINITY {
            LogProb(f64::INFINITY)
        } else {
            p0 + LogProb((p1 - p0).exp().ln_1p())
        }
    }

    /// Numerically stable subtraction of probabilities in log-space.
    pub fn ln_sub_exp(self, other: LogProb) -> LogProb {
        let (p0, p1) = (self, other);
        assert!(p0 >= p1,
                "Subtraction would lead to negative probability, which is undefined in log space.");
        if *p1 == f64::NEG_INFINITY {
            p0
        } else if relative_eq!(*p0, *p1) || p0 == Self::ln_zero() {
            // the first case leads to zero,
            // in the second case p0 and p1 are -inf, which is fine
            Self::ln_zero()
        } else if *p0 == f64::INFINITY {
            LogProb(f64::INFINITY)
        } else {
            p0 + (p1 - p0).ln_one_minus_exp()
        }
    }

    /// Calculate the cumulative sum of the given probabilities in a numerically stable way (Durbin 1998).
    pub fn ln_cumsum_exp<I: IntoIterator<Item = LogProb>>(probs: I) -> ScanIter<I> {
        probs
            .into_iter()
            .scan(Self::ln_zero(), Self::scan_ln_add_exp)
    }

    /// Integrate numerically stable over given log-space density in the interval [a, b]. Uses the trapezoidal rule with n grid points.
    pub fn ln_trapezoidal_integrate_exp<T, D>(density: &D, a: T, b: T, n: usize) -> LogProb where
        T: Copy + Add<Output=T> + Sub<Output=T> + Div<Output=T> + Mul<Output=T> + Float,
        D: Fn(T) -> LogProb,
        f64: From<T>
    {
        let mut probs = linspace(a, b, n)
            .dropping(1)
            .dropping_back(1)
            .map(|v| LogProb(*density(v) + 2.0f64.ln()))
            .collect_vec();
        probs.push(density(a));
        probs.push(density(b));
        let width = f64::from(b - a);

        LogProb(*Self::ln_sum_exp(&probs) + width.ln() - (2.0 * (n - 1) as f64).ln())
    }

    /// Integrate numerically stable over given log-space density in the interval [a, b]. Uses Simpson's rule with n (odd) grid points.
    pub fn ln_simpsons_integrate_exp<T, D>(density: &D, a: T, b: T, n: usize) -> LogProb where
        T: Copy + Add<Output=T> + Sub<Output=T> + Div<Output=T> + Mul<Output=T> + Float,
        D: Fn(T) -> LogProb,
        f64: From<T>
    {
        assert_eq!(n % 2, 1, "n must be odd");
        let mut probs = linspace(a, b, n)
            .enumerate()
            .dropping(1)
            .dropping_back(1)
            .map(|(i, v)| {
                     let weight = (2 + (i % 2) * 2) as f64;
                     LogProb(*density(v) + weight.ln()) // factors alter between 2 and 4
                 })
            .collect_vec();
        probs.push(density(a));
        probs.push(density(b));
        let width = f64::from(b - a);

        LogProb(*Self::ln_sum_exp(&probs) + width.ln() - ((n - 1) as f64).ln() - 3.0f64.ln())
    }

    fn scan_ln_add_exp(s: &mut LogProb, p: LogProb) -> Option<LogProb> {
        *s = s.ln_add_exp(p);
        Some(*s)
    }
}

impl From<LogProb> for Prob {
    fn from(p: LogProb) -> Prob {
        Prob(p.exp())
    }
}

impl From<PHREDProb> for Prob {
    fn from(p: PHREDProb) -> Prob {
        Prob(10.0f64.powf(-*p / 10.0))
    }
}

impl From<Prob> for LogProb {
    fn from(p: Prob) -> LogProb {
        LogProb(p.ln())
    }
}

impl From<PHREDProb> for LogProb {
    fn from(p: PHREDProb) -> LogProb {
        LogProb(*p * PHRED_TO_LOG_FACTOR)
    }
}

impl From<Prob> for PHREDProb {
    fn from(p: Prob) -> PHREDProb {
        PHREDProb(-10.0 * p.log10())
    }
}

impl From<LogProb> for PHREDProb {
    fn from(p: LogProb) -> PHREDProb {
        PHREDProb(*p * LOG_TO_PHRED_FACTOR)
    }
}

impl Default for LogProb {
    fn default() -> LogProb {
        LogProb::ln_zero()
    }
}

impl Default for PHREDProb {
    fn default() -> PHREDProb {
        PHREDProb::from(Prob(0.0))
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum ProbError {
        InvalidProb(value: f64) {
            description("invalid probability")
            display("probabilty {} not in interval [0,1]", value)
        }
    }
}

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

    #[test]
    fn test_sum() {
        let probs = [LogProb::ln_zero(), LogProb::ln_one(), LogProb::ln_zero()];
        assert_eq!(LogProb::ln_sum_exp(&probs), LogProb::ln_one());
    }

    #[test]
    fn test_empty_sum() {
        assert_eq!(LogProb::ln_sum_exp(&[]), LogProb::ln_zero());
    }

    #[test]
    fn test_cumsum() {
        let probs = vec![LogProb::ln_zero(), LogProb(0.01f64.ln()), LogProb(0.001f64.ln())];
        assert_eq!(LogProb::ln_cumsum_exp(probs).collect_vec(),
                   [LogProb::ln_zero(), LogProb(0.01f64.ln()), LogProb(0.011f64.ln())]);
    }

    #[test]
    fn test_sub() {
        assert_eq!(
            LogProb::ln_one().ln_sub_exp(LogProb::ln_one()),
            LogProb::ln_zero()
        );
        assert_relative_eq!(
            *LogProb::ln_one().ln_sub_exp(LogProb(0.5f64.ln())),
            *LogProb(0.5f64.ln())
        );
        assert_relative_eq!(
            *LogProb(-1.6094379124341).ln_sub_exp(LogProb::ln_zero()),
            *LogProb(-1.6094379124341)
        );
    }

    #[test]
    fn test_one_minus() {
        assert_eq!(LogProb::ln_zero().ln_one_minus_exp(), LogProb::ln_one());
        assert_eq!(LogProb::ln_one().ln_one_minus_exp(), LogProb::ln_zero());
    }

    #[test]
    fn test_trapezoidal_integrate() {
        let density = |_| LogProb(0.1f64.ln());
        let prob = LogProb::ln_trapezoidal_integrate_exp(&density, 0.0, 10.0, 5);
        assert_relative_eq!(*prob, *LogProb::ln_one(), epsilon = 0.0000001);
    }

    #[test]
    fn test_simpsons_integrate() {
        let density = |_| LogProb(0.1f64.ln());
        let prob = LogProb::ln_simpsons_integrate_exp(&density, 0.0, 10.0, 5);
        assert_relative_eq!(*prob, *LogProb::ln_one(), epsilon = 0.0000001);
    }

    #[test]
    fn test_cap_numerical_overshoot() {
        let under_top = LogProb(-0.00000005);
        assert_eq!(under_top, under_top.cap_numerical_overshoot(0.0000001) );
        let over_top = LogProb(0.00000005);
        assert_eq!(LogProb::ln_one(), over_top.cap_numerical_overshoot(0.0000001) );
    }

    #[test]
    #[should_panic]
    fn test_cap_numerical_overshoot_panic() {
        let over_top = LogProb(0.00000005);
        over_top.cap_numerical_overshoot(0.00000001);
    }

}
<|endoftext|>


<commit_before>//! Basic types to build the parsers

use self::IResult::*;
use self::Needed::*;

#[cfg(feature = "core")]
use std::prelude::v1::*;

#[cfg(feature = "verbose-errors")]
use verbose_errors::Err;

#[cfg(not(feature = "verbose-errors"))]
use simple_errors::Err;

/// Contains information on needed data if a parser returned `Incomplete`
#[derive(Debug,PartialEq,Eq,Clone,Copy)]
pub enum Needed {
  /// needs more data, but we do not know how much
  Unknown,
  /// contains the required data size
  Size(usize)
}

impl Needed {
  pub fn is_known(&self) -> bool {
    *self != Unknown
  }

  /// Maps a `Needed` to `Needed` by appling a function to a contained `Size` value.
  #[inline]
  pub fn map<F: FnOnce(usize) -> usize>(self, f: F) -> Needed {
    match self {
      Unknown => Unknown,
      Size(n) => Size(f(n)),
    }
  }
}

#[cfg(feature = "verbose-errors")]
/// Holds the result of parsing functions
///
/// It depends on I, the input type, O, the output type, and E, the error type (by default u32)
///
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum IResult<I,O,E=u32> {
   /// indicates a correct parsing, the first field containing the rest of the unparsed data, the second field contains the parsed data
  Done(I,O),
  /// contains a Err, an enum that can indicate an error code, a position in the input, and a pointer to another error, making a list of errors in the parsing tree
  Error(Err<I,E>),
  /// Incomplete contains a Needed, an enum than can represent a known quantity of input data, or unknown
  Incomplete(Needed)
}

#[cfg(not(feature = "verbose-errors"))]
/// Holds the result of parsing functions
///
/// It depends on I, the input type, O, the output type, and E, the error type (by default u32)
///
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum IResult<I,O,E=u32> {
   /// indicates a correct parsing, the first field containing the rest of the unparsed data, the second field contains the parsed data
  Done(I,O),
  /// contains a Err, an enum that can indicate an error code, a position in the input, and a pointer to another error, making a list of errors in the parsing tree
  Error(Err<E>),
  /// Incomplete contains a Needed, an enum than can represent a known quantity of input data, or unknown
  Incomplete(Needed)
}

impl<I,O,E> IResult<I,O,E> {
  pub fn is_done(&self) -> bool {
    match *self {
      Done(_,_) => true,
      _         => false
    }
  }

  pub fn is_err(&self) -> bool {
    match *self {
      Error(_) => true,
      _        => false
    }
  }

  pub fn is_incomplete(&self) -> bool {
    match *self {
      Incomplete(_) => true,
      _             => false
    }
  }

  /// Maps a `IResult<I, O, E>` to `IResult<I, N, E>` by appling a function
  /// to a contained `Done` value, leaving `Error` and `Incomplete` value
  /// untouched.
  #[inline]
  pub fn map<N, F: FnOnce(O) -> N>(self, f: F) -> IResult<I, N, E> {
    match self {
      Done(i, o)    => Done(i, f(o)),
      Error(e)      => Error(e),
      Incomplete(n) => Incomplete(n),
    }
  }

  /// Maps a `IResult<I, O, E>` to `IResult<I, O, E>` by appling a function
  /// to a contained `Incomplete` value, leaving `Done` and `Error` value
  /// untouched.
  #[inline]
  pub fn map_inc<F>(self, f: F) -> IResult<I, O, E>
   where F: FnOnce(Needed) -> Needed {
    match self {
      Error(e)      => Error(e),
      Incomplete(n) => Incomplete(f(n)),
      Done(i, o)    => Done(i, o),
    }
  }

  /// Unwrap the contained `Done(I, O)` value, or panic if the `IResult` is not
  /// `Done`.
  pub fn unwrap(self) -> (I, O) {
    match self {
      Done(i, o)    => (i, o),
      Incomplete(_) => panic!("unwrap() called on an IResult that is Incomplete"),
      Error(_)      => panic!("unwrap() called on an IResult that is Error")
    }
  }

  /// Unwrap the contained `Incomplete(n)` value, or panic if the `IResult` is not
  /// `Incomplete`.
  pub fn unwrap_inc(self) -> Needed {
    match self {
      Incomplete(n) => n,
      Done(_, _)    => panic!("unwrap_inc() called on an IResult that is Done"),
      Error(_)      => panic!("unwrap_inc() called on an IResult that is Error")
    }
  }
}

pub trait GetInput<I> {
  fn remaining_input(&self) -> Option<I>;
}

pub trait GetOutput<O> {
  fn output(&self) -> Option<O>;
}

impl<'a,I,O,E> GetInput<&'a[I]> for IResult<&'a[I],O,E> {
  fn remaining_input(&self) -> Option<&'a[I]> {
    match *self {
      Done(ref i,_) => Some(*i),
      _             => None
    }
  }
}

impl<O,E> GetInput<()> for IResult<(),O,E> {
  fn remaining_input(&self) -> Option<()> {
    match *self {
      Done((),_) => Some(()),
      _          => None
    }
  }
}

impl<'a,O,E> GetInput<&'a str> for IResult<&'a str,O,E> {
  fn remaining_input(&self) -> Option<&'a str> {
    match *self {
      Done(ref i,_) => Some(*i),
      _          => None
    }
  }
}

impl<'a,I,O,E> GetOutput<&'a[O]> for IResult<I,&'a[O],E> {
  fn output(&self) -> Option<&'a[O]> {
    match *self {
      Done(_, ref o) => Some(*o),
      _              => None
    }
  }
}

impl<I,E> GetOutput<()> for IResult<I,(),E> {
  fn output(&self) -> Option<()> {
    match *self {
      Done(_,()) => Some(()),
      _          => None
    }
  }
}

impl<'a,I,E> GetOutput<&'a str> for IResult<I,&'a str,E> {
  fn output(&self) -> Option<&'a str> {
    match *self {
      Done(_,ref o) => Some(*o),
      _          => None
    }
  }
}

#[cfg(not(feature = "core"))]
#[cfg(feature = "verbose-errors")]
use std::any::Any;
#[cfg(not(feature = "core"))]
#[cfg(feature = "verbose-errors")]
use std::{error,fmt};
#[cfg(not(feature = "core"))]
#[cfg(feature = "verbose-errors")]
use std::fmt::Debug;
#[cfg(not(feature = "core"))]
#[cfg(feature = "verbose-errors")]
impl<P:Debug+Any,E:Debug+Any> error::Error for Err<P,E> {
  fn description(&self) -> &str {
    let kind = match *self {
      Err::Code(ref e) | Err::Node(ref e, _) | Err::Position(ref e, _) | Err::NodePosition(ref e, _, _) => e
    };
    kind.description()
  }
}

#[cfg(not(feature = "core"))]
#[cfg(feature = "verbose-errors")]
impl<P:fmt::Debug,E:fmt::Debug> fmt::Display for Err<P,E> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Err::Code(ref e) | Err::Node(ref e, _) => {
        write!(f, "{:?}", e)
      },
      Err::Position(ref e, ref p) | Err::NodePosition(ref e, ref p, _) => {
        write!(f, "{:?}:{:?}", p, e)
      }
    }
  }
}

#[cfg(feature = "verbose-errors")]
#[macro_export]
macro_rules! error_code(
  ($code:expr) => ($crate::Err::Code($code));
);

#[cfg(not(feature = "verbose-errors"))]
#[macro_export]
macro_rules! error_code(
  ($code:expr) => ($code);
);

#[cfg(feature = "verbose-errors")]
#[macro_export]
macro_rules! error_node(
  ($code:expr, $next:expr) => ($crate::Err::Node($code, ::std::boxed::Box::new($next)));
);

#[cfg(not(feature = "verbose-errors"))]
#[macro_export]
macro_rules! error_node(
  ($code:expr, $next:expr) => ($code);
);

#[cfg(feature = "verbose-errors")]
#[macro_export]
macro_rules! error_position(
  ($code:expr, $input:expr) => ($crate::Err::Position($code, $input));
);

#[cfg(not(feature = "verbose-errors"))]
#[macro_export]
macro_rules! error_position(
  ($code:expr, $input:expr) => ($code);
);

#[cfg(feature = "verbose-errors")]
#[macro_export]
macro_rules! error_node_position(
  ($code:expr, $input:expr, $next:expr) => ($crate::Err::NodePosition($code, $input, ::std::boxed::Box::new($next)));
);

#[cfg(not(feature = "verbose-errors"))]
#[macro_export]
macro_rules! error_node_position(
  ($code:expr, $input: expr, $next:expr) => ($code);
);

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

  const REST: [u8; 0] = [];
  const DONE: IResult<&'static [u8], u32> = IResult::Done(&REST, 5);
  const ERROR: IResult<&'static [u8], u32> = IResult::Error(error_code!(ErrorKind::Tag));
  const INCOMPLETE: IResult<&'static [u8], u32> = IResult::Incomplete(Needed::Unknown);

  #[test]
  fn needed_map() {
    let unknown = Needed::Unknown;
    let size = Needed::Size(5);

    assert_eq!(size.map(|x| x * 2), Needed::Size(10));
    assert_eq!(unknown.map(|x| x * 2), Needed::Unknown);
  }

  #[test]
  fn iresult_map() {
    assert_eq!(DONE.map(|x| x * 2), IResult::Done(&b""[..], 10));
    assert_eq!(ERROR.map(|x| x * 2), IResult::Error(error_code!(ErrorKind::Tag)));
    assert_eq!(INCOMPLETE.map(|x| x * 2), IResult::Incomplete(Needed::Unknown));
  }

  #[test]
  fn iresult_map_inc() {
    let inc_unknown: IResult<&[u8], u32> = IResult::Incomplete(Needed::Unknown);
    let inc_size: IResult<&[u8], u32> = IResult::Incomplete(Needed::Size(5));

    assert_eq!(DONE.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Done(&b""[..], 5));
    assert_eq!(ERROR.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Error(error_code!(ErrorKind::Tag)));
    assert_eq!(inc_unknown.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Incomplete(Needed::Unknown));
    assert_eq!(inc_size.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Incomplete(Needed::Size(6)));
  }

  #[test]
  fn iresult_map_err() {
    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    struct Error(u32);

    let error_kind = error_code!(ErrorKind::Custom(Error(5)));

    assert_eq!(DONE.map_err(|_| error_kind.clone()), IResult::Done(&b""[..], 5));
    assert_eq!(ERROR.map_err(|x| {println!("err: {:?}", x); error_kind.clone()}), IResult::Error(error_kind.clone()));
    assert_eq!(INCOMPLETE.map_err(|x| {println!("err: {:?}", x); error_kind.clone()}), IResult::Incomplete(Needed::Unknown));
  }

  #[test]
  fn iresult_unwrap_on_done() {
    assert_eq!(DONE.unwrap(), (&b""[..], 5));
  }

  #[test]
  #[should_panic]
  fn iresult_unwrap_on_err() {
    ERROR.unwrap();
  }

  #[test]
  #[should_panic]
  fn iresult_unwrap_on_inc() {
    INCOMPLETE.unwrap();
  }

  #[test]
  #[should_panic]
  fn iresult_unwrap_err_on_done() {
    DONE.unwrap_err();
  }

  #[test]
  fn iresult_unwrap_err_on_err() {
    assert_eq!(ERROR.unwrap_err(), error_code!(ErrorKind::Tag));
  }

  #[test]
  #[should_panic]
  fn iresult_unwrap_err_on_inc() {
    INCOMPLETE.unwrap_err();
  }

  #[test]
  #[should_panic]
  fn iresult_unwrap_inc_on_done() {
    DONE.unwrap_inc();
  }

  #[test]
  #[should_panic]
  fn iresult_unwrap_inc_on_err() {
    ERROR.unwrap_inc();
  }

  #[test]
  fn iresult_unwrap_inc_on_inc() {
    assert_eq!(INCOMPLETE.unwrap_inc(), Needed::Unknown);
  }
}
<commit_msg>add a way to convert an IResult to a std::result::Result<commit_after>//! Basic types to build the parsers

use self::IResult::*;
use self::Needed::*;

#[cfg(feature = "core")]
use std::prelude::v1::*;

#[cfg(feature = "verbose-errors")]
use verbose_errors::Err;

#[cfg(not(feature = "verbose-errors"))]
use simple_errors::Err;

/// Contains information on needed data if a parser returned `Incomplete`
#[derive(Debug,PartialEq,Eq,Clone,Copy)]
pub enum Needed {
  /// needs more data, but we do not know how much
  Unknown,
  /// contains the required data size
  Size(usize)
}

impl Needed {
  pub fn is_known(&self) -> bool {
    *self != Unknown
  }

  /// Maps a `Needed` to `Needed` by appling a function to a contained `Size` value.
  #[inline]
  pub fn map<F: FnOnce(usize) -> usize>(self, f: F) -> Needed {
    match self {
      Unknown => Unknown,
      Size(n) => Size(f(n)),
    }
  }
}

#[cfg(feature = "verbose-errors")]
/// Holds the result of parsing functions
///
/// It depends on I, the input type, O, the output type, and E, the error type (by default u32)
///
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum IResult<I,O,E=u32> {
   /// indicates a correct parsing, the first field containing the rest of the unparsed data, the second field contains the parsed data
  Done(I,O),
  /// contains a Err, an enum that can indicate an error code, a position in the input, and a pointer to another error, making a list of errors in the parsing tree
  Error(Err<I,E>),
  /// Incomplete contains a Needed, an enum than can represent a known quantity of input data, or unknown
  Incomplete(Needed)
}

#[cfg(not(feature = "verbose-errors"))]
/// Holds the result of parsing functions
///
/// It depends on I, the input type, O, the output type, and E, the error type (by default u32)
///
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum IResult<I,O,E=u32> {
   /// indicates a correct parsing, the first field containing the rest of the unparsed data, the second field contains the parsed data
  Done(I,O),
  /// contains a Err, an enum that can indicate an error code, a position in the input, and a pointer to another error, making a list of errors in the parsing tree
  Error(Err<E>),
  /// Incomplete contains a Needed, an enum than can represent a known quantity of input data, or unknown
  Incomplete(Needed)
}

#[cfg(feature = "verbose-errors")]
/// This is the same as IResult, but without Done
///
/// This is used as the Error type when converting to std::result::Result
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum IError<I,E=u32> {
  Error(Err<I,E>),
  Incomplete(Needed)
}

#[cfg(not(feature = "verbose-errors"))]
/// This is the same as IResult, but without Done
///
/// This is used as the Error type when converting to std::result::Result
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum IError<I,E=u32> {
  Error(Err<E>),
  Incomplete(Needed)
}

impl<I,O,E> IResult<I,O,E> {
  pub fn is_done(&self) -> bool {
    match *self {
      Done(_,_) => true,
      _         => false
    }
  }

  pub fn is_err(&self) -> bool {
    match *self {
      Error(_) => true,
      _        => false
    }
  }

  pub fn is_incomplete(&self) -> bool {
    match *self {
      Incomplete(_) => true,
      _             => false
    }
  }

  /// Maps a `IResult<I, O, E>` to `IResult<I, N, E>` by appling a function
  /// to a contained `Done` value, leaving `Error` and `Incomplete` value
  /// untouched.
  #[inline]
  pub fn map<N, F: FnOnce(O) -> N>(self, f: F) -> IResult<I, N, E> {
    match self {
      Done(i, o)    => Done(i, f(o)),
      Error(e)      => Error(e),
      Incomplete(n) => Incomplete(n),
    }
  }

  /// Maps a `IResult<I, O, E>` to `IResult<I, O, E>` by appling a function
  /// to a contained `Incomplete` value, leaving `Done` and `Error` value
  /// untouched.
  #[inline]
  pub fn map_inc<F>(self, f: F) -> IResult<I, O, E>
   where F: FnOnce(Needed) -> Needed {
    match self {
      Error(e)      => Error(e),
      Incomplete(n) => Incomplete(f(n)),
      Done(i, o)    => Done(i, o),
    }
  }

  /// Unwrap the contained `Done(I, O)` value, or panic if the `IResult` is not
  /// `Done`.
  pub fn unwrap(self) -> (I, O) {
    match self {
      Done(i, o)    => (i, o),
      Incomplete(_) => panic!("unwrap() called on an IResult that is Incomplete"),
      Error(_)      => panic!("unwrap() called on an IResult that is Error")
    }
  }

  /// Unwrap the contained `Incomplete(n)` value, or panic if the `IResult` is not
  /// `Incomplete`.
  pub fn unwrap_inc(self) -> Needed {
    match self {
      Incomplete(n) => n,
      Done(_, _)    => panic!("unwrap_inc() called on an IResult that is Done"),
      Error(_)      => panic!("unwrap_inc() called on an IResult that is Error")
    }
  }

  /// Convert the IResult to a std::result::Result
  pub fn to_result(self) -> Result<O, IError<I,E>> {
    match self {
      Done(_, o)    => Ok(o),
      Incomplete(n) => Err(IError::Incomplete(n)),
      Error(e)      => Err(IError::Error(e))
    }
  }
}

pub trait GetInput<I> {
  fn remaining_input(&self) -> Option<I>;
}

pub trait GetOutput<O> {
  fn output(&self) -> Option<O>;
}

impl<'a,I,O,E> GetInput<&'a[I]> for IResult<&'a[I],O,E> {
  fn remaining_input(&self) -> Option<&'a[I]> {
    match *self {
      Done(ref i,_) => Some(*i),
      _             => None
    }
  }
}

impl<O,E> GetInput<()> for IResult<(),O,E> {
  fn remaining_input(&self) -> Option<()> {
    match *self {
      Done((),_) => Some(()),
      _          => None
    }
  }
}

impl<'a,O,E> GetInput<&'a str> for IResult<&'a str,O,E> {
  fn remaining_input(&self) -> Option<&'a str> {
    match *self {
      Done(ref i,_) => Some(*i),
      _          => None
    }
  }
}

impl<'a,I,O,E> GetOutput<&'a[O]> for IResult<I,&'a[O],E> {
  fn output(&self) -> Option<&'a[O]> {
    match *self {
      Done(_, ref o) => Some(*o),
      _              => None
    }
  }
}

impl<I,E> GetOutput<()> for IResult<I,(),E> {
  fn output(&self) -> Option<()> {
    match *self {
      Done(_,()) => Some(()),
      _          => None
    }
  }
}

impl<'a,I,E> GetOutput<&'a str> for IResult<I,&'a str,E> {
  fn output(&self) -> Option<&'a str> {
    match *self {
      Done(_,ref o) => Some(*o),
      _          => None
    }
  }
}

#[cfg(not(feature = "core"))]
#[cfg(feature = "verbose-errors")]
use std::any::Any;
#[cfg(not(feature = "core"))]
#[cfg(feature = "verbose-errors")]
use std::{error,fmt};
#[cfg(not(feature = "core"))]
#[cfg(feature = "verbose-errors")]
use std::fmt::Debug;
#[cfg(not(feature = "core"))]
#[cfg(feature = "verbose-errors")]
impl<P:Debug+Any,E:Debug+Any> error::Error for Err<P,E> {
  fn description(&self) -> &str {
    let kind = match *self {
      Err::Code(ref e) | Err::Node(ref e, _) | Err::Position(ref e, _) | Err::NodePosition(ref e, _, _) => e
    };
    kind.description()
  }
}

#[cfg(not(feature = "core"))]
#[cfg(feature = "verbose-errors")]
impl<P:fmt::Debug,E:fmt::Debug> fmt::Display for Err<P,E> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Err::Code(ref e) | Err::Node(ref e, _) => {
        write!(f, "{:?}", e)
      },
      Err::Position(ref e, ref p) | Err::NodePosition(ref e, ref p, _) => {
        write!(f, "{:?}:{:?}", p, e)
      }
    }
  }
}

#[cfg(feature = "verbose-errors")]
#[macro_export]
macro_rules! error_code(
  ($code:expr) => ($crate::Err::Code($code));
);

#[cfg(not(feature = "verbose-errors"))]
#[macro_export]
macro_rules! error_code(
  ($code:expr) => ($code);
);

#[cfg(feature = "verbose-errors")]
#[macro_export]
macro_rules! error_node(
  ($code:expr, $next:expr) => ($crate::Err::Node($code, ::std::boxed::Box::new($next)));
);

#[cfg(not(feature = "verbose-errors"))]
#[macro_export]
macro_rules! error_node(
  ($code:expr, $next:expr) => ($code);
);

#[cfg(feature = "verbose-errors")]
#[macro_export]
macro_rules! error_position(
  ($code:expr, $input:expr) => ($crate::Err::Position($code, $input));
);

#[cfg(not(feature = "verbose-errors"))]
#[macro_export]
macro_rules! error_position(
  ($code:expr, $input:expr) => ($code);
);

#[cfg(feature = "verbose-errors")]
#[macro_export]
macro_rules! error_node_position(
  ($code:expr, $input:expr, $next:expr) => ($crate::Err::NodePosition($code, $input, ::std::boxed::Box::new($next)));
);

#[cfg(not(feature = "verbose-errors"))]
#[macro_export]
macro_rules! error_node_position(
  ($code:expr, $input: expr, $next:expr) => ($code);
);

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

  const REST: [u8; 0] = [];
  const DONE: IResult<&'static [u8], u32> = IResult::Done(&REST, 5);
  const ERROR: IResult<&'static [u8], u32> = IResult::Error(error_code!(ErrorKind::Tag));
  const INCOMPLETE: IResult<&'static [u8], u32> = IResult::Incomplete(Needed::Unknown);

  #[test]
  fn needed_map() {
    let unknown = Needed::Unknown;
    let size = Needed::Size(5);

    assert_eq!(size.map(|x| x * 2), Needed::Size(10));
    assert_eq!(unknown.map(|x| x * 2), Needed::Unknown);
  }

  #[test]
  fn iresult_map() {
    assert_eq!(DONE.map(|x| x * 2), IResult::Done(&b""[..], 10));
    assert_eq!(ERROR.map(|x| x * 2), IResult::Error(error_code!(ErrorKind::Tag)));
    assert_eq!(INCOMPLETE.map(|x| x * 2), IResult::Incomplete(Needed::Unknown));
  }

  #[test]
  fn iresult_map_inc() {
    let inc_unknown: IResult<&[u8], u32> = IResult::Incomplete(Needed::Unknown);
    let inc_size: IResult<&[u8], u32> = IResult::Incomplete(Needed::Size(5));

    assert_eq!(DONE.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Done(&b""[..], 5));
    assert_eq!(ERROR.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Error(error_code!(ErrorKind::Tag)));
    assert_eq!(inc_unknown.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Incomplete(Needed::Unknown));
    assert_eq!(inc_size.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Incomplete(Needed::Size(6)));
  }

  #[test]
  fn iresult_map_err() {
    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    struct Error(u32);

    let error_kind = error_code!(ErrorKind::Custom(Error(5)));

    assert_eq!(DONE.map_err(|_| error_kind.clone()), IResult::Done(&b""[..], 5));
    assert_eq!(ERROR.map_err(|x| {println!("err: {:?}", x); error_kind.clone()}), IResult::Error(error_kind.clone()));
    assert_eq!(INCOMPLETE.map_err(|x| {println!("err: {:?}", x); error_kind.clone()}), IResult::Incomplete(Needed::Unknown));
  }

  #[test]
  fn iresult_unwrap_on_done() {
    assert_eq!(DONE.unwrap(), (&b""[..], 5));
  }

  #[test]
  #[should_panic]
  fn iresult_unwrap_on_err() {
    ERROR.unwrap();
  }

  #[test]
  #[should_panic]
  fn iresult_unwrap_on_inc() {
    INCOMPLETE.unwrap();
  }

  #[test]
  #[should_panic]
  fn iresult_unwrap_err_on_done() {
    DONE.unwrap_err();
  }

  #[test]
  fn iresult_unwrap_err_on_err() {
    assert_eq!(ERROR.unwrap_err(), error_code!(ErrorKind::Tag));
  }

  #[test]
  #[should_panic]
  fn iresult_unwrap_err_on_inc() {
    INCOMPLETE.unwrap_err();
  }

  #[test]
  #[should_panic]
  fn iresult_unwrap_inc_on_done() {
    DONE.unwrap_inc();
  }

  #[test]
  #[should_panic]
  fn iresult_unwrap_inc_on_err() {
    ERROR.unwrap_inc();
  }

  #[test]
  fn iresult_unwrap_inc_on_inc() {
    assert_eq!(INCOMPLETE.unwrap_inc(), Needed::Unknown);
  }

  #[test]
  fn iresult_to_result() {
    assert_eq!(DONE.to_result(), Ok(5));
    assert_eq!(INCOMPLETE.to_result(), Err(IError::Incomplete(Needed::Unknown)));
    assert_eq!(ERROR.to_result(), Err(IError::Error(error_code!(ErrorKind::Tag))));
  }
}
<|endoftext|>


<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! FastQ reading and writing.
//!
//! # Example
//!
//! ```
//! use std::io;
//! use bio::io::fastq;
//! let reader = fastq::Reader::new(io::stdin());
//! ```

use std::io;
use std::io::prelude::*;
use std::ascii::AsciiExt;
use std::fs;
use std::path::Path;
use std::convert::AsRef;

/// A FastQ reader.
pub struct Reader<R: io::Read> {
    reader: io::BufReader<R>,
    sep_line: String,
}

impl Reader<fs::File> {
    /// Read from a given file.
    pub fn from_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        fs::File::open(path).map(Reader::new)
    }
}

impl<R: io::Read> Reader<R> {
    /// Read from a given `io::Read`.
    pub fn new(reader: R) -> Self {
        Reader {
            reader: io::BufReader::new(reader),
            sep_line: String::new(),
        }
    }

    /// Read into a given record.
    /// Returns an error if the record in incomplete or syntax is violated.
    /// The content of the record can be checked via the record object.
    pub fn read(&mut self, record: &mut Record) -> io::Result<()> {
        record.clear();
        try!(self.reader.read_line(&mut record.header));

        if !record.header.is_empty() {
            if !record.header.starts_with('@') {
                return Err(io::Error::new(io::ErrorKind::Other, "Expected @ at record start."));
            }
            try!(self.reader.read_line(&mut record.seq));
            try!(self.reader.read_line(&mut self.sep_line));
            try!(self.reader.read_line(&mut record.qual));
            if record.qual.is_empty() {
                return Err(io::Error::new(io::ErrorKind::Other,
                                          "Incomplete record. Each FastQ record has to consist \
                                           of 4 lines: header, sequence, separator and qualities."));
            }
        }

        Ok(())
    }

    /// Return an iterator over the records of this FastQ file.
    pub fn records(self) -> Records<R> {
        Records { reader: self }
    }
}

/// A FastQ record.
pub struct Record {
    header: String,
    seq: String,
    qual: String,
}

impl Record {
    /// Create a new, empty FastQ record.
    pub fn new() -> Self {
        Record {
            header: String::new(),
            seq: String::new(),
            qual: String::new(),
        }
    }

    /// Check if record is empty.
    pub fn is_empty(&self) -> bool {
        self.header.is_empty() && self.seq.is_empty() && self.qual.is_empty()
    }

    /// Check validity of FastQ record.
    pub fn check(&self) -> Result<(), &str> {
        if self.id().is_none() {
            return Err("Expecting id for FastQ record.");
        }
        if !self.seq.is_ascii() {
            return Err("Non-ascii character found in sequence.");
        }
        if !self.qual.is_ascii() {
            return Err("Non-ascii character found in qualities.");
        }
        if self.seq().len() != self.qual().len() {
            return Err("Unequal length of sequence an qualities.");
        }

        Ok(())
    }

    /// Return the id of the record.
    pub fn id(&self) -> Option<&str> {
        self.header[1..].trim_right().splitn(2, ' ').next()
    }

    /// Return descriptions if present.
    pub fn desc(&self) -> Option<&str> {
        self.header[1..].trim_right().splitn(2, ' ').skip(1).next()
    }

    /// Return the sequence of the record.
    pub fn seq(&self) -> &[u8] {
        self.seq.trim_right().as_bytes()
    }

    /// Return the base qualities of the record.
    pub fn qual(&self) -> &[u8] {
        self.qual.trim_right().as_bytes()
    }

    /// Clear the record.
    fn clear(&mut self) {
        self.header.clear();
        self.seq.clear();
        self.qual.clear();
    }
}

/// An iterator over the records of a FastQ file.
pub struct Records<R: io::Read> {
    reader: Reader<R>,
}

impl<R: io::Read> Iterator for Records<R> {
    type Item = io::Result<Record>;

    fn next(&mut self) -> Option<io::Result<Record>> {
        let mut record = Record::new();
        match self.reader.read(&mut record) {
            Ok(()) if record.is_empty() => None,
            Ok(()) => Some(Ok(record)),
            Err(err) => Some(Err(err)),
        }
    }
}

/// A FastQ writer.
pub struct Writer<W: io::Write> {
    writer: io::BufWriter<W>,
}

impl Writer<fs::File> {
    /// Write to a given file path.
    pub fn to_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        fs::File::create(path).map(Writer::new)
    }
}

impl<W: io::Write> Writer<W> {
    /// Write to a given `io::Write`.
    pub fn new(writer: W) -> Self {
        Writer { writer: io::BufWriter::new(writer) }
    }

    /// Directly write a FastQ record.
    pub fn write_record(&mut self, record: Record) -> io::Result<()> {
        self.write(record.id().unwrap_or(""),
                   record.desc(),
                   record.seq(),
                   record.qual())
    }

    /// Write a FastQ record with given id, optional description, sequence and qualities.
    pub fn write(&mut self,
                 id: &str,
                 desc: Option<&str>,
                 seq: &[u8],
                 qual: &[u8])
                 -> io::Result<()> {
        try!(self.writer.write(b"@"));
        try!(self.writer.write(id.as_bytes()));
        if desc.is_some() {
            try!(self.writer.write(b" "));
            try!(self.writer.write(desc.unwrap().as_bytes()));
        }
        try!(self.writer.write(b"\n"));
        try!(self.writer.write(seq));
        try!(self.writer.write(b"\n+\n"));
        try!(self.writer.write(qual));
        try!(self.writer.write(b"\n"));

        Ok(())
    }

    /// Flush the writer, ensuring that everything is written.
    pub fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }
}

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

    const FASTQ_FILE: &'static [u8] = b"@id desc
ACCGTAGGCTGA
+
IIIIIIJJJJJJ
";

    #[test]
    fn test_reader() {
        let reader = Reader::new(FASTQ_FILE);
        let records: Vec<io::Result<Record>> = reader.records().collect();
        assert!(records.len() == 1);
        for res in records {
            let record = res.ok().unwrap();
            assert_eq!(record.check(), Ok(()));
            assert_eq!(record.id(), Some("id"));
            assert_eq!(record.desc(), Some("desc"));
            assert_eq!(record.seq(), b"ACCGTAGGCTGA");
            assert_eq!(record.qual(), b"IIIIIIJJJJJJ");
        }
    }

    #[test]
    fn test_writer() {
        let mut writer = Writer::new(Vec::new());
        writer.write("id", Some("desc"), b"ACCGTAGGCTGA", b"IIIIIIJJJJJJ")
              .ok()
              .expect("Expected successful write");
        writer.flush().ok().expect("Expected successful write");
        assert_eq!(writer.writer.get_ref(), &FASTQ_FILE);
    }
}
<commit_msg>make FASTQ Record derive a few useful things<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! FastQ reading and writing.
//!
//! # Example
//!
//! ```
//! use std::io;
//! use bio::io::fastq;
//! let reader = fastq::Reader::new(io::stdin());
//! ```

use std::io;
use std::io::prelude::*;
use std::ascii::AsciiExt;
use std::fs;
use std::fmt;
use std::path::Path;
use std::convert::AsRef;

/// A FastQ reader.
pub struct Reader<R: io::Read> {
    reader: io::BufReader<R>,
    sep_line: String,
}

impl Reader<fs::File> {
    /// Read from a given file.
    pub fn from_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        fs::File::open(path).map(Reader::new)
    }
}

impl<R: io::Read> Reader<R> {
    /// Read from a given `io::Read`.
    pub fn new(reader: R) -> Self {
        Reader {
            reader: io::BufReader::new(reader),
            sep_line: String::new(),
        }
    }

    /// Read into a given record.
    /// Returns an error if the record in incomplete or syntax is violated.
    /// The content of the record can be checked via the record object.
    pub fn read(&mut self, record: &mut Record) -> io::Result<()> {
        record.clear();
        try!(self.reader.read_line(&mut record.header));

        if !record.header.is_empty() {
            if !record.header.starts_with('@') {
                return Err(io::Error::new(io::ErrorKind::Other, "Expected @ at record start."));
            }
            try!(self.reader.read_line(&mut record.seq));
            try!(self.reader.read_line(&mut self.sep_line));
            try!(self.reader.read_line(&mut record.qual));
            if record.qual.is_empty() {
                return Err(io::Error::new(io::ErrorKind::Other,
                                          "Incomplete record. Each FastQ record has to consist \
                                           of 4 lines: header, sequence, separator and qualities."));
            }
        }

        Ok(())
    }

    /// Return an iterator over the records of this FastQ file.
    pub fn records(self) -> Records<R> {
        Records { reader: self }
    }
}

/// A FastQ record.
#[derive(Debug, Clone, PartialEq)]
pub struct Record {
    header: String,
    seq: String,
    qual: String,
}

impl Record {
    /// Create a new, empty FastQ record.
    pub fn new() -> Self {
        Record {
            header: String::new(),
            seq: String::new(),
            qual: String::new(),
        }
    }

    /// Check if record is empty.
    pub fn is_empty(&self) -> bool {
        self.header.is_empty() && self.seq.is_empty() && self.qual.is_empty()
    }

    /// Check validity of FastQ record.
    pub fn check(&self) -> Result<(), &str> {
        if self.id().is_none() {
            return Err("Expecting id for FastQ record.");
        }
        if !self.seq.is_ascii() {
            return Err("Non-ascii character found in sequence.");
        }
        if !self.qual.is_ascii() {
            return Err("Non-ascii character found in qualities.");
        }
        if self.seq().len() != self.qual().len() {
            return Err("Unequal length of sequence an qualities.");
        }

        Ok(())
    }

    /// Return the id of the record.
    pub fn id(&self) -> Option<&str> {
        self.header[1..].trim_right().splitn(2, ' ').next()
    }

    /// Return descriptions if present.
    pub fn desc(&self) -> Option<&str> {
        self.header[1..].trim_right().splitn(2, ' ').skip(1).next()
    }

    /// Return the sequence of the record.
    pub fn seq(&self) -> &[u8] {
        self.seq.trim_right().as_bytes()
    }

    /// Return the base qualities of the record.
    pub fn qual(&self) -> &[u8] {
        self.qual.trim_right().as_bytes()
    }

    /// Clear the record.
    fn clear(&mut self) {
        self.header.clear();
        self.seq.clear();
        self.qual.clear();
    }
}

impl fmt::Display for Record {
	fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
		write!(f, "@{}\n{}\n+\n{}", self.header, self.seq, self.qual)
	}
}

/// An iterator over the records of a FastQ file.
pub struct Records<R: io::Read> {
    reader: Reader<R>,
}

impl<R: io::Read> Iterator for Records<R> {
    type Item = io::Result<Record>;

    fn next(&mut self) -> Option<io::Result<Record>> {
        let mut record = Record::new();
        match self.reader.read(&mut record) {
            Ok(()) if record.is_empty() => None,
            Ok(()) => Some(Ok(record)),
            Err(err) => Some(Err(err)),
        }
    }
}

/// A FastQ writer.
pub struct Writer<W: io::Write> {
    writer: io::BufWriter<W>,
}

impl Writer<fs::File> {
    /// Write to a given file path.
    pub fn to_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        fs::File::create(path).map(Writer::new)
    }
}

impl<W: io::Write> Writer<W> {
    /// Write to a given `io::Write`.
    pub fn new(writer: W) -> Self {
        Writer { writer: io::BufWriter::new(writer) }
    }

    /// Directly write a FastQ record.
    pub fn write_record(&mut self, record: Record) -> io::Result<()> {
        self.write(record.id().unwrap_or(""),
                   record.desc(),
                   record.seq(),
                   record.qual())
    }

    /// Write a FastQ record with given id, optional description, sequence and qualities.
    pub fn write(&mut self,
                 id: &str,
                 desc: Option<&str>,
                 seq: &[u8],
                 qual: &[u8])
                 -> io::Result<()> {
        try!(self.writer.write(b"@"));
        try!(self.writer.write(id.as_bytes()));
        if desc.is_some() {
            try!(self.writer.write(b" "));
            try!(self.writer.write(desc.unwrap().as_bytes()));
        }
        try!(self.writer.write(b"\n"));
        try!(self.writer.write(seq));
        try!(self.writer.write(b"\n+\n"));
        try!(self.writer.write(qual));
        try!(self.writer.write(b"\n"));

        Ok(())
    }

    /// Flush the writer, ensuring that everything is written.
    pub fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }
}

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

    const FASTQ_FILE: &'static [u8] = b"@id desc
ACCGTAGGCTGA
+
IIIIIIJJJJJJ
";

    #[test]
    fn test_reader() {
        let reader = Reader::new(FASTQ_FILE);
        let records: Vec<io::Result<Record>> = reader.records().collect();
        assert!(records.len() == 1);
        for res in records {
            let record = res.ok().unwrap();
            assert_eq!(record.check(), Ok(()));
            assert_eq!(record.id(), Some("id"));
            assert_eq!(record.desc(), Some("desc"));
            assert_eq!(record.seq(), b"ACCGTAGGCTGA");
            assert_eq!(record.qual(), b"IIIIIIJJJJJJ");
        }
    }

    #[test]
    fn test_writer() {
        let mut writer = Writer::new(Vec::new());
        writer.write("id", Some("desc"), b"ACCGTAGGCTGA", b"IIIIIIJJJJJJ")
              .ok()
              .expect("Expected successful write");
        writer.flush().ok().expect("Expected successful write");
        assert_eq!(writer.writer.get_ref(), &FASTQ_FILE);
    }
}
<|endoftext|>


<commit_before>use std::ffi::{CString, self};
use std::mem;
use std::str;
use libc::c_char;

use objc::{encode, Encode, Id};

use {INSCopying, INSObject};

pub trait INSValue : INSObject {
    type Value: Copy + Encode;

    fn value(&self) -> Self::Value {
        assert!(self.encoding() == encode::<Self::Value>());
        unsafe {
            let mut value = mem::uninitialized::<Self::Value>();
            let _: () = msg_send![self, getValue:&mut value];
            value
        }
    }

    fn encoding(&self) -> &str {
        unsafe {
            let result: *const c_char = msg_send![self, objCType];
            let bytes = ffi::c_str_to_bytes(&result);
            let s = str::from_utf8(bytes).unwrap();
            mem::transmute(s)
        }
    }

    fn from_value(value: Self::Value) -> Id<Self> {
        let cls = <Self as INSObject>::class();
        let encoding = CString::from_slice(encode::<Self::Value>().as_bytes());
        unsafe {
            let obj: *mut Self = msg_send![cls, alloc];
            let obj: *mut Self = msg_send![obj, initWithBytes:&value
                                                     objCType:encoding.as_ptr()];
            Id::from_retained_ptr(obj)
        }
    }
}

object_struct!(NSValue<T>);

impl<T> INSValue for NSValue<T> where T: Copy + Encode {
    type Value = T;
}

impl<T> INSCopying for NSValue<T> {
    type Output = NSValue<T>;
}

#[cfg(test)]
mod tests {
    use objc::{encode, Id};
    use {INSValue, NSValue};

    #[test]
    fn test_value() {
        let val: Id<NSValue<u32>> = INSValue::from_value(13);
        assert!(val.value() == 13);
        assert!(val.encoding() == encode::<u32>());
    }
}
<commit_msg>Put a static bound on NSValue's value.<commit_after>use std::ffi::{CString, self};
use std::mem;
use std::str;
use libc::c_char;

use objc::{encode, Encode, Id};

use {INSCopying, INSObject};

pub trait INSValue : INSObject {
    type Value: 'static + Copy + Encode;

    fn value(&self) -> Self::Value {
        assert!(self.encoding() == encode::<Self::Value>());
        unsafe {
            let mut value = mem::uninitialized::<Self::Value>();
            let _: () = msg_send![self, getValue:&mut value];
            value
        }
    }

    fn encoding(&self) -> &str {
        unsafe {
            let result: *const c_char = msg_send![self, objCType];
            let bytes = ffi::c_str_to_bytes(&result);
            let s = str::from_utf8(bytes).unwrap();
            mem::transmute(s)
        }
    }

    fn from_value(value: Self::Value) -> Id<Self> {
        let cls = <Self as INSObject>::class();
        let encoding = CString::from_slice(encode::<Self::Value>().as_bytes());
        unsafe {
            let obj: *mut Self = msg_send![cls, alloc];
            let obj: *mut Self = msg_send![obj, initWithBytes:&value
                                                     objCType:encoding.as_ptr()];
            Id::from_retained_ptr(obj)
        }
    }
}

object_struct!(NSValue<T>);

impl<T> INSValue for NSValue<T> where T: 'static + Copy + Encode {
    type Value = T;
}

impl<T> INSCopying for NSValue<T> {
    type Output = NSValue<T>;
}

#[cfg(test)]
mod tests {
    use objc::{encode, Id};
    use {INSValue, NSValue};

    #[test]
    fn test_value() {
        let val: Id<NSValue<u32>> = INSValue::from_value(13);
        assert!(val.value() == 13);
        assert!(val.encoding() == encode::<u32>());
    }
}
<|endoftext|>


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

extern crate prost_build;

fn main() {
    let file_paths = [
        "oak_functions/proto/abi.proto",
        "oak_functions/proto/lookup_data.proto",
    ];
    prost_build::compile_protos(&file_paths, &[env!("WORKSPACE_ROOT")])
        .expect("Proto compilation failed");

    // Tell cargo to rerun this build script if the proto file has changed.
    // https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorerun-if-changedpath
    for proto_path in file_paths.iter() {
        let file_path = std::path::Path::new(proto_path);
        println!("cargo:rerun-if-changed=../../{}", file_path.display());
    }
}
<commit_msg>Avoid recompiling oak_functions_abi crate (#3393)<commit_after>//
// Copyright 2021 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

extern crate prost_build;

fn main() {
    let file_paths = [
        "oak_functions/proto/abi.proto",
        "oak_functions/proto/lookup_data.proto",
    ];
    prost_build::compile_protos(&file_paths, &[env!("WORKSPACE_ROOT")])
        .expect("Proto compilation failed");

    // Tell cargo to rerun this build script if the proto file has changed.
    // https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorerun-if-changedpath
    for proto_path in file_paths.iter() {
        let file_path = std::path::Path::new(proto_path);
        println!(
            "cargo:rerun-if-changed={}{}",
            env!("WORKSPACE_ROOT"),
            file_path.display()
        );
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use parking_lot::RwLock;
use elements::Module;
use interpreter::Error;
use interpreter::env::env_module;
use interpreter::module::{ModuleInstance, ModuleInstanceInterface};

/// Program instance. Program is a set of instantiated modules.
pub struct ProgramInstance {
	/// Shared data reference.
	essence: Arc<ProgramInstanceEssence>,
}

/// Program instance essence.
pub struct ProgramInstanceEssence {
	/// Loaded modules.
	modules: RwLock<HashMap<String, Arc<ModuleInstanceInterface>>>,
}

impl ProgramInstance {
	/// Create new program instance.
	pub fn new() -> Result<Self, Error> {
		Ok(ProgramInstance {
			essence: Arc::new(ProgramInstanceEssence::new()?),
		})
	}

	/// Instantiate module.
	pub fn add_module(&self, name: &str, module: Module) -> Result<Arc<ModuleInstance>, Error> {
		let module_instance = Arc::new(ModuleInstance::new(Arc::downgrade(&self.essence), module)?);
		let mut modules = self.essence.modules.write();
		match modules.entry(name.into()) {
			Entry::Occupied(_) => Err(Error::Program(format!("module {} already instantiated", name))),
			Entry::Vacant(entry) => {
				entry.insert(module_instance.clone());
				Ok(module_instance)
			},
		}
	}
}

impl ProgramInstanceEssence {
	/// Create new program essence.
	pub fn new() -> Result<Self, Error> {
		let mut modules = HashMap::new();
		let env_module: Arc<ModuleInstanceInterface> = Arc::new(env_module()?);
		modules.insert("env".into(), env_module);
		Ok(ProgramInstanceEssence {
			modules: RwLock::new(modules),
		})
	}

	/// Get module reference.
	pub fn module(&self, name: &str) -> Option<Arc<ModuleInstanceInterface>> {
		self.modules.read().get(name).cloned()
	}
}
<commit_msg>add module resolving to program instance<commit_after>use std::sync::Arc;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use parking_lot::RwLock;
use elements::Module;
use interpreter::Error;
use interpreter::env::env_module;
use interpreter::module::{ModuleInstance, ModuleInstanceInterface};

/// Program instance. Program is a set of instantiated modules.
pub struct ProgramInstance {
	/// Shared data reference.
	essence: Arc<ProgramInstanceEssence>,
}

/// Program instance essence.
pub struct ProgramInstanceEssence {
	/// Loaded modules.
	modules: RwLock<HashMap<String, Arc<ModuleInstanceInterface>>>,
}

impl ProgramInstance {
	/// Create new program instance.
	pub fn new() -> Result<Self, Error> {
		Ok(ProgramInstance {
			essence: Arc::new(ProgramInstanceEssence::new()?),
		})
	}

	/// Instantiate module.
	pub fn add_module(&self, name: &str, module: Module) -> Result<Arc<ModuleInstance>, Error> {
		let module_instance = Arc::new(ModuleInstance::new(Arc::downgrade(&self.essence), module)?);
		let mut modules = self.essence.modules.write();
		match modules.entry(name.into()) {
			Entry::Occupied(_) => Err(Error::Program(format!("module {} already instantiated", name))),
			Entry::Vacant(entry) => {
				entry.insert(module_instance.clone());
				Ok(module_instance)
			},
		}
	}

	/// Get one of the modules by name
	pub fn module(&self, name: &str) -> Option<Arc<ModuleInstanceInterface>> {
		self.essence.module(name)
	}
}

impl ProgramInstanceEssence {
	/// Create new program essence.
	pub fn new() -> Result<Self, Error> {
		let mut modules = HashMap::new();
		let env_module: Arc<ModuleInstanceInterface> = Arc::new(env_module()?);
		modules.insert("env".into(), env_module);
		Ok(ProgramInstanceEssence {
			modules: RwLock::new(modules),
		})
	}

	/// Get module reference.
	pub fn module(&self, name: &str) -> Option<Arc<ModuleInstanceInterface>> {
		self.modules.read().get(name).cloned()
	}
}
<|endoftext|>


<commit_before>use color::{Colorf32, Color888};

/// Document is a sequence of nodes concatenated together.
#[derive(Debug)]
pub struct Document(pub Vec<Node>);

#[derive(Debug)]
pub enum Node {
    /// Pure text.
    Text(String),
    /// Set foreground color for the child document.
    Foreground(Colorf32, Document),
    /// Set background color for the child document.
    Background(Colorf32, Document),
    /// Bold the child document.
    Bold(Document),
    /// `Widget(name, args)` calls the widget named `name` with `args`.
    Widget(String, Vec<String>),
}

impl From<Vec<Node>> for Document {
    fn from(nodes: Vec<Node>) -> Self {
        Document(nodes)
    }
}

mod grammar {
    include!(concat!(env!("OUT_DIR"), "/grammar.rs"));
}

/// Parse `input` string into a `Document`.
pub fn parse(input: &str) -> Result<Document, String> {
    grammar::document(input).map_err(|e| e.to_string())
}

/// Parse `input` string into a `Document`. A `Document` is a
/// sequence of `Node`s. Take the first `Node` and discard all
/// the rest.
pub fn parse_for_first_node(input: &str) -> Result<Node, String> {
    parse(input).and_then(|doc| {
        doc.0
            .into_iter()
            .next()
            .ok_or("not a single node".into())
    })
}

/// Parse `input` string into a `Color888`.
/// `input` should be in `rrggbb` format, all in lowercase.
pub fn parse_color(input: &str) -> Result<Color888, String> {
    grammar::color(input).map_err(|e| e.to_string())
}

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

    #[test]
    fn test() {
        println!("{:?}", parse("f{f1\\[  }234(123456: a<sd|h|>el\\)lo) \\("));
        println!("{:?}", parse("f{f1\\[\\}234(123456: a<sd|h|>el\\)lo) \\("));
    }
}

<commit_msg>fastup: + escape_for_text to remove magic of the input<commit_after>use color::{Colorf32, Color888};

/// Document is a sequence of nodes concatenated together.
#[derive(Debug)]
pub struct Document(pub Vec<Node>);

#[derive(Debug)]
pub enum Node {
    /// Pure text.
    Text(String),
    /// Set foreground color for the child document.
    Foreground(Colorf32, Document),
    /// Set background color for the child document.
    Background(Colorf32, Document),
    /// Bold the child document.
    Bold(Document),
    /// `Widget(name, args)` calls the widget named `name` with `args`.
    Widget(String, Vec<String>),
}

impl From<Vec<Node>> for Document {
    fn from(nodes: Vec<Node>) -> Self {
        Document(nodes)
    }
}

mod grammar {
    include!(concat!(env!("OUT_DIR"), "/grammar.rs"));
}

/// Parse `input` string into a `Document`.
pub fn parse(input: &str) -> Result<Document, String> {
    grammar::document(input).map_err(|e| e.to_string())
}

/// Parse `input` string into a `Document`. A `Document` is a
/// sequence of `Node`s. Take the first `Node` and discard all
/// the rest.
pub fn parse_for_first_node(input: &str) -> Result<Node, String> {
    parse(input).and_then(|doc| {
        doc.0
            .into_iter()
            .next()
            .ok_or("not a single node".into())
    })
}

/// Parse `input` string into a `Color888`.
/// `input` should be in `rrggbb` format, all in lowercase.
pub fn parse_color(input: &str) -> Result<Color888, String> {
    grammar::color(input).map_err(|e| e.to_string())
}

/// Escape `input` so that it will only generate `Text` node,
/// removing magic in the `input` string.
pub fn escape_for_text(input: &str) -> String {
    input.chars().map(escape_char_for_text).collect()
}

fn escape_char_for_text(ch: char) -> String {
    match ch {
        '<' | '>' | '(' | ')' | '[' | ']' | '{' | '}' | '\\' | '|' => {
            let mut s = '\\'.to_string();
            s.push(ch);
            s
        }
        _ => ch.to_string(),
    }
}

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

    #[test]
    fn test() {
        println!("{:?}", parse("f{f1\\[  }234(123456: a<sd|h|>el\\)lo) \\("));
        println!("{:?}", parse("f{f1\\[\\}234(123456: a<sd|h|>el\\)lo) \\("));
    }

    #[test]
    fn escape() {
        let escaped = escape_for_text("hello <([{\\|}])> world");
        let should_be = "hello \\<\\(\\[\\{\\\\\\|\\}\\]\\)\\> world";
        assert_eq!(escaped, should_be);
    }
}

<|endoftext|>


<commit_before>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use escape::escape_html;
use token::Token;
use book::{Book, Number};
use error::{Error,Result};

use mustache;

/// Renderer for HTML
///
/// Also used by Epub.
pub struct HtmlRenderer<'a> {
    current_chapter: i32,
    book: &'a Book,
    current_numbering: bool,
    current_hide: bool,
}

impl<'a> HtmlRenderer<'a> {
    /// Creates a new HTML renderer
    pub fn new(book: &'a Book) -> HtmlRenderer<'a> {
        HtmlRenderer {
            book: book,
            current_chapter: 1,
            current_numbering: book.numbering,
            current_hide: false
        }
    }

    /// Render books as a standalone HTML file
    pub fn render_book(&mut self) -> Result<String> {
        let mut content = String::new();

        for &(n, ref v) in &self.book.chapters {
            self.current_hide = false;
            match n {
                Number::Unnumbered => self.current_numbering = false,
                Number::Default => self.current_numbering = self.book.numbering,
                Number::Specified(n) => {
                    self.current_numbering = self.book.numbering;
                    self.current_chapter = n;
                },
                Number::Hidden => {
                    self.current_numbering = false;
                    self.current_hide = true;
                },
            }
            for token in v {
                content.push_str(&self.parse_token(token));
            }
        }

        let template = mustache::compile_str(try!(self.book.get_template("html_template")).as_ref());
        let data = self.book.get_mapbuilder("none")
            .insert_str("content", content)
            .insert_str("style",
                        &try!(self.book.get_template("html_css")))
            .build();

        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML was not utf-8 valid")),
            Ok(res) => Ok(res)
        }
    }

    /// Transform a vector of `Token`s to HTML format.
    pub fn render_vec(&mut self, tokens: &[Token]) -> String {
        let mut res = String::new();

        for token in tokens {
            res.push_str(&self.parse_token(&token));
        }
        res
    }

    /// Parse a single token.
    pub fn parse_token(&mut self, token: &Token) -> String {
        match *token {
            Token::Str(ref text) => escape_html(&*text),
            Token::Paragraph(ref vec) => format!("
{}
\n", self.render_vec(vec)),
            Token::Header(n, ref vec) => {
                if n == 1 && self.current_hide {
                    return String::new();
                }
                let s = if n == 1 && self.current_numbering {
                    let chapter = self.current_chapter;
                    self.current_chapter += 1;
                    self.book.get_header(chapter, &self.render_vec(vec)).unwrap()
                } else {
                    self.render_vec(vec)
                };
                format!("<h{}>{}</h{}>\n", n, escape_html(&s), n)
            },
            Token::Emphasis(ref vec) => format!("{}", self.render_vec(vec)),
            Token::Strong(ref vec) => format!("{}", self.render_vec(vec)),
            Token::Code(ref vec) => format!("{}", self.render_vec(vec)),
            Token::BlockQuote(ref vec) => format!("
{}
\n", self.render_vec(vec)),
            Token::CodeBlock(ref language, ref vec) => {
                let s = self.render_vec(vec);
                if language.is_empty() {
                    format!("
{}
\n", s)
                } else {
                    format!("
{}
\n", language, s)
                }
            },
            Token::Rule => String::from("
***
\n"),
            Token::SoftBreak => String::from(" "),
            Token::HardBreak => String::from("
\n"),
            Token::List(ref vec) => format!("
\n{}
\n", self.render_vec(vec)),
            Token::OrderedList(n, ref vec) => format!("
\n{}
\n",
                                                      if n != 1 {
                                                          format!(" start = \"{}\"", n)
                                                      } else {
                                                          String::new()
                                                      },
                                                      self.render_vec(vec)),
            Token::Item(ref vec) => format!("
{}
\n", self.render_vec(vec)),
            Token::Link(ref url, ref title, ref vec) => format!("{}",
                                                    url,
                                                    if title.is_empty() {
                                                        String::new()
                                                    } else {
                                                        format!(" title = \"{}\"", title)
                                                    },
                                                    self.render_vec(vec)),
            Token::Image(ref url, ref title, ref alt) => format!("",
                                                     url,
                                                     title,
                                                     self.render_vec(alt))

        }
    }
}

<commit_msg>html: fixed escaping html issue<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use escape::escape_html;
use token::Token;
use book::{Book, Number};
use error::{Error,Result};

use mustache;

/// Renderer for HTML
///
/// Also used by Epub.
pub struct HtmlRenderer<'a> {
    current_chapter: i32,
    book: &'a Book,
    current_numbering: bool,
    current_hide: bool,
}

impl<'a> HtmlRenderer<'a> {
    /// Creates a new HTML renderer
    pub fn new(book: &'a Book) -> HtmlRenderer<'a> {
        HtmlRenderer {
            book: book,
            current_chapter: 1,
            current_numbering: book.numbering,
            current_hide: false
        }
    }

    /// Render books as a standalone HTML file
    pub fn render_book(&mut self) -> Result<String> {
        let mut content = String::new();

        for &(n, ref v) in &self.book.chapters {
            self.current_hide = false;
            match n {
                Number::Unnumbered => self.current_numbering = false,
                Number::Default => self.current_numbering = self.book.numbering,
                Number::Specified(n) => {
                    self.current_numbering = self.book.numbering;
                    self.current_chapter = n;
                },
                Number::Hidden => {
                    self.current_numbering = false;
                    self.current_hide = true;
                },
            }
            for token in v {
                content.push_str(&self.parse_token(token));
            }
        }

        let template = mustache::compile_str(try!(self.book.get_template("html_template")).as_ref());
        let data = self.book.get_mapbuilder("none")
            .insert_str("content", content)
            .insert_str("style",
                        &try!(self.book.get_template("html_css")))
            .build();

        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML was not utf-8 valid")),
            Ok(res) => Ok(res)
        }
    }

    /// Transform a vector of `Token`s to HTML format.
    pub fn render_vec(&mut self, tokens: &[Token]) -> String {
        let mut res = String::new();

        for token in tokens {
            res.push_str(&self.parse_token(&token));
        }
        res
    }

    /// Parse a single token.
    pub fn parse_token(&mut self, token: &Token) -> String {
        match *token {
            Token::Str(ref text) => escape_html(&*text),
            Token::Paragraph(ref vec) => format!("
{}
\n", self.render_vec(vec)),
            Token::Header(n, ref vec) => {
                if n == 1 && self.current_hide {
                    return String::new();
                }
                let s = if n == 1 && self.current_numbering {
                    let chapter = self.current_chapter;
                    self.current_chapter += 1;
                    self.book.get_header(chapter, &self.render_vec(vec)).unwrap()
                } else {
                    self.render_vec(vec)
                };
                format!("<h{}>{}</h{}>\n", n, s, n)
            },
            Token::Emphasis(ref vec) => format!("{}", self.render_vec(vec)),
            Token::Strong(ref vec) => format!("{}", self.render_vec(vec)),
            Token::Code(ref vec) => format!("{}", self.render_vec(vec)),
            Token::BlockQuote(ref vec) => format!("
{}
\n", self.render_vec(vec)),
            Token::CodeBlock(ref language, ref vec) => {
                let s = self.render_vec(vec);
                if language.is_empty() {
                    format!("
{}
\n", s)
                } else {
                    format!("
{}
\n", language, s)
                }
            },
            Token::Rule => String::from("
***
\n"),
            Token::SoftBreak => String::from(" "),
            Token::HardBreak => String::from("
\n"),
            Token::List(ref vec) => format!("
\n{}
\n", self.render_vec(vec)),
            Token::OrderedList(n, ref vec) => format!("
\n{}
\n",
                                                      if n != 1 {
                                                          format!(" start = \"{}\"", n)
                                                      } else {
                                                          String::new()
                                                      },
                                                      self.render_vec(vec)),
            Token::Item(ref vec) => format!("
{}
\n", self.render_vec(vec)),
            Token::Link(ref url, ref title, ref vec) => format!("{}",
                                                    url,
                                                    if title.is_empty() {
                                                        String::new()
                                                    } else {
                                                        format!(" title = \"{}\"", title)
                                                    },
                                                    self.render_vec(vec)),
            Token::Image(ref url, ref title, ref alt) => format!("",
                                                     url,
                                                     title,
                                                     self.render_vec(alt))

        }
    }
}

<|endoftext|>