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

/// Implements the [Categorical](https://en.wikipedia.org/wiki/Categorical_distribution)
/// distribution, also known as the generalized Bernoulli or discrete distribution
///
/// # Examples
///
/// ```
/// use statrs::distribution::{Categorical, Discrete};
/// use statrs::statistics::Mode;
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Categorical {
    norm_pmf: Vec<f64>,
    cdf: Vec<f64>,
}

impl Categorical {
    pub fn new(prob_mass: &[f64]) -> Result<Categorical> {
        if !is_valid_prob_mass(prob_mass) {
            Err(StatsError::BadParams)
        } else {
            // extract un-normalized cdf
            let mut cdf = vec![0.0; prob_mass.len()];
            cdf[0] = prob_mass[0];
            for i in 1..prob_mass.len() {
                unsafe {
                    let val = cdf.get_unchecked(i - 1) + prob_mass.get_unchecked(i);
                    let elem = cdf.get_unchecked_mut(i);
                    *elem = val;
                }
            }

            // extract normalized probability mass
            let sum = cdf[cdf.len() - 1];
            let mut norm_pmf = vec![0.0; prob_mass.len()];
            for i in 0..prob_mass.len() {
                unsafe {
                    let elem = norm_pmf.get_unchecked_mut(i);
                    *elem = prob_mass.get_unchecked(i) / sum;
                }
            }
            Ok(Categorical {
                norm_pmf: norm_pmf,
                cdf: cdf,
            })
        }
    }

    fn cdf_max(&self) -> f64 {
        *unsafe { self.cdf.get_unchecked(self.cdf.len() - 1) }
    }
}

impl Sample<f64> for Categorical {
    /// Generate a random sample from a categorical
    /// 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 Categorical {
    /// Generate a random independent sample from a categorical
    /// 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 Categorical {
    /// Generate a random sample from the categorical distribution
    /// using `r` as the source of randomness
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    /// use rand::StdRng;
    /// use statrs::distribution::{Categorical, Distribution};
    ///
    /// # fn main() {
    /// let mut r = rand::StdRng::new().unwrap();
    /// let n = Categorical::new(&[1.0, 2.0, 3.0]).unwrap();
    /// print!("{}", n.sample::<StdRng>(&mut r));
    /// # }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        let draw = r.next_f64() * self.cdf_max();
        let mut idx = 0;

        if draw == 0.0 {
            // skip zero-probability categories
            let mut el = unsafe { self.cdf.get_unchecked(idx) };
            while *el == 0.0 {
                // don't need bounds checking because we do not allow
                // creating Categorical distributions with all 0.0 probs
                idx += 1;
                el = unsafe { self.cdf.get_unchecked(idx) }
            }
        }
        let mut el = unsafe { self.cdf.get_unchecked(idx) };
        while draw > *el {
            idx += 1;
            el = unsafe { self.cdf.get_unchecked(idx) };
        }
        return idx as f64;
    }
}

impl Univariate<u64, f64> for Categorical {
    /// Calculates the cumulative distribution function for the categorical
    /// distribution at `x`
    ///
    /// # Panics
    ///
    /// If `x < 0.0` or `x > k` where `k` is the number of categories
    /// (i.e. the length of the `prob_mass` slice passed to the constructor)
    ///
    /// # Formula
    ///
    /// ```ignore
    /// sum(p_j) from 0..x
    /// ```
    ///
    /// where `p_j` is the probability mass for the `j`th category
    fn cdf(&self, x: f64) -> f64 {
        assert!(x >= 0.0 && x <= self.cdf.len() as f64,
                format!("{}",
                        StatsError::ArgIntervalIncl("x", 0.0, self.cdf.len() as f64)));
        if x == self.cdf.len() as f64 {
            1.0
        } else {
            unsafe { self.cdf.get_unchecked(x as usize) / self.cdf_max() }
        }
    }
}

impl Min<u64> for Categorical {
    /// Returns the minimum value in the domain of the
    /// categorical distribution representable by a 64-bit
    /// integer
    ///
    /// # Formula
    ///
    /// ```ignore
    /// 0
    /// ```
    fn min(&self) -> u64 {
        0
    }
}

impl Max<u64> for Categorical {
    /// Returns the maximum value in the domain of the
    /// categorical distribution representable by a 64-bit
    /// integer
    ///
    /// # Formula
    ///
    /// ```ignore
    /// n
    /// ```
    fn max(&self) -> u64 {
        self.cdf.len() as u64 - 1
    }
}

// determines if `p` is a valid probability mass array
// for the Categorical distribution
fn is_valid_prob_mass(p: &[f64]) -> bool {
    !p.iter().any(|&x| x < 0.0 || x.is_nan()) && !p.iter().all(|&x| x == 0.0)
}

#[test]
fn test_is_valid_prob_mass() {
    let invalid = [1.0, f64::NAN, 3.0];
    assert!(!is_valid_prob_mass(&invalid));
    let invalid2 = [-2.0, 5.0, 1.0, 6.2];
    assert!(!is_valid_prob_mass(&invalid2));
    let invalid3 = [0.0, 0.0, 0.0];
    assert!(!is_valid_prob_mass(&invalid3));
    let invalid4: [f64; 0] = [];
    assert!(!is_valid_prob_mass(&invalid4));
    let valid = [5.2, 0.00001, 1e-15, 1000000.12];
    assert!(is_valid_prob_mass(&valid));
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[cfg(test)]
mod test {
    use std::fmt::Debug;
    use statistics::*;
    use distribution::{Univariate, Categorical};

    fn try_create(prob_mass: &[f64]) -> Categorical {
        let n = Categorical::new(prob_mass);
        assert!(n.is_ok());
        n.unwrap()
    }

    fn create_case(prob_mass: &[f64]) {
        try_create(prob_mass);
    }

    fn bad_create_case(prob_mass: &[f64]) {
        let n = Categorical::new(prob_mass);
        assert!(n.is_err());
    }

    fn test_case<T, F>(prob_mass: &[f64], expected: T, eval: F)
        where T: PartialEq + Debug,
              F: Fn(Categorical) -> T
    {
        let n = try_create(prob_mass);
        let x = eval(n);
        assert_eq!(expected, x);
    }

    #[test]
    fn test_create() {
        create_case(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]);
    }

    #[test]
    fn test_bad_create() {
        bad_create_case(&[-1.0, 1.0]);
        bad_create_case(&[0.0, 0.0]);
    }

    #[test]
    fn test_min_max() {
        test_case(&[4.0, 2.5, 2.5, 1.0], 0, |x| x.min());
        test_case(&[4.0, 2.5, 2.5, 1.0], 3, |x| x.max());
    }

    #[test]
    fn test_cdf() {
        test_case(&[0.0, 3.0, 1.0, 1.0], 3.0 / 5.0, |x| x.cdf(1.5));
        test_case(&[1.0, 1.0, 1.0, 1.0], 0.25, |x| x.cdf(0.0));
        test_case(&[4.0, 2.5, 2.5, 1.0], 0.4, |x| x.cdf(0.8));
        test_case(&[4.0, 2.5, 2.5, 1.0], 1.0, |x| x.cdf(3.2));
        test_case(&[4.0, 2.5, 2.5, 1.0], 1.0, |x| x.cdf(4.0));
    }

    #[test]
    #[should_panic]
    fn test_cdf_input_low() {
        test_case(&[4.0, 2.5, 2.5, 1.0], 1.0, |x| x.cdf(-1.0));
    }

    #[test]
    #[should_panic]
    fn test_cdf_input_high() {
        test_case(&[4.0, 2.5, 2.5, 1.0], 1.0, |x| x.cdf(4.5));
    }
}<commit_msg>feat: impl categorical mean<commit_after>use std::f64;
use rand::Rng;
use rand::distributions::{Sample, IndependentSample};
use statistics::*;
use distribution::{Univariate, Discrete, Distribution};
use {Result, StatsError};

/// Implements the [Categorical](https://en.wikipedia.org/wiki/Categorical_distribution)
/// distribution, also known as the generalized Bernoulli or discrete distribution
///
/// # Examples
///
/// ```
/// use statrs::distribution::{Categorical, Discrete};
/// use statrs::statistics::Mode;
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Categorical {
    norm_pmf: Vec<f64>,
    cdf: Vec<f64>,
}

impl Categorical {
    pub fn new(prob_mass: &[f64]) -> Result<Categorical> {
        if !is_valid_prob_mass(prob_mass) {
            Err(StatsError::BadParams)
        } else {
            // extract un-normalized cdf
            let mut cdf = vec![0.0; prob_mass.len()];
            cdf[0] = prob_mass[0];
            for i in 1..prob_mass.len() {
                unsafe {
                    let val = cdf.get_unchecked(i - 1) + prob_mass.get_unchecked(i);
                    let elem = cdf.get_unchecked_mut(i);
                    *elem = val;
                }
            }

            // extract normalized probability mass
            let sum = cdf[cdf.len() - 1];
            let mut norm_pmf = vec![0.0; prob_mass.len()];
            for i in 0..prob_mass.len() {
                unsafe {
                    let elem = norm_pmf.get_unchecked_mut(i);
                    *elem = prob_mass.get_unchecked(i) / sum;
                }
            }
            Ok(Categorical {
                norm_pmf: norm_pmf,
                cdf: cdf,
            })
        }
    }

    fn cdf_max(&self) -> f64 {
        *unsafe { self.cdf.get_unchecked(self.cdf.len() - 1) }
    }
}

impl Sample<f64> for Categorical {
    /// Generate a random sample from a categorical
    /// 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 Categorical {
    /// Generate a random independent sample from a categorical
    /// 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 Categorical {
    /// Generate a random sample from the categorical distribution
    /// using `r` as the source of randomness
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    /// use rand::StdRng;
    /// use statrs::distribution::{Categorical, Distribution};
    ///
    /// # fn main() {
    /// let mut r = rand::StdRng::new().unwrap();
    /// let n = Categorical::new(&[1.0, 2.0, 3.0]).unwrap();
    /// print!("{}", n.sample::<StdRng>(&mut r));
    /// # }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        let draw = r.next_f64() * self.cdf_max();
        let mut idx = 0;

        if draw == 0.0 {
            // skip zero-probability categories
            let mut el = unsafe { self.cdf.get_unchecked(idx) };
            while *el == 0.0 {
                // don't need bounds checking because we do not allow
                // creating Categorical distributions with all 0.0 probs
                idx += 1;
                el = unsafe { self.cdf.get_unchecked(idx) }
            }
        }
        let mut el = unsafe { self.cdf.get_unchecked(idx) };
        while draw > *el {
            idx += 1;
            el = unsafe { self.cdf.get_unchecked(idx) };
        }
        return idx as f64;
    }
}

impl Univariate<u64, f64> for Categorical {
    /// Calculates the cumulative distribution function for the categorical
    /// distribution at `x`
    ///
    /// # Panics
    ///
    /// If `x < 0.0` or `x > k` where `k` is the number of categories
    /// (i.e. the length of the `prob_mass` slice passed to the constructor)
    ///
    /// # Formula
    ///
    /// ```ignore
    /// sum(p_j) from 0..x
    /// ```
    ///
    /// where `p_j` is the probability mass for the `j`th category
    fn cdf(&self, x: f64) -> f64 {
        assert!(x >= 0.0 && x <= self.cdf.len() as f64,
                format!("{}",
                        StatsError::ArgIntervalIncl("x", 0.0, self.cdf.len() as f64)));
        if x == self.cdf.len() as f64 {
            1.0
        } else {
            unsafe { self.cdf.get_unchecked(x as usize) / self.cdf_max() }
        }
    }
}

impl Min<u64> for Categorical {
    /// Returns the minimum value in the domain of the
    /// categorical distribution representable by a 64-bit
    /// integer
    ///
    /// # Formula
    ///
    /// ```ignore
    /// 0
    /// ```
    fn min(&self) -> u64 {
        0
    }
}

impl Max<u64> for Categorical {
    /// Returns the maximum value in the domain of the
    /// categorical distribution representable by a 64-bit
    /// integer
    ///
    /// # Formula
    ///
    /// ```ignore
    /// n
    /// ```
    fn max(&self) -> u64 {
        self.cdf.len() as u64 - 1
    }
}

impl Mean<f64> for Categorical {
    /// Returns the mean of the categorical distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// E[X] = sum(j * p_j) for j in 0..k-1
    /// ```
    ///
    /// where `p_j` is the `j`th probability mass and `k` is the number
    /// of categoires
    fn mean(&self) -> f64 {
        self.norm_pmf.iter().enumerate().fold(0.0, |acc, (idx, &val)| acc + idx as f64 * val)
    }
}

// determines if `p` is a valid probability mass array
// for the Categorical distribution
fn is_valid_prob_mass(p: &[f64]) -> bool {
    !p.iter().any(|&x| x < 0.0 || x.is_nan()) && !p.iter().all(|&x| x == 0.0)
}

#[test]
fn test_is_valid_prob_mass() {
    let invalid = [1.0, f64::NAN, 3.0];
    assert!(!is_valid_prob_mass(&invalid));
    let invalid2 = [-2.0, 5.0, 1.0, 6.2];
    assert!(!is_valid_prob_mass(&invalid2));
    let invalid3 = [0.0, 0.0, 0.0];
    assert!(!is_valid_prob_mass(&invalid3));
    let invalid4: [f64; 0] = [];
    assert!(!is_valid_prob_mass(&invalid4));
    let valid = [5.2, 0.00001, 1e-15, 1000000.12];
    assert!(is_valid_prob_mass(&valid));
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[cfg(test)]
mod test {
    use std::fmt::Debug;
    use statistics::*;
    use distribution::{Univariate, Categorical};

    fn try_create(prob_mass: &[f64]) -> Categorical {
        let n = Categorical::new(prob_mass);
        assert!(n.is_ok());
        n.unwrap()
    }

    fn create_case(prob_mass: &[f64]) {
        try_create(prob_mass);
    }

    fn bad_create_case(prob_mass: &[f64]) {
        let n = Categorical::new(prob_mass);
        assert!(n.is_err());
    }

    fn test_case<T, F>(prob_mass: &[f64], expected: T, eval: F)
        where T: PartialEq + Debug,
              F: Fn(Categorical) -> T
    {
        let n = try_create(prob_mass);
        let x = eval(n);
        assert_eq!(expected, x);
    }

    #[test]
    fn test_create() {
        create_case(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]);
    }

    #[test]
    fn test_bad_create() {
        bad_create_case(&[-1.0, 1.0]);
        bad_create_case(&[0.0, 0.0]);
    }

    #[test]
    fn test_mean() {
        test_case(&[0.0, 0.25, 0.5, 0.25], 2.0, |x| x.mean());
        test_case(&[0.0, 1.0, 2.0, 1.0], 2.0, |x| x.mean());
        test_case(&[0.0, 0.5, 0.5], 1.5, |x| x.mean());
        test_case(&[0.75, 0.25], 0.25, |x| x.mean());
        test_case(&[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], 5.0, |x| x.mean());

    }

    #[test]
    fn test_min_max() {
        test_case(&[4.0, 2.5, 2.5, 1.0], 0, |x| x.min());
        test_case(&[4.0, 2.5, 2.5, 1.0], 3, |x| x.max());
    }

    #[test]
    fn test_cdf() {
        test_case(&[0.0, 3.0, 1.0, 1.0], 3.0 / 5.0, |x| x.cdf(1.5));
        test_case(&[1.0, 1.0, 1.0, 1.0], 0.25, |x| x.cdf(0.0));
        test_case(&[4.0, 2.5, 2.5, 1.0], 0.4, |x| x.cdf(0.8));
        test_case(&[4.0, 2.5, 2.5, 1.0], 1.0, |x| x.cdf(3.2));
        test_case(&[4.0, 2.5, 2.5, 1.0], 1.0, |x| x.cdf(4.0));
    }

    #[test]
    #[should_panic]
    fn test_cdf_input_low() {
        test_case(&[4.0, 2.5, 2.5, 1.0], 1.0, |x| x.cdf(-1.0));
    }

    #[test]
    #[should_panic]
    fn test_cdf_input_high() {
        test_case(&[4.0, 2.5, 2.5, 1.0], 1.0, |x| x.cdf(4.5));
    }
}<|endoftext|>


<commit_before>extern crate clap;

use clap::{App, Arg, ErrorKind};

#[test]
fn posix_compatible_flags_long() {
    let m = App::new("posix")
        .arg(Arg::from_usage("--flag  'some flag'").overrides_with("color"))
        .arg(Arg::from_usage("--color 'some other flag'"))
        .get_matches_from(vec!["", "--flag", "--color"]);
    assert!(m.is_present("color"));
    assert!(!m.is_present("flag"));

    let m = App::new("posix")
        .arg(Arg::from_usage("--flag  'some flag'").overrides_with("color"))
        .arg(Arg::from_usage("--color 'some other flag'"))
        .get_matches_from(vec!["", "--color", "--flag"]);
    assert!(!m.is_present("color"));
    assert!(m.is_present("flag"));
}

#[test]
fn posix_compatible_flags_short() {
    let m = App::new("posix")
        .arg(Arg::from_usage("-f, --flag  'some flag'").overrides_with("color"))
        .arg(Arg::from_usage("-c, --color 'some other flag'"))
        .get_matches_from(vec!["", "-f", "-c"]);
    assert!(m.is_present("color"));
    assert!(!m.is_present("flag"));

    let m = App::new("posix")
        .arg(Arg::from_usage("-f, --flag  'some flag'").overrides_with("color"))
        .arg(Arg::from_usage("-c, --color 'some other flag'"))
        .get_matches_from(vec!["", "-c", "-f"]);
    assert!(!m.is_present("color"));
    assert!(m.is_present("flag"));
}

#[test]
fn posix_compatible_opts_long() {
    let m = App::new("posix")
        .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color"))
        .arg(Arg::from_usage("--color [color] 'some other flag'"))
        .get_matches_from(vec!["", "--flag", "some", "--color", "other"]);
    assert!(m.is_present("color"));
    assert_eq!(m.value_of("color").unwrap(), "other");
    assert!(!m.is_present("flag"));

    let m = App::new("posix")
        .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color"))
        .arg(Arg::from_usage("--color [color] 'some other flag'"))
        .get_matches_from(vec!["", "--color", "some", "--flag", "other"]);
    assert!(!m.is_present("color"));
    assert!(m.is_present("flag"));
    assert_eq!(m.value_of("flag").unwrap(), "other");
}

#[test]
fn posix_compatible_opts_long_equals() {
    let m = App::new("posix")
        .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color"))
        .arg(Arg::from_usage("--color [color] 'some other flag'"))
        .get_matches_from(vec!["", "--flag=some", "--color=other"]);
    assert!(m.is_present("color"));
    assert_eq!(m.value_of("color").unwrap(), "other");
    assert!(!m.is_present("flag"));

    let m = App::new("posix")
        .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color"))
        .arg(Arg::from_usage("--color [color] 'some other flag'"))
        .get_matches_from(vec!["", "--color=some", "--flag=other"]);
    assert!(!m.is_present("color"));
    assert!(m.is_present("flag"));
    assert_eq!(m.value_of("flag").unwrap(), "other");
}

#[test]
fn posix_compatible_opts_short() {
    let m = App::new("posix")
        .arg(Arg::from_usage("-f [flag]  'some flag'").overrides_with("c"))
        .arg(Arg::from_usage("-c [color] 'some other flag'"))
        .get_matches_from(vec!["", "-f", "some", "-c", "other"]);
    assert!(m.is_present("c"));
    assert_eq!(m.value_of("c").unwrap(), "other");
    assert!(!m.is_present("f"));

    let m = App::new("posix")
        .arg(Arg::from_usage("-f [flag]  'some flag'").overrides_with("c"))
        .arg(Arg::from_usage("-c [color] 'some other flag'"))
        .get_matches_from(vec!["", "-c", "some", "-f", "other"]);
    assert!(!m.is_present("c"));
    assert!(m.is_present("f"));
    assert_eq!(m.value_of("f").unwrap(), "other");
}

#[test]
fn conflict_overriden() {
    let m = App::new("conflict_overriden")
        .arg(Arg::from_usage("-f, --flag 'some flag'").conflicts_with("debug"))
        .arg(Arg::from_usage("-d, --debug 'other flag'"))
        .arg(Arg::from_usage("-c, --color 'third flag'").overrides_with("flag"))
        .get_matches_from(vec!["", "-f", "-c", "-d"]);
    assert!(m.is_present("color"));
    assert!(!m.is_present("flag"));
    assert!(m.is_present("debug"));
}

#[test]
fn conflict_overriden_2() {
    let result = App::new("conflict_overriden")
        .arg(Arg::from_usage("-f, --flag 'some flag'").conflicts_with("debug"))
        .arg(Arg::from_usage("-d, --debug 'other flag'"))
        .arg(Arg::from_usage("-c, --color 'third flag'").overrides_with("flag"))
        .get_matches_from_safe(vec!["", "-f", "-d", "-c"]);
    assert!(result.is_ok());
    let m = result.unwrap();
    assert!(m.is_present("color"));
    assert!(m.is_present("debug"));
    assert!(!m.is_present("flag"));
}

#[test]
fn conflict_overriden_3() {
    let result = App::new("conflict_overriden")
        .arg(Arg::from_usage("-f, --flag 'some flag'").conflicts_with("debug"))
        .arg(Arg::from_usage("-d, --debug 'other flag'"))
        .arg(Arg::from_usage("-c, --color 'third flag'").overrides_with("flag"))
        .get_matches_from_safe(vec!["", "-d", "-c", "-f"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn conflict_overriden_4() {
    let m = App::new("conflict_overriden")
        .arg(Arg::from_usage("-f, --flag 'some flag'").conflicts_with("debug"))
        .arg(Arg::from_usage("-d, --debug 'other flag'"))
        .arg(Arg::from_usage("-c, --color 'third flag'").overrides_with("flag"))
        .get_matches_from(vec!["", "-d", "-f", "-c"]);
    assert!(m.is_present("color"));
    assert!(!m.is_present("flag"));
    assert!(m.is_present("debug"));
}

#[test]
fn pos_required_overridden_by_flag() {
    let result = App::new("require_overriden")
        .arg(Arg::with_name("pos").index(1).required(true))
        .arg(Arg::from_usage("-c, --color 'some flag'").overrides_with("pos"))
        .get_matches_from_safe(vec!["", "test", "-c"]);
    assert!(result.is_ok(), "{:?}", result.unwrap_err());
}

#[test]
fn require_overriden_2() {
    let m = App::new("require_overriden")
        .arg(Arg::with_name("req_pos").required(true))
        .arg(Arg::from_usage("-c, --color 'other flag'").overrides_with("req_pos"))
        .get_matches_from(vec!["", "-c", "req_pos"]);
    assert!(!m.is_present("color"));
    assert!(m.is_present("req_pos"));
}

#[test]
fn require_overriden_3() {
    let m = App::new("require_overriden")
        .arg(Arg::from_usage("-f, --flag 'some flag'").requires("debug"))
        .arg(Arg::from_usage("-d, --debug 'other flag'"))
        .arg(Arg::from_usage("-c, --color 'third flag'").overrides_with("flag"))
        .get_matches_from(vec!["", "-f", "-c"]);
    assert!(m.is_present("color"));
    assert!(!m.is_present("flag"));
    assert!(!m.is_present("debug"));
}

#[test]
fn require_overriden_4() {
    let result = App::new("require_overriden")
        .arg(Arg::from_usage("-f, --flag 'some flag'").requires("debug"))
        .arg(Arg::from_usage("-d, --debug 'other flag'"))
        .arg(Arg::from_usage("-c, --color 'third flag'").overrides_with("flag"))
        .get_matches_from_safe(vec!["", "-c", "-f"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}
<commit_msg>tests: splits tests into single duties<commit_after>extern crate clap;

use clap::{App, Arg, ErrorKind};

#[test]
fn posix_compatible_flags_long() {
    let m = App::new("posix")
        .arg(Arg::from_usage("--flag  'some flag'").overrides_with("color"))
        .arg(Arg::from_usage("--color 'some other flag'"))
        .get_matches_from(vec!["", "--flag", "--color"]);
    assert!(m.is_present("color"));
    assert!(!m.is_present("flag"));
}

#[test]
fn posix_compatible_flags_long_rev() {
    let m = App::new("posix")
        .arg(Arg::from_usage("--flag  'some flag'").overrides_with("color"))
        .arg(Arg::from_usage("--color 'some other flag'"))
        .get_matches_from(vec!["", "--color", "--flag"]);
    assert!(!m.is_present("color"));
    assert!(m.is_present("flag"));
}

#[test]
fn posix_compatible_flags_short() {
    let m = App::new("posix")
        .arg(Arg::from_usage("-f, --flag  'some flag'").overrides_with("color"))
        .arg(Arg::from_usage("-c, --color 'some other flag'"))
        .get_matches_from(vec!["", "-f", "-c"]);
    assert!(m.is_present("color"));
    assert!(!m.is_present("flag"));
}

#[test]
fn posix_compatible_flags_short_rev() {
    let m = App::new("posix")
        .arg(Arg::from_usage("-f, --flag  'some flag'").overrides_with("color"))
        .arg(Arg::from_usage("-c, --color 'some other flag'"))
        .get_matches_from(vec!["", "-c", "-f"]);
    assert!(!m.is_present("color"));
    assert!(m.is_present("flag"));
}

#[test]
fn posix_compatible_opts_long() {
    let m = App::new("posix")
        .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color"))
        .arg(Arg::from_usage("--color [color] 'some other flag'"))
        .get_matches_from(vec!["", "--flag", "some", "--color", "other"]);
    assert!(m.is_present("color"));
    assert_eq!(m.value_of("color").unwrap(), "other");
    assert!(!m.is_present("flag"));
}

#[test]
fn posix_compatible_opts_long_rev() {
    let m = App::new("posix")
        .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color"))
        .arg(Arg::from_usage("--color [color] 'some other flag'"))
        .get_matches_from(vec!["", "--color", "some", "--flag", "other"]);
    assert!(!m.is_present("color"));
    assert!(m.is_present("flag"));
    assert_eq!(m.value_of("flag").unwrap(), "other");
}

#[test]
fn posix_compatible_opts_long_equals() {
    let m = App::new("posix")
        .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color"))
        .arg(Arg::from_usage("--color [color] 'some other flag'"))
        .get_matches_from(vec!["", "--flag=some", "--color=other"]);
    assert!(m.is_present("color"));
    assert_eq!(m.value_of("color").unwrap(), "other");
    assert!(!m.is_present("flag"));
}

#[test]
fn posix_compatible_opts_long_equals_rev() {
    let m = App::new("posix")
        .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color"))
        .arg(Arg::from_usage("--color [color] 'some other flag'"))
        .get_matches_from(vec!["", "--color=some", "--flag=other"]);
    assert!(!m.is_present("color"));
    assert!(m.is_present("flag"));
    assert_eq!(m.value_of("flag").unwrap(), "other");
}

#[test]
fn posix_compatible_opts_short() {
    let m = App::new("posix")
        .arg(Arg::from_usage("-f [flag]  'some flag'").overrides_with("c"))
        .arg(Arg::from_usage("-c [color] 'some other flag'"))
        .get_matches_from(vec!["", "-f", "some", "-c", "other"]);
    assert!(m.is_present("c"));
    assert_eq!(m.value_of("c").unwrap(), "other");
    assert!(!m.is_present("f"));
}

#[test]
fn posix_compatible_opts_short_rev() {
    let m = App::new("posix")
        .arg(Arg::from_usage("-f [flag]  'some flag'").overrides_with("c"))
        .arg(Arg::from_usage("-c [color] 'some other flag'"))
        .get_matches_from(vec!["", "-c", "some", "-f", "other"]);
    assert!(!m.is_present("c"));
    assert!(m.is_present("f"));
    assert_eq!(m.value_of("f").unwrap(), "other");
}

#[test]
fn conflict_overriden() {
    let m = App::new("conflict_overriden")
        .arg(Arg::from_usage("-f, --flag 'some flag'").conflicts_with("debug"))
        .arg(Arg::from_usage("-d, --debug 'other flag'"))
        .arg(Arg::from_usage("-c, --color 'third flag'").overrides_with("flag"))
        .get_matches_from(vec!["", "-f", "-c", "-d"]);
    assert!(m.is_present("color"));
    assert!(!m.is_present("flag"));
    assert!(m.is_present("debug"));
}

#[test]
fn conflict_overriden_2() {
    let result = App::new("conflict_overriden")
        .arg(Arg::from_usage("-f, --flag 'some flag'").conflicts_with("debug"))
        .arg(Arg::from_usage("-d, --debug 'other flag'"))
        .arg(Arg::from_usage("-c, --color 'third flag'").overrides_with("flag"))
        .get_matches_from_safe(vec!["", "-f", "-d", "-c"]);
    assert!(result.is_ok());
    let m = result.unwrap();
    assert!(m.is_present("color"));
    assert!(m.is_present("debug"));
    assert!(!m.is_present("flag"));
}

#[test]
fn conflict_overriden_3() {
    let result = App::new("conflict_overriden")
        .arg(Arg::from_usage("-f, --flag 'some flag'").conflicts_with("debug"))
        .arg(Arg::from_usage("-d, --debug 'other flag'"))
        .arg(Arg::from_usage("-c, --color 'third flag'").overrides_with("flag"))
        .get_matches_from_safe(vec!["", "-d", "-c", "-f"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn conflict_overriden_4() {
    let m = App::new("conflict_overriden")
        .arg(Arg::from_usage("-f, --flag 'some flag'").conflicts_with("debug"))
        .arg(Arg::from_usage("-d, --debug 'other flag'"))
        .arg(Arg::from_usage("-c, --color 'third flag'").overrides_with("flag"))
        .get_matches_from(vec!["", "-d", "-f", "-c"]);
    assert!(m.is_present("color"));
    assert!(!m.is_present("flag"));
    assert!(m.is_present("debug"));
}

#[test]
fn pos_required_overridden_by_flag() {
    let result = App::new("require_overriden")
        .arg(Arg::with_name("pos").index(1).required(true))
        .arg(Arg::from_usage("-c, --color 'some flag'").overrides_with("pos"))
        .get_matches_from_safe(vec!["", "test", "-c"]);
    assert!(result.is_ok(), "{:?}", result.unwrap_err());
}

#[test]
fn require_overriden_2() {
    let m = App::new("require_overriden")
        .arg(Arg::with_name("req_pos").required(true))
        .arg(Arg::from_usage("-c, --color 'other flag'").overrides_with("req_pos"))
        .get_matches_from(vec!["", "-c", "req_pos"]);
    assert!(!m.is_present("color"));
    assert!(m.is_present("req_pos"));
}

#[test]
fn require_overriden_3() {
    let m = App::new("require_overriden")
        .arg(Arg::from_usage("-f, --flag 'some flag'").requires("debug"))
        .arg(Arg::from_usage("-d, --debug 'other flag'"))
        .arg(Arg::from_usage("-c, --color 'third flag'").overrides_with("flag"))
        .get_matches_from(vec!["", "-f", "-c"]);
    assert!(m.is_present("color"));
    assert!(!m.is_present("flag"));
    assert!(!m.is_present("debug"));
}

#[test]
fn require_overriden_4() {
    let result = App::new("require_overriden")
        .arg(Arg::from_usage("-f, --flag 'some flag'").requires("debug"))
        .arg(Arg::from_usage("-d, --debug 'other flag'"))
        .arg(Arg::from_usage("-c, --color 'third flag'").overrides_with("flag"))
        .get_matches_from_safe(vec!["", "-c", "-f"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}
<|endoftext|>


<commit_before>/// `mbe` (short for Macro By Example) crate contains code for handling
/// `macro_rules` macros. It uses `TokenTree` (from `ra_tt` package) as the
/// interface, although it contains some code to bridge `SyntaxNode`s and
/// `TokenTree`s as well!

macro_rules! impl_froms {
    ($e:ident: $($v:ident), *) => {
        $(
            impl From<$v> for $e {
                fn from(it: $v) -> $e {
                    $e::$v(it)
                }
            }
        )*
    }
}

mod tt_cursor;
mod mbe_parser;
mod mbe_expander;
mod syntax_bridge;

use ra_syntax::SmolStr;

pub use tt::{Delimiter, Punct};

pub use crate::syntax_bridge::ast_to_token_tree;

/// This struct contains AST for a single `macro_rules` defenition. What might
/// be very confusing is that AST has almost exactly the same shape as
/// `tt::TokenTree`, but there's a crucial difference: in macro rules, `$ident`
/// and `$()*` have special meaning (see `Var` and `Repeat` data structures)
#[derive(Debug)]
pub struct MacroRules {
    pub(crate) rules: Vec<Rule>,
}

impl MacroRules {
    pub fn parse(tt: &tt::Subtree) -> Option<MacroRules> {
        mbe_parser::parse(tt)
    }
    pub fn expand(&self, tt: &tt::Subtree) -> Option<tt::Subtree> {
        mbe_expander::exapnd(self, tt)
    }
}

#[derive(Debug)]
pub(crate) struct Rule {
    pub(crate) lhs: Subtree,
    pub(crate) rhs: Subtree,
}

#[derive(Debug)]
pub(crate) enum TokenTree {
    Leaf(Leaf),
    Subtree(Subtree),
    Repeat(Repeat),
}
impl_froms!(TokenTree: Leaf, Subtree, Repeat);

#[derive(Debug)]
pub(crate) enum Leaf {
    Literal(Literal),
    Punct(Punct),
    Ident(Ident),
    Var(Var),
}
impl_froms!(Leaf: Literal, Punct, Ident, Var);

#[derive(Debug)]
pub(crate) struct Subtree {
    pub(crate) delimiter: Delimiter,
    pub(crate) token_trees: Vec<TokenTree>,
}

#[derive(Debug)]
pub(crate) struct Repeat {
    pub(crate) subtree: Subtree,
    pub(crate) kind: RepeatKind,
    pub(crate) separator: Option<char>,
}

#[derive(Debug)]
pub(crate) enum RepeatKind {
    ZeroOrMore,
    OneOrMore,
    ZeroOrOne,
}

#[derive(Debug)]
pub(crate) struct Literal {
    pub(crate) text: SmolStr,
}

#[derive(Debug)]
pub(crate) struct Ident {
    pub(crate) text: SmolStr,
}

#[derive(Debug)]
pub(crate) struct Var {
    pub(crate) text: SmolStr,
    pub(crate) kind: Option<SmolStr>,
}

#[cfg(test)]
mod tests {
    use ra_syntax::{ast, AstNode};

    use super::*;

    // Good first issue (although a slightly chellegning one):
    //
    // * Pick a random test from here
    //   https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt
    // * Port the test to rust and add it to this module
    // * Make it pass :-)

    #[test]
    fn test_convert_tt() {
        let macro_definition = r#"
macro_rules! impl_froms {
    ($e:ident: $($v:ident),*) => {
        $(
            impl From<$v> for $e {
                fn from(it: $v) -> $e {
                    $e::$v(it)
                }
            }
        )*
    }
}
"#;

        let macro_invocation = r#"
impl_froms!(TokenTree: Leaf, Subtree);
"#;

        let source_file = ast::SourceFile::parse(macro_definition);
        let macro_definition = source_file
            .syntax()
            .descendants()
            .find_map(ast::MacroCall::cast)
            .unwrap();

        let source_file = ast::SourceFile::parse(macro_invocation);
        let macro_invocation = source_file
            .syntax()
            .descendants()
            .find_map(ast::MacroCall::cast)
            .unwrap();

        let definition_tt = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap();
        let invocation_tt = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap();
        let rules = crate::MacroRules::parse(&definition_tt).unwrap();
        let expansion = rules.expand(&invocation_tt).unwrap();
        assert_eq!(
        expansion.to_string(),
        "impl From < Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree :: Leaf (it)}} \
         impl From < Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree :: Subtree (it)}}"
    )
    }

    fn assert_expansion(rules: &MacroRules, invocation: &str, expansion: &str) {
        let source_file = ast::SourceFile::parse(invocation);
        let macro_invocation = source_file
            .syntax()
            .descendants()
            .find_map(ast::MacroCall::cast)
            .unwrap();

        let invocation_tt = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap();

        let expaned = rules.expand(&invocation_tt).unwrap();
        assert_eq!(expaned.to_string(), expansion);
    }

    #[test]
    fn test_fail_match_pattern_by_first_token() {
        let macro_definition = r#"
        macro_rules! foo {
            ($ i:ident) => (
                mod $ i {}
            );
            (= $ i:ident) => (
                fn $ i() {}
            );
            (+ $ i:ident) => (
                struct $ i;
            )
        }
"#;

        let source_file = ast::SourceFile::parse(macro_definition);
        let macro_definition = source_file
            .syntax()
            .descendants()
            .find_map(ast::MacroCall::cast)
            .unwrap();

        let definition_tt = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap();
        let rules = crate::MacroRules::parse(&definition_tt).unwrap();

        assert_expansion(&rules, "foo! { foo }", "mod foo {}");
        assert_expansion(&rules, "foo! { = bar }", "fn bar () {}");
        assert_expansion(&rules, "foo! { + Baz }", "struct Baz ;");
    }

    #[test]
    fn test_fail_match_pattern_by_last_token() {
        let macro_definition = r#"
        macro_rules! foo {
            ($ i:ident) => (
                mod $ i {}
            );
            ($ i:ident =) => (
                fn $ i() {}
            );
            ($ i:ident +) => (
                struct $ i;
            )
        }
"#;

        let source_file = ast::SourceFile::parse(macro_definition);
        let macro_definition = source_file
            .syntax()
            .descendants()
            .find_map(ast::MacroCall::cast)
            .unwrap();

        let definition_tt = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap();
        let rules = crate::MacroRules::parse(&definition_tt).unwrap();

        assert_expansion(&rules, "foo! { foo }", "mod foo {}");
        assert_expansion(&rules, "foo! { bar = }", "fn bar () {}");
        assert_expansion(&rules, "foo! { Baz + }", "struct Baz ;");
    }
}
<commit_msg>Factor out rules parsing<commit_after>/// `mbe` (short for Macro By Example) crate contains code for handling
/// `macro_rules` macros. It uses `TokenTree` (from `ra_tt` package) as the
/// interface, although it contains some code to bridge `SyntaxNode`s and
/// `TokenTree`s as well!

macro_rules! impl_froms {
    ($e:ident: $($v:ident), *) => {
        $(
            impl From<$v> for $e {
                fn from(it: $v) -> $e {
                    $e::$v(it)
                }
            }
        )*
    }
}

mod tt_cursor;
mod mbe_parser;
mod mbe_expander;
mod syntax_bridge;

use ra_syntax::SmolStr;

pub use tt::{Delimiter, Punct};

pub use crate::syntax_bridge::ast_to_token_tree;

/// This struct contains AST for a single `macro_rules` defenition. What might
/// be very confusing is that AST has almost exactly the same shape as
/// `tt::TokenTree`, but there's a crucial difference: in macro rules, `$ident`
/// and `$()*` have special meaning (see `Var` and `Repeat` data structures)
#[derive(Debug)]
pub struct MacroRules {
    pub(crate) rules: Vec<Rule>,
}

impl MacroRules {
    pub fn parse(tt: &tt::Subtree) -> Option<MacroRules> {
        mbe_parser::parse(tt)
    }
    pub fn expand(&self, tt: &tt::Subtree) -> Option<tt::Subtree> {
        mbe_expander::exapnd(self, tt)
    }
}

#[derive(Debug)]
pub(crate) struct Rule {
    pub(crate) lhs: Subtree,
    pub(crate) rhs: Subtree,
}

#[derive(Debug)]
pub(crate) enum TokenTree {
    Leaf(Leaf),
    Subtree(Subtree),
    Repeat(Repeat),
}
impl_froms!(TokenTree: Leaf, Subtree, Repeat);

#[derive(Debug)]
pub(crate) enum Leaf {
    Literal(Literal),
    Punct(Punct),
    Ident(Ident),
    Var(Var),
}
impl_froms!(Leaf: Literal, Punct, Ident, Var);

#[derive(Debug)]
pub(crate) struct Subtree {
    pub(crate) delimiter: Delimiter,
    pub(crate) token_trees: Vec<TokenTree>,
}

#[derive(Debug)]
pub(crate) struct Repeat {
    pub(crate) subtree: Subtree,
    pub(crate) kind: RepeatKind,
    pub(crate) separator: Option<char>,
}

#[derive(Debug)]
pub(crate) enum RepeatKind {
    ZeroOrMore,
    OneOrMore,
    ZeroOrOne,
}

#[derive(Debug)]
pub(crate) struct Literal {
    pub(crate) text: SmolStr,
}

#[derive(Debug)]
pub(crate) struct Ident {
    pub(crate) text: SmolStr,
}

#[derive(Debug)]
pub(crate) struct Var {
    pub(crate) text: SmolStr,
    pub(crate) kind: Option<SmolStr>,
}

#[cfg(test)]
mod tests {
    use ra_syntax::{ast, AstNode};

    use super::*;

    // Good first issue (although a slightly chellegning one):
    //
    // * Pick a random test from here
    //   https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt
    // * Port the test to rust and add it to this module
    // * Make it pass :-)

    #[test]
    fn test_convert_tt() {
        let macro_definition = r#"
macro_rules! impl_froms {
    ($e:ident: $($v:ident),*) => {
        $(
            impl From<$v> for $e {
                fn from(it: $v) -> $e {
                    $e::$v(it)
                }
            }
        )*
    }
}
"#;

        let macro_invocation = r#"
impl_froms!(TokenTree: Leaf, Subtree);
"#;

        let source_file = ast::SourceFile::parse(macro_definition);
        let macro_definition = source_file
            .syntax()
            .descendants()
            .find_map(ast::MacroCall::cast)
            .unwrap();

        let source_file = ast::SourceFile::parse(macro_invocation);
        let macro_invocation = source_file
            .syntax()
            .descendants()
            .find_map(ast::MacroCall::cast)
            .unwrap();

        let definition_tt = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap();
        let invocation_tt = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap();
        let rules = crate::MacroRules::parse(&definition_tt).unwrap();
        let expansion = rules.expand(&invocation_tt).unwrap();
        assert_eq!(
        expansion.to_string(),
        "impl From < Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree :: Leaf (it)}} \
         impl From < Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree :: Subtree (it)}}"
    )
    }

    fn create_rules(macro_definition: &str) -> MacroRules {
        let source_file = ast::SourceFile::parse(macro_definition);
        let macro_definition = source_file
            .syntax()
            .descendants()
            .find_map(ast::MacroCall::cast)
            .unwrap();

        let definition_tt = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap();
        crate::MacroRules::parse(&definition_tt).unwrap()
    }

    fn assert_expansion(rules: &MacroRules, invocation: &str, expansion: &str) {
        let source_file = ast::SourceFile::parse(invocation);
        let macro_invocation = source_file
            .syntax()
            .descendants()
            .find_map(ast::MacroCall::cast)
            .unwrap();

        let invocation_tt = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap();

        let expaned = rules.expand(&invocation_tt).unwrap();
        assert_eq!(expaned.to_string(), expansion);
    }

    #[test]
    fn test_fail_match_pattern_by_first_token() {
        let rules = create_rules(
            r#"
        macro_rules! foo {
            ($ i:ident) => (
                mod $ i {}
            );
            (= $ i:ident) => (
                fn $ i() {}
            );
            (+ $ i:ident) => (
                struct $ i;
            )
        }
"#,
        );

        assert_expansion(&rules, "foo! { foo }", "mod foo {}");
        assert_expansion(&rules, "foo! { = bar }", "fn bar () {}");
        assert_expansion(&rules, "foo! { + Baz }", "struct Baz ;");
    }

    #[test]
    fn test_fail_match_pattern_by_last_token() {
        let rules = create_rules(
            r#"
        macro_rules! foo {
            ($ i:ident) => (
                mod $ i {}
            );
            ($ i:ident =) => (
                fn $ i() {}
            );
            ($ i:ident +) => (
                struct $ i;
            )
        }
"#,
        );

        assert_expansion(&rules, "foo! { foo }", "mod foo {}");
        assert_expansion(&rules, "foo! { bar = }", "fn bar () {}");
        assert_expansion(&rules, "foo! { Baz + }", "struct Baz ;");
    }
}
<|endoftext|>


<commit_before>//!
//! Module for common/shared types of the various [`Device`](::backend::drm::Device)
//! and [`Surface`](::backend::drm::Surface) implementations of the `backend::drm` module.
//!

use crate::backend::graphics::SwapBuffersError;
use drm::control::{connector, crtc, Mode, RawResourceHandle};
use std::path::PathBuf;

pub mod fallback;

/// Errors thrown by the [`LegacyDrmDevice`](::backend::drm::legacy::LegacyDrmDevice),
/// [`AtomicDrmDevice`](::backend::drm::atomic::AtomicDrmDevice)
/// and their surfaces: [`LegacyDrmSurface`](::backend::drm::legacy::LegacyDrmSurface)
/// and [`AtomicDrmSurface`](::backend::drm::atomic::AtomicDrmSurface).
#[derive(thiserror::Error, Debug)]
pub enum Error {
    /// Unable to acquire DRM master
    #[error("Failed to aquire DRM master")]
    DrmMasterFailed,
    /// The `DrmDevice` encountered an access error
    #[error("DRM access error: {errmsg} on device `{dev:?}` ({source:})")]
    Access {
        /// Error message associated to the access error
        errmsg: &'static str,
        /// Device on which the error was generated
        dev: Option<PathBuf>,
        /// Underlying device error
        source: failure::Compat<drm::SystemError>,
    },
    /// Unable to determine device id of drm device
    #[error("Unable to determine device id of drm device")]
    UnableToGetDeviceId(#[source] nix::Error),
    /// Device is currently paused
    #[error("Device is currently paused, operation rejected")]
    DeviceInactive,
    /// Mode is not compatible with all given connectors
    #[error("Mode `{0:?}` is not compatible with all given connectors")]
    ModeNotSuitable(Mode),
    /// The given crtc is already in use by another backend
    #[error("Crtc `{0:?}` is already in use by another backend")]
    CrtcAlreadyInUse(crtc::Handle),
    /// This operation would result in a surface without connectors.
    #[error("Surface of crtc `{0:?}` would have no connectors, which is not accepted")]
    SurfaceWithoutConnectors(crtc::Handle),
    /// No encoder was found for a given connector on the set crtc
    #[error("No encoder found for the given connector '{connector:?}' on crtc `{crtc:?}`")]
    NoSuitableEncoder {
        /// Connector
        connector: connector::Handle,
        /// CRTC
        crtc: crtc::Handle,
    },
    /// No matching primary and cursor plane could be found for the given crtc
    #[error("No matching primary and cursor plane could be found for crtc {crtc:?} on {dev:?}")]
    NoSuitablePlanes {
        /// CRTC
        crtc: crtc::Handle,
        /// Device on which the error was generated
        dev: Option<PathBuf>,
    },
    /// The DrmDevice is missing a required property
    #[error("The DrmDevice is missing a required property '{name}' for handle ({handle:?})")]
    UnknownProperty {
        /// Property handle
        handle: RawResourceHandle,
        /// Property name
        name: &'static str,
    },
    /// Atomic Test failed for new properties
    #[error("Atomic Test failed for new properties on crtc ({0:?})")]
    TestFailed(crtc::Handle),
}

impl Into<SwapBuffersError> for Error {
    fn into(self) -> SwapBuffersError {
        match self {
            x @ Error::DeviceInactive => SwapBuffersError::TemporaryFailure(Box::new(x)),
            Error::Access { source, .. }
                if match source.get_ref() {
                    drm::SystemError::Unknown {
                        errno: nix::errno::Errno::EBUSY,
                    } => true,
                    drm::SystemError::Unknown {
                        errno: nix::errno::Errno::EINTR,
                    } => true,
                    _ => false,
                } =>
            {
                SwapBuffersError::TemporaryFailure(Box::new(source))
            }
            x => SwapBuffersError::ContextLost(Box::new(x)),
        }
    }
}
<commit_msg>drm: Do not unpack drm-rs errors on conversion<commit_after>//!
//! Module for common/shared types of the various [`Device`](::backend::drm::Device)
//! and [`Surface`](::backend::drm::Surface) implementations of the `backend::drm` module.
//!

use crate::backend::graphics::SwapBuffersError;
use drm::control::{connector, crtc, Mode, RawResourceHandle};
use std::path::PathBuf;

pub mod fallback;

/// Errors thrown by the [`LegacyDrmDevice`](::backend::drm::legacy::LegacyDrmDevice),
/// [`AtomicDrmDevice`](::backend::drm::atomic::AtomicDrmDevice)
/// and their surfaces: [`LegacyDrmSurface`](::backend::drm::legacy::LegacyDrmSurface)
/// and [`AtomicDrmSurface`](::backend::drm::atomic::AtomicDrmSurface).
#[derive(thiserror::Error, Debug)]
pub enum Error {
    /// Unable to acquire DRM master
    #[error("Failed to aquire DRM master")]
    DrmMasterFailed,
    /// The `DrmDevice` encountered an access error
    #[error("DRM access error: {errmsg} on device `{dev:?}` ({source:})")]
    Access {
        /// Error message associated to the access error
        errmsg: &'static str,
        /// Device on which the error was generated
        dev: Option<PathBuf>,
        /// Underlying device error
        source: failure::Compat<drm::SystemError>,
    },
    /// Unable to determine device id of drm device
    #[error("Unable to determine device id of drm device")]
    UnableToGetDeviceId(#[source] nix::Error),
    /// Device is currently paused
    #[error("Device is currently paused, operation rejected")]
    DeviceInactive,
    /// Mode is not compatible with all given connectors
    #[error("Mode `{0:?}` is not compatible with all given connectors")]
    ModeNotSuitable(Mode),
    /// The given crtc is already in use by another backend
    #[error("Crtc `{0:?}` is already in use by another backend")]
    CrtcAlreadyInUse(crtc::Handle),
    /// This operation would result in a surface without connectors.
    #[error("Surface of crtc `{0:?}` would have no connectors, which is not accepted")]
    SurfaceWithoutConnectors(crtc::Handle),
    /// No encoder was found for a given connector on the set crtc
    #[error("No encoder found for the given connector '{connector:?}' on crtc `{crtc:?}`")]
    NoSuitableEncoder {
        /// Connector
        connector: connector::Handle,
        /// CRTC
        crtc: crtc::Handle,
    },
    /// No matching primary and cursor plane could be found for the given crtc
    #[error("No matching primary and cursor plane could be found for crtc {crtc:?} on {dev:?}")]
    NoSuitablePlanes {
        /// CRTC
        crtc: crtc::Handle,
        /// Device on which the error was generated
        dev: Option<PathBuf>,
    },
    /// The DrmDevice is missing a required property
    #[error("The DrmDevice is missing a required property '{name}' for handle ({handle:?})")]
    UnknownProperty {
        /// Property handle
        handle: RawResourceHandle,
        /// Property name
        name: &'static str,
    },
    /// Atomic Test failed for new properties
    #[error("Atomic Test failed for new properties on crtc ({0:?})")]
    TestFailed(crtc::Handle),
}

impl Into<SwapBuffersError> for Error {
    fn into(self) -> SwapBuffersError {
        match self {
            x @ Error::DeviceInactive => SwapBuffersError::TemporaryFailure(Box::new(x)),
            Error::Access { errmsg, dev, source, .. }
                if match source.get_ref() {
                    drm::SystemError::Unknown {
                        errno: nix::errno::Errno::EBUSY,
                    } => true,
                    drm::SystemError::Unknown {
                        errno: nix::errno::Errno::EINTR,
                    } => true,
                    _ => false,
                } =>
            {
                SwapBuffersError::TemporaryFailure(Box::new(Error::Access { errmsg, dev, source }))
            },
            x => SwapBuffersError::ContextLost(Box::new(x)),
        }
    }
}
<|endoftext|>


<commit_before>use backend::Backend;
use connection::Connection;
use helper_types::Limit;
use query_builder::{QueryFragment, AsQuery, QueryId};
use query_source::Queryable;
use result::QueryResult;
use super::LimitDsl;
use types::HasSqlType;

/// Methods to execute a query given a connection. These are automatically implemented for the
/// various query types.
pub trait LoadDsl<Conn: Connection>: Sized where
    Conn::Backend: HasSqlType<Self::SqlType>,
{
    type SqlType;

    /// Executes the given query, returning an `Iterator` over the returned
    /// rows.
    fn load<U>(self, conn: &Conn) -> QueryResult<Vec<U>> where
        U: Queryable<Self::SqlType, Conn::Backend>;

    /// Attempts to load a single record. Returns `Ok(record)` if found, and
    /// `Err(NotFound)` if no results are returned. If the query truly is
    /// optional, you can call `.optional()` on the result of this to get a
    /// `Result<Option<U>>`.
    fn first<U>(self, conn: &Conn) -> QueryResult<U> where
        Self: LimitDsl,
        Limit<Self>: LoadDsl<Conn, SqlType=<Self as LoadDsl<Conn>>::SqlType>,
        U: Queryable<<Self as LoadDsl<Conn>>::SqlType, Conn::Backend>,
    {
        self.limit(1).get_result(conn)
    }

    /// Runs the command, and returns the affected row. `Err(NotFound)` will be
    /// returned if the query affected 0 rows. You can call `.optional()` on the
    /// result of this if the command was optional to get back a
    /// `Result<Option<U>>`
    fn get_result<U>(self, conn: &Conn) -> QueryResult<U> where
        U: Queryable<Self::SqlType, Conn::Backend>;

    /// Runs the command, returning an `Iterator` over the affected rows.
    fn get_results<U>(self, conn: &Conn) -> QueryResult<Vec<U>> where
        U: Queryable<Self::SqlType, Conn::Backend>,
    {
        self.load(conn)
    }
}

impl<Conn: Connection, T: AsQuery> LoadDsl<Conn> for T where
    T::Query: QueryFragment<Conn::Backend> + QueryId,
    Conn::Backend: HasSqlType<T::SqlType>,
{
    type SqlType = <Self as AsQuery>::SqlType;

    fn load<U>(self, conn: &Conn) -> QueryResult<Vec<U>> where
        U: Queryable<Self::SqlType, Conn::Backend>,
    {
        conn.query_all(self)
    }

    fn get_result<U>(self, conn: &Conn) -> QueryResult<U> where
        U: Queryable<Self::SqlType, Conn::Backend>,
    {
        conn.query_one(self)
    }
}

pub trait ExecuteDsl<Conn: Connection<Backend=DB>, DB: Backend = <Conn as Connection>::Backend>: Sized {
    /// Executes the given command, returning the number of rows affected. Used
    /// in conjunction with
    /// [`update`](/diesel/fn.update.html) and
    /// [`delete`](/diesel/fn.delete.html)
    fn execute(self, conn: &Conn) -> QueryResult<usize>;
}

impl<Conn, T> ExecuteDsl<Conn> for T where
    Conn: Connection,
    T: QueryFragment<Conn::Backend> + QueryId,
{
    fn execute(self, conn: &Conn) -> QueryResult<usize> {
        conn.execute_returning_count(&self)
    }
}
<commit_msg>We are returning vectors here (#888)<commit_after>use backend::Backend;
use connection::Connection;
use helper_types::Limit;
use query_builder::{QueryFragment, AsQuery, QueryId};
use query_source::Queryable;
use result::QueryResult;
use super::LimitDsl;
use types::HasSqlType;

/// Methods to execute a query given a connection. These are automatically implemented for the
/// various query types.
pub trait LoadDsl<Conn: Connection>: Sized where
    Conn::Backend: HasSqlType<Self::SqlType>,
{
    type SqlType;

    /// Executes the given query, returning a `Vec` with the returned rows.
    fn load<U>(self, conn: &Conn) -> QueryResult<Vec<U>> where
        U: Queryable<Self::SqlType, Conn::Backend>;

    /// Attempts to load a single record. Returns `Ok(record)` if found, and
    /// `Err(NotFound)` if no results are returned. If the query truly is
    /// optional, you can call `.optional()` on the result of this to get a
    /// `Result<Option<U>>`.
    fn first<U>(self, conn: &Conn) -> QueryResult<U> where
        Self: LimitDsl,
        Limit<Self>: LoadDsl<Conn, SqlType=<Self as LoadDsl<Conn>>::SqlType>,
        U: Queryable<<Self as LoadDsl<Conn>>::SqlType, Conn::Backend>,
    {
        self.limit(1).get_result(conn)
    }

    /// Runs the command, and returns the affected row. `Err(NotFound)` will be
    /// returned if the query affected 0 rows. You can call `.optional()` on the
    /// result of this if the command was optional to get back a
    /// `Result<Option<U>>`
    fn get_result<U>(self, conn: &Conn) -> QueryResult<U> where
        U: Queryable<Self::SqlType, Conn::Backend>;

    /// Runs the command, returning an `Vec` with the affected rows.
    fn get_results<U>(self, conn: &Conn) -> QueryResult<Vec<U>> where
        U: Queryable<Self::SqlType, Conn::Backend>,
    {
        self.load(conn)
    }
}

impl<Conn: Connection, T: AsQuery> LoadDsl<Conn> for T where
    T::Query: QueryFragment<Conn::Backend> + QueryId,
    Conn::Backend: HasSqlType<T::SqlType>,
{
    type SqlType = <Self as AsQuery>::SqlType;

    fn load<U>(self, conn: &Conn) -> QueryResult<Vec<U>> where
        U: Queryable<Self::SqlType, Conn::Backend>,
    {
        conn.query_all(self)
    }

    fn get_result<U>(self, conn: &Conn) -> QueryResult<U> where
        U: Queryable<Self::SqlType, Conn::Backend>,
    {
        conn.query_one(self)
    }
}

pub trait ExecuteDsl<Conn: Connection<Backend=DB>, DB: Backend = <Conn as Connection>::Backend>: Sized {
    /// Executes the given command, returning the number of rows affected. Used
    /// in conjunction with
    /// [`update`](/diesel/fn.update.html) and
    /// [`delete`](/diesel/fn.delete.html)
    fn execute(self, conn: &Conn) -> QueryResult<usize>;
}

impl<Conn, T> ExecuteDsl<Conn> for T where
    Conn: Connection,
    T: QueryFragment<Conn::Backend> + QueryId,
{
    fn execute(self, conn: &Conn) -> QueryResult<usize> {
        conn.execute_returning_count(&self)
    }
}
<|endoftext|>


<commit_before>//! Endpoints for room membership.

pub mod ban_user;
pub mod forget_room;
pub mod get_member_events;
pub mod invite_user;
pub mod join_room_by_id;
pub mod join_room_by_id_or_alias;
pub mod joined_members;
pub mod joined_rooms;
pub mod kick_user;
pub mod leave_room;
pub mod unban_user;

use std::collections::BTreeMap;

use ruma_common::thirdparty::Medium;
use ruma_identifiers::{ServerNameBox, ServerSigningKeyId};
use ruma_serde::Outgoing;
use serde::Serialize;

/// A signature of an `m.third_party_invite` token to prove that this user owns a third party
/// identity which has been invited to the room.
#[derive(Clone, Debug, Outgoing, Serialize)]
pub struct ThirdPartySigned<'a> {
    /// The Matrix ID of the user who issued the invite.
    pub sender: &'a str,

    /// The Matrix ID of the invitee.
    pub mxid: &'a str,

    /// The state key of the `m.third_party_invite` event.
    pub token: &'a str,

    /// A signatures object containing a signature of the entire signed object.
    pub signatures: BTreeMap<ServerNameBox, BTreeMap<ServerSigningKeyId, String>>,
}

/// Represents third party IDs to invite to the room.
#[derive(Clone, Debug, PartialEq, Outgoing, Serialize)]
#[incoming_derive(PartialEq)]
pub struct Invite3pid<'a> {
    /// Hostname and port of identity server to be used for account lookups.
    pub id_server: &'a str,

    /// An access token registered with the identity server.
    pub id_access_token: &'a str,

    /// Type of third party ID.
    pub medium: Medium,

    /// Third party identifier.
    pub address: &'a str,
}
<commit_msg>client-api: Change str to UserId in ThirdPartySigned<commit_after>//! Endpoints for room membership.

pub mod ban_user;
pub mod forget_room;
pub mod get_member_events;
pub mod invite_user;
pub mod join_room_by_id;
pub mod join_room_by_id_or_alias;
pub mod joined_members;
pub mod joined_rooms;
pub mod kick_user;
pub mod leave_room;
pub mod unban_user;

use std::collections::BTreeMap;

use ruma_common::thirdparty::Medium;
use ruma_identifiers::{ServerNameBox, ServerSigningKeyId, UserId};
use ruma_serde::Outgoing;
use serde::Serialize;

/// A signature of an `m.third_party_invite` token to prove that this user owns a third party
/// identity which has been invited to the room.
#[derive(Clone, Debug, Outgoing, Serialize)]
pub struct ThirdPartySigned<'a> {
    /// The Matrix ID of the user who issued the invite.
    pub sender: &'a UserId,

    /// The Matrix ID of the invitee.
    pub mxid: &'a UserId,

    /// The state key of the `m.third_party_invite` event.
    pub token: &'a str,

    /// A signatures object containing a signature of the entire signed object.
    pub signatures: BTreeMap<ServerNameBox, BTreeMap<ServerSigningKeyId, String>>,
}

/// Represents third party IDs to invite to the room.
#[derive(Clone, Debug, PartialEq, Outgoing, Serialize)]
#[incoming_derive(PartialEq)]
pub struct Invite3pid<'a> {
    /// Hostname and port of identity server to be used for account lookups.
    pub id_server: &'a str,

    /// An access token registered with the identity server.
    pub id_access_token: &'a str,

    /// Type of third party ID.
    pub medium: Medium,

    /// Third party identifier.
    pub address: &'a str,
}
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc. All rights reserved.
//
// 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.

use std::collections::{HashMap, hash_map};

use super::{PluginName, PluginDescription};
use super::manifest::debug_plugins;

/// A catalog of all available plugins.
pub struct PluginCatalog {
    items: HashMap<PluginName, PluginDescription>,
}

impl <'a>PluginCatalog {
    /// For use during development: returns the debug plugins
    pub fn debug() -> Self {
        PluginCatalog::new(&debug_plugins())
    }

    pub fn new(plugins: &[PluginDescription]) -> Self {
        let mut items = HashMap::with_capacity(plugins.len());
        for plugin in plugins {
            if items.contains_key(&plugin.name) {
                print_err!("Duplicate plugin name.\n 1: {:?}\n 2: {:?}",
                           plugin, items.get(&plugin.name));
                continue
            }
            items.insert(plugin.name.to_owned(), plugin.to_owned());
        }
        PluginCatalog { items }
    }

    pub fn iter(&'a self) -> hash_map::Values<PluginName, PluginDescription> {
       self.items.values()
    }

    pub fn iter_names(&'a self) -> hash_map::Keys<PluginName, PluginDescription> {
        self.items.keys()
    }

    pub fn get_named(&self, plugin_name: &str) -> Option<&PluginDescription> {
        self.items.get(plugin_name)
    }

    /// Returns all PluginDescriptions matching some predicate
    pub fn filter<F>(&self, predicate: F) -> Vec<&PluginDescription>
    where F: Fn(&PluginDescription) -> bool {
        self.iter()
            .filter(|item| predicate(item))
            .collect::<Vec<_>>()
    }
}
<commit_msg>Adopt Box<Iterator>> pattern in PluginCatalog<commit_after>// Copyright 2017 Google Inc. All rights reserved.
//
// 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.

use std::collections::HashMap;

use super::{PluginName, PluginDescription};
use super::manifest::debug_plugins;

/// A catalog of all available plugins.
pub struct PluginCatalog {
    items: HashMap<PluginName, PluginDescription>,
}

impl <'a>PluginCatalog {
    /// For use during development: returns the debug plugins
    pub fn debug() -> Self {
        PluginCatalog::new(&debug_plugins())
    }

    pub fn new(plugins: &[PluginDescription]) -> Self {
        let mut items = HashMap::with_capacity(plugins.len());
        for plugin in plugins {
            if items.contains_key(&plugin.name) {
                print_err!("Duplicate plugin name.\n 1: {:?}\n 2: {:?}",
                           plugin, items.get(&plugin.name));
                continue
            }
            items.insert(plugin.name.to_owned(), plugin.to_owned());
        }
        PluginCatalog { items }
    }

    /// Returns an iterator over all plugins in the catalog, in arbitrary order.
    pub fn iter(&'a self) -> Box<Iterator<Item=&'a PluginDescription> + 'a> {
       Box::new(self.items.values())
    }

    /// Returns an iterator over all plugin names in the catalog,
    /// in arbitrary order.
    pub fn iter_names(&'a self) -> Box<Iterator<Item=&'a PluginName> + 'a> {
        Box::new(self.items.keys())
    }

    /// Returns a reference to the named plugin if it exists in the catalog.
    pub fn get_named(&self, plugin_name: &str) -> Option<&PluginDescription> {
        self.items.get(plugin_name)
    }

    /// Returns all PluginDescriptions matching some predicate
    pub fn filter<F>(&self, predicate: F) -> Vec<&PluginDescription>
    where F: Fn(&PluginDescription) -> bool {
        self.iter()
            .filter(|item| predicate(item))
            .collect::<Vec<_>>()
    }
}
<|endoftext|>


<commit_before>use crate::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground};
use crate::rustc_span::edition::Edition;
use std::fs;
use std::path::Path;
use std::str;

use serde::Serialize;

#[derive(Clone, Debug, Serialize)]
crate struct ExternalHtml {
    /// Content that will be included inline in the <head> section of a
    /// rendered Markdown file or generated documentation
    crate in_header: String,
    /// Content that will be included inline between <body> and the content of
    /// a rendered Markdown file or generated documentation
    crate before_content: String,
    /// Content that will be included inline between the content and </body> of
    /// a rendered Markdown file or generated documentation
    crate after_content: String,
}

impl ExternalHtml {
    crate fn load(
        in_header: &[String],
        before_content: &[String],
        after_content: &[String],
        md_before_content: &[String],
        md_after_content: &[String],
        nightly_build: bool,
        diag: &rustc_errors::Handler,
        id_map: &mut IdMap,
        edition: Edition,
        playground: &Option<Playground>,
    ) -> Option<ExternalHtml> {
        let codes = ErrorCodes::from(nightly_build);
        let ih = load_external_files(in_header, diag)?;
        let bc = load_external_files(before_content, diag)?;
        let m_bc = load_external_files(md_before_content, diag)?;
        let bc = format!(
            "{}{}",
            bc,
            Markdown {
                content: &m_bc,
                links: &[],
                ids: id_map,
                error_codes: codes,
                edition,
                playground,
                heading_offset: HeadingOffset::H2,
            }
            .into_string()
        );
        let ac = load_external_files(after_content, diag)?;
        let m_ac = load_external_files(md_after_content, diag)?;
        let ac = format!(
            "{}{}",
            ac,
            Markdown {
                content: &m_ac,
                links: &[],
                ids: id_map,
                error_codes: codes,
                edition,
                playground,
                heading_offset: HeadingOffset::H2,
            }
            .into_string()
        );
        Some(ExternalHtml { in_header: ih, before_content: bc, after_content: ac })
    }
}

crate enum LoadStringError {
    ReadFail,
    BadUtf8,
}

crate fn load_string<P: AsRef<Path>>(
    file_path: P,
    diag: &rustc_errors::Handler,
) -> Result<String, LoadStringError> {
    let file_path = file_path.as_ref();
    let contents = match fs::read(file_path) {
        Ok(bytes) => bytes,
        Err(e) => {
            diag.struct_err(&format!("error reading `{}`: {}", file_path.display(), e)).emit();
            return Err(LoadStringError::ReadFail);
        }
    };
    match str::from_utf8(&contents) {
        Ok(s) => Ok(s.to_string()),
        Err(_) => {
            diag.struct_err(&format!("error reading `{}`: not UTF-8", file_path.display())).emit();
            Err(LoadStringError::BadUtf8)
        }
    }
}

fn load_external_files(names: &[String], diag: &rustc_errors::Handler) -> Option<String> {
    let mut out = String::new();
    for name in names {
        let s = match load_string(name, diag) {
            Ok(s) => s,
            Err(_) => return None,
        };
        out.push_str(&s);
        out.push('\n');
    }
    Some(out)
}
<commit_msg>Rollup merge of #91054 - camelid:fix-tags, r=GuillaumeGomez<commit_after>use crate::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground};
use crate::rustc_span::edition::Edition;
use std::fs;
use std::path::Path;
use std::str;

use serde::Serialize;

#[derive(Clone, Debug, Serialize)]
crate struct ExternalHtml {
    /// Content that will be included inline in the `<head>` section of a
    /// rendered Markdown file or generated documentation
    crate in_header: String,
    /// Content that will be included inline between `<body>` and the content of
    /// a rendered Markdown file or generated documentation
    crate before_content: String,
    /// Content that will be included inline between the content and `</body>` of
    /// a rendered Markdown file or generated documentation
    crate after_content: String,
}

impl ExternalHtml {
    crate fn load(
        in_header: &[String],
        before_content: &[String],
        after_content: &[String],
        md_before_content: &[String],
        md_after_content: &[String],
        nightly_build: bool,
        diag: &rustc_errors::Handler,
        id_map: &mut IdMap,
        edition: Edition,
        playground: &Option<Playground>,
    ) -> Option<ExternalHtml> {
        let codes = ErrorCodes::from(nightly_build);
        let ih = load_external_files(in_header, diag)?;
        let bc = load_external_files(before_content, diag)?;
        let m_bc = load_external_files(md_before_content, diag)?;
        let bc = format!(
            "{}{}",
            bc,
            Markdown {
                content: &m_bc,
                links: &[],
                ids: id_map,
                error_codes: codes,
                edition,
                playground,
                heading_offset: HeadingOffset::H2,
            }
            .into_string()
        );
        let ac = load_external_files(after_content, diag)?;
        let m_ac = load_external_files(md_after_content, diag)?;
        let ac = format!(
            "{}{}",
            ac,
            Markdown {
                content: &m_ac,
                links: &[],
                ids: id_map,
                error_codes: codes,
                edition,
                playground,
                heading_offset: HeadingOffset::H2,
            }
            .into_string()
        );
        Some(ExternalHtml { in_header: ih, before_content: bc, after_content: ac })
    }
}

crate enum LoadStringError {
    ReadFail,
    BadUtf8,
}

crate fn load_string<P: AsRef<Path>>(
    file_path: P,
    diag: &rustc_errors::Handler,
) -> Result<String, LoadStringError> {
    let file_path = file_path.as_ref();
    let contents = match fs::read(file_path) {
        Ok(bytes) => bytes,
        Err(e) => {
            diag.struct_err(&format!("error reading `{}`: {}", file_path.display(), e)).emit();
            return Err(LoadStringError::ReadFail);
        }
    };
    match str::from_utf8(&contents) {
        Ok(s) => Ok(s.to_string()),
        Err(_) => {
            diag.struct_err(&format!("error reading `{}`: not UTF-8", file_path.display())).emit();
            Err(LoadStringError::BadUtf8)
        }
    }
}

fn load_external_files(names: &[String], diag: &rustc_errors::Handler) -> Option<String> {
    let mut out = String::new();
    for name in names {
        let s = match load_string(name, diag) {
            Ok(s) => s,
            Err(_) => return None,
        };
        out.push_str(&s);
        out.push('\n');
    }
    Some(out)
}
<|endoftext|>


<commit_before>//! Manager for wl_shell clients.

use libc;
use wayland_sys::server::signal::wl_signal_add;
use wlroots_sys::wlr_wl_shell_surface;

use super::wl_shell_handler::WlShell;
use {Surface, WlShellHandler, WlShellSurface};
use compositor::{Compositor, COMPOSITOR_PTR};

/// Handles making new Wayland shells as reported by clients.
pub trait WlShellManagerHandler {
    /// Callback that is triggerde when a new wayland shell surface appears.
    fn new_surface(&mut self,
                   &mut Compositor,
                   &mut WlShellSurface,
                   &mut Surface)
                   -> Option<Box<WlShellHandler>>;
}

wayland_listener!(WlShellManager, Box<WlShellManagerHandler>, [
    add_listener => add_notify: |this: &mut WlShellManager, data: *mut libc::c_void,| unsafe {
        let manager = &mut this.data;
        let data = data as *mut wlr_wl_shell_surface;
        wlr_log!(L_DEBUG, "New wl_shell_surface request {:p}", data);
        let compositor = &mut *COMPOSITOR_PTR;
        let mut surface = Surface::from_ptr((*data).surface);
        let mut shell_surface = WlShellSurface::new(data);
        let new_surface_res = manager.new_surface(compositor, &mut shell_surface, &mut surface);
        if let Some(shell_surface_handler) = new_surface_res {
            let mut shell_surface = WlShell::new((shell_surface, surface, shell_surface_handler));
            // Add the destroy event to this handler.
            wl_signal_add(&mut (*data).events.destroy as *mut _ as _,
                          shell_surface.destroy_listener() as _);

            // Add the ping timeout event to this handler.
            wl_signal_add(&mut (*data).events.ping_timeout as *mut _ as _,
                          shell_surface.ping_timeout_listener() as _);

            // Add the move request event to this handler.
            wl_signal_add(&mut (*data).events.request_move as *mut _ as _,
                          shell_surface.request_move_listener() as _);

            // Add the resize request event to this handler.
            wl_signal_add(&mut (*data).events.request_resize as *mut _ as _,
                          shell_surface.request_resize_listener() as _);

            // Add the fullscreen request event to this handler.
            wl_signal_add(&mut (*data).events.request_fullscreen as *mut _ as _,
                          shell_surface.request_fullscreen_listener() as _);

            // Add the maximize request event to this handler.
            wl_signal_add(&mut (*data).events.request_maximize as *mut _ as _,
                          shell_surface.request_maximize_listener() as _);

            // Add the set state request event to this handler.
            wl_signal_add(&mut (*data).events.set_state as *mut _ as _,
                          shell_surface.set_state_listener() as _);

            // Add the set title request event to this handler.
            wl_signal_add(&mut (*data).events.set_title as *mut _ as _,
                          shell_surface.set_title_listener() as _);

            // Add the set class request event to this handler.
            wl_signal_add(&mut (*data).events.set_class as *mut _ as _,
                          shell_surface.set_class_listener() as _);

            // NOTE This is cleaned up in the wl_shell_handler::destroy signal.
            ::std::mem::forget(shell_surface);
        }
    };
]);
<commit_msg>Added locking to wl_shell_manager creation<commit_after>//! Manager for wl_shell clients.

use libc;
use wayland_sys::server::signal::wl_signal_add;
use wlroots_sys::wlr_wl_shell_surface;

use super::wl_shell_handler::WlShell;
use {Surface, WlShellHandler, WlShellSurface};
use compositor::{Compositor, COMPOSITOR_PTR};

/// Handles making new Wayland shells as reported by clients.
pub trait WlShellManagerHandler {
    /// Callback that is triggerde when a new wayland shell surface appears.
    fn new_surface(&mut self,
                   &mut Compositor,
                   &mut WlShellSurface,
                   &mut Surface)
                   -> Option<Box<WlShellHandler>>;
}

wayland_listener!(WlShellManager, Box<WlShellManagerHandler>, [
    add_listener => add_notify: |this: &mut WlShellManager, data: *mut libc::c_void,| unsafe {
        let manager = &mut this.data;
        let data = data as *mut wlr_wl_shell_surface;
        wlr_log!(L_DEBUG, "New wl_shell_surface request {:p}", data);
        let compositor = &mut *COMPOSITOR_PTR;
        let mut surface = Surface::from_ptr((*data).surface);
        let mut shell_surface = WlShellSurface::new(data);
        surface.set_lock(true);
        shell_surface.set_lock(true);
        let new_surface_res = manager.new_surface(compositor, &mut shell_surface, &mut surface);
        surface.set_lock(false);
        shell_surface.set_lock(false);
        if let Some(shell_surface_handler) = new_surface_res {
            let mut shell_surface = WlShell::new((shell_surface, surface, shell_surface_handler));
            // Add the destroy event to this handler.
            wl_signal_add(&mut (*data).events.destroy as *mut _ as _,
                          shell_surface.destroy_listener() as _);

            // Add the ping timeout event to this handler.
            wl_signal_add(&mut (*data).events.ping_timeout as *mut _ as _,
                          shell_surface.ping_timeout_listener() as _);

            // Add the move request event to this handler.
            wl_signal_add(&mut (*data).events.request_move as *mut _ as _,
                          shell_surface.request_move_listener() as _);

            // Add the resize request event to this handler.
            wl_signal_add(&mut (*data).events.request_resize as *mut _ as _,
                          shell_surface.request_resize_listener() as _);

            // Add the fullscreen request event to this handler.
            wl_signal_add(&mut (*data).events.request_fullscreen as *mut _ as _,
                          shell_surface.request_fullscreen_listener() as _);

            // Add the maximize request event to this handler.
            wl_signal_add(&mut (*data).events.request_maximize as *mut _ as _,
                          shell_surface.request_maximize_listener() as _);

            // Add the set state request event to this handler.
            wl_signal_add(&mut (*data).events.set_state as *mut _ as _,
                          shell_surface.set_state_listener() as _);

            // Add the set title request event to this handler.
            wl_signal_add(&mut (*data).events.set_title as *mut _ as _,
                          shell_surface.set_title_listener() as _);

            // Add the set class request event to this handler.
            wl_signal_add(&mut (*data).events.set_class as *mut _ as _,
                          shell_surface.set_class_listener() as _);

            // NOTE This is cleaned up in the wl_shell_handler::destroy signal.
            ::std::mem::forget(shell_surface);
        }
    };
]);
<|endoftext|>