<commit_before>//! Empirical cumulative distribution function.

pub struct Ecdf<T: Ord> {
    samples: Vec<T>,
    length: usize,
}

impl<T: Ord + Clone> Ecdf<T> {
    /// Construct a new representation of a cumulative distribution function for
    /// a given sample.
    ///
    /// The construction will involve computing a sorted clone of the given sample
    /// and may be inefficient or completely prohibitive for large samples. This
    /// computation is amortized significantly if there is heavy use of the value
    /// function.
    ///
    /// # Panics
    ///
    /// The sample set must be non-empty.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate kolmogorov_smirnov as ks;
    ///
    /// let samples = vec!(9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
    /// let ecdf = ks::Ecdf::new(&samples);
    /// ```
    pub fn new(samples: &[T]) -> Ecdf<T> {
        let length = samples.len();
        assert!(length > 0);

        // Sort a copied sample for binary searching.
        let mut sorted = samples.to_vec();
        sorted.sort();

        Ecdf {
            samples: sorted,
            length: length,
        }
    }

    /// Calculate a value of the empirical cumulative distribution function for
    /// a given sample.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate kolmogorov_smirnov as ks;
    ///
    /// let samples = vec!(9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
    /// let ecdf = ks::Ecdf::new(&samples);
    /// println!("{}", ecdf.value(4));
    /// ```
    pub fn value(&self, t: T) -> f64 {
        let num_samples_leq_t = match self.samples.binary_search(&t) {
            Ok(mut index) => {
                // At least one sample is a t and we have the index of it. Need
                // to walk down the sorted samples until at last that == t.
                while index + 1 < self.length && self.samples[index + 1] == t {
                    index += 1;
                }

                // Compensate for 0-based indexing.
                index + 1
            }
            Err(index) => {
                // No sample is a t but if we had to put one in it would go at
                // index. This means all indices to the left have samples < t
                // and should be counted in the cdf proportion. We must take one
                // from index to get the last included sample but then we just
                // have to add one again to account for 0-based indexing.
                index
            }
        };

        num_samples_leq_t as f64 / self.length as f64
    }
}

/// Calculate a one-time value of the empirical cumulative distribution function
/// for a given sample.
///
/// Computational running time of this function is O(n) but does not amortize
/// across multiple calls like Ecdf<T>::value. This function should only be
/// used in the case that a small number of ECDF values are required for the
/// sample. Otherwise, Ecdf::new should be used to create a structure that
/// takes the upfront O(n log n) sort cost by calculates values in O(log n).
///
/// # Panics
///
/// The sample set must be non-empty.
///
/// # Examples
///
/// ```
/// extern crate kolmogorov_smirnov as ks;
///
/// let samples = vec!(9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
/// let value = ks::ecdf(&samples, 4);
/// println!("{}", value);
/// ```
pub fn ecdf<T: Ord>(samples: &[T], t: T) -> f64 {
    let mut num_samples_leq_t = 0;
    let mut length = 0;

    for sample in samples.iter() {
        length += 1;
        if *sample <= t {
            num_samples_leq_t += 1;
        }
    }

    assert!(length > 0);

    num_samples_leq_t as f64 / length as f64
}

#[cfg(test)]
mod tests {
    extern crate quickcheck;
    extern crate rand;

    use self::quickcheck::{Arbitrary, Gen, QuickCheck, Testable, TestResult, StdGen};
    use std::cmp;
    use std::usize;
    use super::{Ecdf, ecdf};

    fn check<A: Testable>(f: A) {
        let g = StdGen::new(rand::thread_rng(), usize::MAX);
        QuickCheck::new().gen(g).quickcheck(f);
    }

    /// Wrapper for generating sample data with QuickCheck.
    ///
    /// Samples must be non-empty sequences of u64 values.
    #[derive(Debug, Clone)]
    struct Samples {
        vec: Vec<u64>,
    }

    impl Arbitrary for Samples {
        fn arbitrary<G: Gen>(g: &mut G) -> Samples {
            // Limit size of generated sample set to 1024
            let max = cmp::min(g.size(), 1024);

            let size = g.gen_range(1, max);
            let vec = (0..size).map(|_| u64::arbitrary(g)).collect();

            Samples { vec: vec }
        }

        fn shrink(&self) -> Box<Iterator<Item = Samples>> {
            let vec: Vec<u64> = self.vec.clone();
            let shrunk: Box<Iterator<Item = Vec<u64>>> = vec.shrink();

            Box::new(shrunk.filter(|v| v.len() > 0).map(|v| Samples { vec: v }))
        }
    }

    #[test]
    #[should_panic(expected="assertion failed: length > 0")]
    fn single_use_ecdf_panics_on_empty_samples_set() {
        let xs: Vec<u64> = vec![];
        ecdf(&xs, 0);
    }

    #[test]
    #[should_panic(expected="assertion failed: length > 0")]
    fn multiple_use_ecdf_panics_on_empty_samples_set() {
        let xs: Vec<u64> = vec![];
        Ecdf::new(&xs);
    }

    #[test]
    fn single_use_ecdf_between_zero_and_one() {
        fn prop(xs: Samples, val: u64) -> bool {
            let actual = ecdf(&xs.vec, val);

            0.0 <= actual && actual <= 1.0
        }

        check(prop as fn(Samples, u64) -> bool);
    }

    #[test]
    fn multiple_use_ecdf_between_zero_and_one() {
        fn prop(xs: Samples, val: u64) -> bool {
            let ecdf = Ecdf::new(&xs.vec);
            let actual = ecdf.value(val);

            0.0 <= actual && actual <= 1.0
        }

        check(prop as fn(Samples, u64) -> bool);
    }

    #[test]
    fn single_use_ecdf_is_an_increasing_function() {
        fn prop(xs: Samples, val: u64) -> bool {
            let actual = ecdf(&xs.vec, val);

            ecdf(&xs.vec, val - 1) <= actual && actual <= ecdf(&xs.vec, val + 1)
        }

        check(prop as fn(Samples, u64) -> bool);
    }

    #[test]
    fn multiple_use_ecdf_is_an_increasing_function() {
        fn prop(xs: Samples, val: u64) -> bool {
            let ecdf = Ecdf::new(&xs.vec);
            let actual = ecdf.value(val);

            ecdf.value(val - 1) <= actual && actual <= ecdf.value(val + 1)
        }

        check(prop as fn(Samples, u64) -> bool);
    }

    #[test]
    fn single_use_ecdf_sample_min_minus_one_is_zero() {
        fn prop(xs: Samples) -> bool {
            let &min = xs.vec.iter().min().unwrap();

            ecdf(&xs.vec, min - 1) == 0.0
        }

        check(prop as fn(Samples) -> bool);
    }

    #[test]
    fn multiple_use_ecdf_sample_min_minus_one_is_zero() {
        fn prop(xs: Samples) -> bool {
            let &min = xs.vec.iter().min().unwrap();
            let ecdf = Ecdf::new(&xs.vec);

            ecdf.value(min - 1) == 0.0
        }

        check(prop as fn(Samples) -> bool);
    }

    #[test]
    fn single_use_ecdf_sample_max_is_one() {
        fn prop(xs: Samples) -> bool {
            let &max = xs.vec.iter().max().unwrap();

            ecdf(&xs.vec, max) == 1.0
        }

        check(prop as fn(Samples) -> bool);
    }

    #[test]
    fn multiple_use_ecdf_sample_max_is_one() {
        fn prop(xs: Samples) -> bool {
            let &max = xs.vec.iter().max().unwrap();
            let ecdf = Ecdf::new(&xs.vec);

            ecdf.value(max) == 1.0
        }

        check(prop as fn(Samples) -> bool);
    }

    #[test]
    fn single_use_ecdf_sample_val_is_num_samples_leq_val_div_length() {
        fn prop(xs: Samples) -> bool {
            let &val = xs.vec.first().unwrap();
            let num_samples = xs.vec
                                .iter()
                                .filter(|&&x| x <= val)
                                .count();
            let expected = num_samples as f64 / xs.vec.len() as f64;

            ecdf(&xs.vec, val) == expected
        }

        check(prop as fn(Samples) -> bool);
    }

    #[test]
    fn multiple_use_ecdf_sample_val_is_num_samples_leq_val_div_length() {
        fn prop(xs: Samples) -> bool {
            let &val = xs.vec.first().unwrap();
            let num_samples = xs.vec
                                .iter()
                                .filter(|&&x| x <= val)
                                .count();
            let expected = num_samples as f64 / xs.vec.len() as f64;

            let ecdf = Ecdf::new(&xs.vec);

            ecdf.value(val) == expected
        }

        check(prop as fn(Samples) -> bool);
    }

    #[test]
    fn single_use_ecdf_non_sample_val_is_num_samples_leq_val_div_length() {
        fn prop(xs: Samples, val: u64) -> TestResult {
            let length = xs.vec.len();

            if xs.vec.iter().any(|&x| x == val) {
                // Discard Vec containing val.
                return TestResult::discard();
            }

            let num_samples = xs.vec
                                .iter()
                                .filter(|&&x| x <= val)
                                .count();
            let expected = num_samples as f64 / length as f64;

            let actual = ecdf(&xs.vec, val);

            TestResult::from_bool(actual == expected)
        }

        check(prop as fn(Samples, u64) -> TestResult);
    }

    #[test]
    fn multiple_use_ecdf_non_sample_val_is_num_samples_leq_val_div_length() {
        fn prop(xs: Samples, val: u64) -> TestResult {
            let length = xs.vec.len();

            if xs.vec.iter().any(|&x| x == val) {
                // Discard Vec containing val.
                return TestResult::discard();
            }

            let num_samples = xs.vec
                                .iter()
                                .filter(|&&x| x <= val)
                                .count();
            let expected = num_samples as f64 / length as f64;

            let ecdf = Ecdf::new(&xs.vec);

            TestResult::from_bool(ecdf.value(val) == expected)
        }

        check(prop as fn(Samples, u64) -> TestResult);
    }

    #[test]
    fn single_and_multiple_use_ecdf_agree() {
        fn prop(xs: Samples, val: u64) -> bool {
            let multiple_use = Ecdf::new(&xs.vec);

            multiple_use.value(val) == ecdf(&xs.vec, val)
        }

        check(prop as fn(Samples, u64) -> bool);
    }
}
<commit_msg>Include percentile function for calculated ECDFs.<commit_after>//! Empirical cumulative distribution function.

pub struct Ecdf<T: Ord> {
    samples: Vec<T>,
    length: usize,
}

impl<T: Ord + Clone> Ecdf<T> {
    /// Construct a new representation of a cumulative distribution function for
    /// a given sample.
    ///
    /// The construction will involve computing a sorted clone of the given sample
    /// and may be inefficient or completely prohibitive for large samples. This
    /// computation is amortized significantly if there is heavy use of the value
    /// function.
    ///
    /// # Panics
    ///
    /// The sample set must be non-empty.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate kolmogorov_smirnov as ks;
    ///
    /// let samples = vec!(9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
    /// let ecdf = ks::Ecdf::new(&samples);
    /// ```
    pub fn new(samples: &[T]) -> Ecdf<T> {
        let length = samples.len();
        assert!(length > 0);

        // Sort a copied sample for binary searching.
        let mut sorted = samples.to_vec();
        sorted.sort();

        Ecdf {
            samples: sorted,
            length: length,
        }
    }

    /// Calculate a value of the empirical cumulative distribution function for
    /// a given sample.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate kolmogorov_smirnov as ks;
    ///
    /// let samples = vec!(9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
    /// let ecdf = ks::Ecdf::new(&samples);
    /// println!("{}", ecdf.value(4));
    /// ```
    pub fn value(&self, t: T) -> f64 {
        let num_samples_leq_t = match self.samples.binary_search(&t) {
            Ok(mut index) => {
                // At least one sample is a t and we have the index of it. Need
                // to walk down the sorted samples until at last that == t.
                while index + 1 < self.length && self.samples[index + 1] == t {
                    index += 1;
                }

                // Compensate for 0-based indexing.
                index + 1
            }
            Err(index) => {
                // No sample is a t but if we had to put one in it would go at
                // index. This means all indices to the left have samples < t
                // and should be counted in the cdf proportion. We must take one
                // from index to get the last included sample but then we just
                // have to add one again to account for 0-based indexing.
                index
            }
        };

        num_samples_leq_t as f64 / self.length as f64
    }

    /// Calculate a percentile for the sample using the Nearest Rank method.
    ///
    /// # Panics
    ///
    /// The percentile requested must be between than 1 and 100 inclusive. In
    /// particular, there is no 0-percentile.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate kolmogorov_smirnov as ks;
    ///
    /// let samples = vec!(9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
    /// let ecdf = ks::Ecdf::new(&samples);
    /// println!("{}", ecdf.percentile(50));
    /// ```
    pub fn percentile(&self, p: u8) -> T {
        assert!(0 < p && p <= 100);

        let rank = (p as f64 * self.length as f64 / 100.0).ceil() as usize;
        self.samples[rank - 1].clone()
    }
}

/// Calculate a one-time value of the empirical cumulative distribution function
/// for a given sample.
///
/// Computational running time of this function is O(n) but does not amortize
/// across multiple calls like Ecdf<T>::value. This function should only be
/// used in the case that a small number of ECDF values are required for the
/// sample. Otherwise, Ecdf::new should be used to create a structure that
/// takes the upfront O(n log n) sort cost by calculates values in O(log n).
///
/// # Panics
///
/// The sample set must be non-empty.
///
/// # Examples
///
/// ```
/// extern crate kolmogorov_smirnov as ks;
///
/// let samples = vec!(9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
/// let value = ks::ecdf(&samples, 4);
/// println!("{}", value);
/// ```
pub fn ecdf<T: Ord>(samples: &[T], t: T) -> f64 {
    let mut num_samples_leq_t = 0;
    let mut length = 0;

    for sample in samples.iter() {
        length += 1;
        if *sample <= t {
            num_samples_leq_t += 1;
        }
    }

    assert!(length > 0);

    num_samples_leq_t as f64 / length as f64
}

#[cfg(test)]
mod tests {
    extern crate quickcheck;
    extern crate rand;

    use self::quickcheck::{Arbitrary, Gen, QuickCheck, Testable, TestResult, StdGen};
    use std::cmp;
    use std::usize;
    use super::{Ecdf, ecdf};

    fn check<A: Testable>(f: A) {
        let g = StdGen::new(rand::thread_rng(), usize::MAX);
        QuickCheck::new().gen(g).quickcheck(f);
    }

    /// Wrapper for generating sample data with QuickCheck.
    ///
    /// Samples must be non-empty sequences of u64 values.
    #[derive(Debug, Clone)]
    struct Samples {
        vec: Vec<u64>,
    }

    impl Arbitrary for Samples {
        fn arbitrary<G: Gen>(g: &mut G) -> Samples {
            // Limit size of generated sample set to 1024
            let max = cmp::min(g.size(), 1024);

            let size = g.gen_range(1, max);
            let vec = (0..size).map(|_| u64::arbitrary(g)).collect();

            Samples { vec: vec }
        }

        fn shrink(&self) -> Box<Iterator<Item = Samples>> {
            let vec: Vec<u64> = self.vec.clone();
            let shrunk: Box<Iterator<Item = Vec<u64>>> = vec.shrink();

            Box::new(shrunk.filter(|v| v.len() > 0).map(|v| Samples { vec: v }))
        }
    }

    /// Wrapper for generating percentile query value data with QuickCheck.
    ///
    /// Percentile must be u8 between 1 and 100 inclusive.
    #[derive(Debug, Clone)]
    struct Percentile {
        val: u8,
    }

    impl Arbitrary for Percentile {
        fn arbitrary<G: Gen>(g: &mut G) -> Percentile {
            let val = g.gen_range(1, 101) as u8;

            Percentile { val: val }
        }

        fn shrink(&self) -> Box<Iterator<Item = Percentile>> {
            let shrunk: Box<Iterator<Item = u8>> = self.val.shrink();

            Box::new(shrunk.filter(|&v| 0u8 < v && v <= 100u8).map(|v| Percentile { val: v }))
        }
    }

    #[test]
    #[should_panic(expected="assertion failed: length > 0")]
    fn single_use_ecdf_panics_on_empty_samples_set() {
        let xs: Vec<u64> = vec![];
        ecdf(&xs, 0);
    }

    #[test]
    #[should_panic(expected="assertion failed: length > 0")]
    fn multiple_use_ecdf_panics_on_empty_samples_set() {
        let xs: Vec<u64> = vec![];
        Ecdf::new(&xs);
    }

    #[test]
    fn single_use_ecdf_between_zero_and_one() {
        fn prop(xs: Samples, val: u64) -> bool {
            let actual = ecdf(&xs.vec, val);

            0.0 <= actual && actual <= 1.0
        }

        check(prop as fn(Samples, u64) -> bool);
    }

    #[test]
    fn multiple_use_ecdf_between_zero_and_one() {
        fn prop(xs: Samples, val: u64) -> bool {
            let ecdf = Ecdf::new(&xs.vec);
            let actual = ecdf.value(val);

            0.0 <= actual && actual <= 1.0
        }

        check(prop as fn(Samples, u64) -> bool);
    }

    #[test]
    fn single_use_ecdf_is_an_increasing_function() {
        fn prop(xs: Samples, val: u64) -> bool {
            let actual = ecdf(&xs.vec, val);

            ecdf(&xs.vec, val - 1) <= actual && actual <= ecdf(&xs.vec, val + 1)
        }

        check(prop as fn(Samples, u64) -> bool);
    }

    #[test]
    fn multiple_use_ecdf_is_an_increasing_function() {
        fn prop(xs: Samples, val: u64) -> bool {
            let ecdf = Ecdf::new(&xs.vec);
            let actual = ecdf.value(val);

            ecdf.value(val - 1) <= actual && actual <= ecdf.value(val + 1)
        }

        check(prop as fn(Samples, u64) -> bool);
    }

    #[test]
    fn single_use_ecdf_sample_min_minus_one_is_zero() {
        fn prop(xs: Samples) -> bool {
            let &min = xs.vec.iter().min().unwrap();

            ecdf(&xs.vec, min - 1) == 0.0
        }

        check(prop as fn(Samples) -> bool);
    }

    #[test]
    fn multiple_use_ecdf_sample_min_minus_one_is_zero() {
        fn prop(xs: Samples) -> bool {
            let &min = xs.vec.iter().min().unwrap();
            let ecdf = Ecdf::new(&xs.vec);

            ecdf.value(min - 1) == 0.0
        }

        check(prop as fn(Samples) -> bool);
    }

    #[test]
    fn single_use_ecdf_sample_max_is_one() {
        fn prop(xs: Samples) -> bool {
            let &max = xs.vec.iter().max().unwrap();

            ecdf(&xs.vec, max) == 1.0
        }

        check(prop as fn(Samples) -> bool);
    }

    #[test]
    fn multiple_use_ecdf_sample_max_is_one() {
        fn prop(xs: Samples) -> bool {
            let &max = xs.vec.iter().max().unwrap();
            let ecdf = Ecdf::new(&xs.vec);

            ecdf.value(max) == 1.0
        }

        check(prop as fn(Samples) -> bool);
    }

    #[test]
    fn single_use_ecdf_sample_val_is_num_samples_leq_val_div_length() {
        fn prop(xs: Samples) -> bool {
            let &val = xs.vec.first().unwrap();
            let num_samples = xs.vec
                                .iter()
                                .filter(|&&x| x <= val)
                                .count();
            let expected = num_samples as f64 / xs.vec.len() as f64;

            ecdf(&xs.vec, val) == expected
        }

        check(prop as fn(Samples) -> bool);
    }

    #[test]
    fn multiple_use_ecdf_sample_val_is_num_samples_leq_val_div_length() {
        fn prop(xs: Samples) -> bool {
            let &val = xs.vec.first().unwrap();
            let num_samples = xs.vec
                                .iter()
                                .filter(|&&x| x <= val)
                                .count();
            let expected = num_samples as f64 / xs.vec.len() as f64;

            let ecdf = Ecdf::new(&xs.vec);

            ecdf.value(val) == expected
        }

        check(prop as fn(Samples) -> bool);
    }

    #[test]
    fn single_use_ecdf_non_sample_val_is_num_samples_leq_val_div_length() {
        fn prop(xs: Samples, val: u64) -> TestResult {
            let length = xs.vec.len();

            if xs.vec.iter().any(|&x| x == val) {
                // Discard Vec containing val.
                return TestResult::discard();
            }

            let num_samples = xs.vec
                                .iter()
                                .filter(|&&x| x <= val)
                                .count();
            let expected = num_samples as f64 / length as f64;

            let actual = ecdf(&xs.vec, val);

            TestResult::from_bool(actual == expected)
        }

        check(prop as fn(Samples, u64) -> TestResult);
    }

    #[test]
    fn multiple_use_ecdf_non_sample_val_is_num_samples_leq_val_div_length() {
        fn prop(xs: Samples, val: u64) -> TestResult {
            let length = xs.vec.len();

            if xs.vec.iter().any(|&x| x == val) {
                // Discard Vec containing val.
                return TestResult::discard();
            }

            let num_samples = xs.vec
                                .iter()
                                .filter(|&&x| x <= val)
                                .count();
            let expected = num_samples as f64 / length as f64;

            let ecdf = Ecdf::new(&xs.vec);

            TestResult::from_bool(ecdf.value(val) == expected)
        }

        check(prop as fn(Samples, u64) -> TestResult);
    }

    #[test]
    fn single_and_multiple_use_ecdf_agree() {
        fn prop(xs: Samples, val: u64) -> bool {
            let multiple_use = Ecdf::new(&xs.vec);

            multiple_use.value(val) == ecdf(&xs.vec, val)
        }

        check(prop as fn(Samples, u64) -> bool);
    }

    #[test]
    #[should_panic(expected="assertion failed: 0 < p && p <= 100")]
    fn multiple_use_percentiles_panics_on_zero_percentile() {
        let xs: Vec<u64> = vec![0];
        let ecdf = Ecdf::new(&xs);

        ecdf.percentile(0);
    }

    #[test]
    #[should_panic(expected="assertion failed: 0 < p && p <= 100")]
    fn multiple_use_percentiles_panics_on_101_percentile() {
        let xs: Vec<u64> = vec![0];
        let ecdf = Ecdf::new(&xs);

        ecdf.percentile(101);
    }

    #[test]
    fn multiple_use_percentile_between_samples_min_and_max() {
        fn prop(xs: Samples, percentile: Percentile) -> bool {
            let &min = xs.vec.iter().min().unwrap();
            let &max = xs.vec.iter().max().unwrap();

            let ecdf = Ecdf::new(&xs.vec);
            let actual = ecdf.percentile(percentile.val);

            min <= actual && actual <= max
        }

        check(prop as fn(Samples, Percentile) -> bool);
    }

    #[test]
    fn multiple_use_percentile_is_an_increasing_function() {
        fn prop(xs: Samples, percentile: Percentile) -> bool {
            let smaller = cmp::max(percentile.val - 1, 1);
            let larger = cmp::min(percentile.val + 1, 100);

            let ecdf = Ecdf::new(&xs.vec);
            let actual = ecdf.percentile(percentile.val);

            ecdf.percentile(smaller) <= actual && actual <= ecdf.percentile(larger)
        }

        check(prop as fn(Samples, Percentile) -> bool);
    }

    #[test]
    fn multiple_use_percentile_100_is_sample_max() {
        fn prop(xs: Samples) -> bool {
            let &max = xs.vec.iter().max().unwrap();
            let ecdf = Ecdf::new(&xs.vec);

            ecdf.percentile(100) == max
        }

        check(prop as fn(Samples) -> bool);
    }

    #[test]
    fn single_use_ecdf_followed_by_multiple_use_percentile_is_leq_original_value() {
        fn prop(xs: Samples, val: u64) -> TestResult {
            let actual = ecdf(&xs.vec, val);

            let percentile = (actual * 100.0).floor() as u8;

            match percentile {
                0 => {
                    // val is below the first percentile threshold. Can't
                    // calculate 0-percentile value so discard.
                    TestResult::discard()
                }
                _ => {
                    // Not equal because e.g. all percentiles of [0] are 0. So
                    // value of 1 gives ecdf == 1.0 and percentile(100) == 0.
                    let multiple_use = Ecdf::new(&xs.vec);
                    TestResult::from_bool(multiple_use.percentile(percentile) <= val)
                }
            }
        }

        check(prop as fn(Samples, u64) -> TestResult);
    }

    #[test]
    fn multiple_use_ecdf_followed_by_multiple_use_percentile_is_leq_original_value() {
        fn prop(xs: Samples, val: u64) -> TestResult {
            let ecdf = Ecdf::new(&xs.vec);
            let actual = ecdf.value(val);

            let percentile = (actual * 100.0).floor() as u8;

            match percentile {
                0 => {
                    // val is below the first percentile threshold. Can't
                    // calculate 0-percentile value so discard.
                    TestResult::discard()
                }
                _ => {
                    // Not equal because e.g. all percentiles of [0] are 0. So
                    // value of 1 gives ecdf == 1.0 and percentile(100) == 0.
                    TestResult::from_bool(ecdf.percentile(percentile) <= val)
                }
            }
        }

        check(prop as fn(Samples, u64) -> TestResult);
    }

    #[test]
    fn multiple_use_percentile_followed_by_single_use_edf_is_geq_original_value() {
        fn prop(xs: Samples, percentile: Percentile) -> bool {
            let multiple_use = Ecdf::new(&xs.vec);
            let actual = multiple_use.percentile(percentile.val);

            // Not equal because e.g. 1- through 50-percentiles of [0, 1] are 0.
            // So original value of 1 gives percentile == 0 and ecdf(0) == 0.5.
            percentile.val as f64 / 100.0 <= ecdf(&xs.vec, actual)
        }

        check(prop as fn(Samples, Percentile) -> bool);
    }

    #[test]
    fn multiple_use_percentile_followed_by_multiple_use_edf_is_geq_original_value() {
        fn prop(xs: Samples, percentile: Percentile) -> bool {
            let ecdf = Ecdf::new(&xs.vec);
            let actual = ecdf.percentile(percentile.val);

            // Not equal because e.g. 1- through 50-percentiles of [0, 1] are 0.
            // So original value of 1 gives percentile == 0 and ecdf(0) == 0.5.
            percentile.val as f64 / 100.0 <= ecdf.value(actual)
        }

        check(prop as fn(Samples, Percentile) -> bool);
    }
}
<|endoftext|>


<commit_before>use name::*;
use art::*;
use std::hash;
use std::hash::Hash;

/// Nominal, artful lists: Lists with names and articulation points
#[derive(Show,Hash,PartialEq,Eq)]
pub enum List<'x,T> {
    Nil,
    Cons(T, Box<List<'x,T>>),
    Name(Name, Box<List<'x,T>>),
    Art(Art<'x, Box<List<'x,T>>>)
}

pub fn copy<'x,T:'x>(list:List<'x,T>) -> List<'x,T> {
    match list {
        List::Nil         => List::Nil,
        List::Cons(hd,tl) => List::Cons(hd, box copy(*tl)),
        List::Art(art)    => copy(*force(art)),
        List::Name(nm,tl) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box copy(*tl)) ;
            List::Name(nm2, box List::Art(art))
        }
    }
}

pub fn map<'x, T:'x, S:'x>
(f:UAr<'x,T,S>, list:List<'x,T>) -> List<'x,S>
{
    match list {
        List::Nil         => List::Nil,
        List::Cons(hd,tl) => List::Cons((*f).call(hd), box map(f,*tl)),
        // - - - - - boilerplate cases - - - - - -
        List::Art(art)    => map(f,*force(art)),
        List::Name(nm,tl) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box map(f,*tl));
            List::Name(nm2, box List::Art(art))
        }
    }
}

pub fn contract<'x,F,G,T:'x>
(f:&'x F, g:&'x G, list:List<'x,T>) -> List<'x,T>
where F:Fn(&T,&T) -> bool + 'x,
      G:Fn(T,T) -> T + 'x
{
    match list {
        List::Nil => List::Nil,
        List::Cons(hd1, box list) => {
            match list {
                List::Nil => List::Cons(hd1, box List::Nil),
                List::Cons(hd2, tl) => {
                    if (*f)(&hd1,&hd2) {
                        List::Cons((*g)(hd1,hd2), box contract(f,g,*tl))
                    } else {
                        List::Cons(hd1, box contract(f, g, List::Cons(hd2, tl)))
                    } },
                // - - - - - boilerplate cases - - - - - -
                List::Art(art) => contract(f,g,List::Cons(hd1,force(art))),
                List::Name(nm, tl) => {
                    let (nm1,nm2) = fork(nm) ;
                    let art = nart!(nm1, box contract(f,g,List::Cons(hd1,tl))) ;
                    List::Name(nm2, box List::Art(art))
                }
            }
        },
        // - - - - - boilerplate cases - - - - - -
        List::Art(art)    => contract(f,g,*force(art)),
        List::Name(nm,tl) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box contract(f,g,*tl)) ;
            List::Name(nm2, box List::Art(art))
        },
    }
}

pub fn reduce<'x,F:'x,G:'x,T:'x>
(f:&'x F, g:&'x G, list:List<'x,T>) -> Option<T>
where F: Fn(&T,&T) -> bool,
      G: Fn(T, T) -> T,
{
    match list {
        List::Nil => None,
        List::Cons(hd, box list) => {
            match list {
                List::Nil => Some(hd),
                List::Cons(hd2, tl) => {
                    let hd3 = (*g)(hd,hd2) ;
                    let list = contract(f, g, List::Cons(hd3, tl)) ;
                    reduce (f, g, list)
                },
                // - - - - - boilerplate cases - - - - - -
                List::Name(_,tl) => reduce (f, g, *tl),
                List::Art(art)   => reduce (f, g, *force(art)),
            }},
        // - - - - - boilerplate cases - - - - - -
        List::Name(_,tl) => reduce(f, g, *tl),
        List::Art(art)   => reduce(f, g, *force(art)),
    }
}

pub fn merge<'x,T:'x,Ord:'x>
(ord:&'x Ord, list1:List<'x,T>, list2:List<'x,T>) -> List<'x,T>
where Ord: Fn(&T,&T) -> bool
{
    match (list1, list2) {
        (List::Nil, list2) => list2,
        (list1, List::Nil) => list1,
        (List::Cons(hd1,tl1),
         List::Cons(hd2,tl2)) =>
            if (*ord)(&hd1,&hd2) {
                List::Cons(hd1, box merge(ord, *tl1, List::Cons(hd2,tl2)))
            } else {
                List::Cons(hd2, box merge(ord, List::Cons(hd1,tl1), *tl2))
            },
        // - - - - - boilerplate cases - - - - -
        (List::Name(nm,tl), list2) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box merge(ord, *tl, list2)) ;
            List::Name(nm2, box List::Art(art))
        },
        (list1, List::Name(nm,tl)) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box merge(ord, list1, *tl)) ;
            List::Name(nm2, box List::Art(art))
        },
        (List::Art(art), list2) => merge(ord, *force(art), list2),
        (list1, List::Art(art)) => merge(ord, list1, *force(art)),
    }
}

pub fn singletons<'x,T:'x>
(list:List<'x,T>) -> List<'x,List<'x,T>>
{
    match list {
        List::Nil => List::Nil,
        List::Cons(hd, tl) => {
            List::Cons( List::Cons(hd, box List::Nil),
                        box singletons(*tl) )
        },
        List::Art(art) => singletons(*force(art)),
        List::Name(nm, tl) => {
            let (nm1, nm2) = fork(nm) ;
            let art = nart!(nm2, box singletons(*tl)) ;
            List::Name(nm1, box List::Art(art))
        }
    }
}

pub fn mergesort<'x,T:'x,Ord:'x>
(ord:&'x Ord, list:List<'x,T>) -> List<'x,T>
where Ord: Fn(&T,&T) -> bool, T:Hash
{
    let c = move |&: list1:&List<'x,T>,list2:&List<'x,T>|
    hash::hash(list1) < hash::hash(list2);

    let m = move |&: list1:List<'x,T>,list2:List<'x,T>|
    merge(ord,list1,list2);

    match reduce(&c, &m, singletons(list)) {
        None => List::Nil,
        Some(list) => list
    }
}

#[test]
pub fn construct_list () {
    let z : List<int> = List::Nil;
    let y : List<int> = List::Cons(1, box z);
    let x : List<int> = List::Art(cell(symbol(format!("two")), box y));
    let l : List<int> = List::Name(symbol(format!("one")), box x);
    println!("constructed list: {}", l);
}

// TODO: Rustup: Fix this:

 /// An iterator over the items in a list.
pub struct ListItems<'x, T: 'x> {
    list: &'x List<'x,T>
}

impl<'x,T> List<'x,T> {
    type Item = &'x T ;
    /// Get an iterator over the items in a list.
    pub fn iter(&'x self) -> ListItems<'x, T> {
        ListItems {
            list: self
        }
    }

}

impl<'x, T:'x> Iterator for ListItems<'x, T> {
    type Item = &'x T ;
    fn next(&mut self) -> Option<&'x T> {
        match *self.list {
            List::Cons(ref hd, ref tl) => {
                self.list = &**tl;
                Some(hd)
            },
            List::Name(_, ref list) => {
                self.list = &**list;
                self.next()
            },
            List::Art(ref art) => {
                self.list = &**force_ref(art);
                self.next()
            },
            List::Nil => None
        }
    }
}

pub enum NameOrContent<T> { Name(Name),Content(T) }

// pub fn clone_iter<'x, 'y, T:'y>
// (iter:&'x mut Iterator where ) -> List<'y,T>
// where T : Clone,

// {
//     match iter.next() {
//         None => List::Nil,
//         Some(x) => match x {
//             NameOrContent::Content(ref hd) => List::Cons(hd.clone(), box clone_iter(iter)),
//             NameOrContent::Name(ref nm) => {
//                 let (nm1,nm2) = fork(nm.clone());
//                 let rest = clone_iter(iter);
//                 List::Name(nm1, box List::Art( cell(nm2, box rest )))
//             }
//         }
//     }
// }

// pub fn from_iter<'x, 'y, T:'y>
// (iter:&'x mut Iterator) -> List<'y,T>
// where T : Clone
// {
//     match iter.next() {
//         None => List::Nil,
//         Some(x) => match x {
//             NameOrContent::Content(hd) => List::Cons(hd, box from_iter(iter)),
//             NameOrContent::Name(nm) => {
//                 let (nm1,nm2) = fork(nm.clone());
//                 let rest = from_iter(iter);
//                 List::Name(nm1, box List::Art( cell(nm2, box rest )))
//             }
//         }
//     }
// }
<commit_msg>Fixed issue that Kyle found: No Names/Arts in inner lists.<commit_after>use name::*;
use art::*;
use std::hash;
use std::hash::Hash;

/// Nominal, artful lists: Lists with names and articulation points
#[derive(Show,Hash,PartialEq,Eq)]
pub enum List<'x,T> {
    Nil,
    Cons(T, Box<List<'x,T>>),
    Name(Name, Box<List<'x,T>>),
    Art(Art<'x, Box<List<'x,T>>>)
}

pub fn copy<'x,T:'x>(list:List<'x,T>) -> List<'x,T> {
    match list {
        List::Nil         => List::Nil,
        List::Cons(hd,tl) => List::Cons(hd, box copy(*tl)),
        List::Art(art)    => copy(*force(art)),
        List::Name(nm,tl) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box copy(*tl)) ;
            List::Name(nm2, box List::Art(art))
        }
    }
}

pub fn map<'x, T:'x, S:'x>
(f:UAr<'x,T,S>, list:List<'x,T>) -> List<'x,S>
{
    match list {
        List::Nil         => List::Nil,
        List::Cons(hd,tl) => List::Cons((*f).call(hd), box map(f,*tl)),
        // - - - - - boilerplate cases - - - - - -
        List::Art(art)    => map(f,*force(art)),
        List::Name(nm,tl) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box map(f,*tl));
            List::Name(nm2, box List::Art(art))
        }
    }
}

pub fn contract<'x,F,G,T:'x>
(f:&'x F, g:&'x G, list:List<'x,T>) -> List<'x,T>
where F:Fn(&T,&T) -> bool + 'x,
      G:Fn(T,T) -> T + 'x
{
    match list {
        List::Nil => List::Nil,
        List::Cons(hd1, box list) => {
            match list {
                List::Nil => List::Cons(hd1, box List::Nil),
                List::Cons(hd2, tl) => {
                    if (*f)(&hd1,&hd2) {
                        List::Cons((*g)(hd1,hd2), box contract(f,g,*tl))
                    } else {
                        List::Cons(hd1, box contract(f, g, List::Cons(hd2, tl)))
                    } },
                // - - - - - boilerplate cases - - - - - -
                List::Art(art) => contract(f,g,List::Cons(hd1,force(art))),
                List::Name(nm, tl) => {
                    let (nm1,nm2) = fork(nm) ;
                    let art = nart!(nm1, box contract(f,g,List::Cons(hd1,tl))) ;
                    List::Name(nm2, box List::Art(art))
                }
            }
        },
        // - - - - - boilerplate cases - - - - - -
        List::Art(art)    => contract(f,g,*force(art)),
        List::Name(nm,tl) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box contract(f,g,*tl)) ;
            List::Name(nm2, box List::Art(art))
        },
    }
}

pub fn reduce<'x,F:'x,G:'x,T:'x>
(f:&'x F, g:&'x G, list:List<'x,T>) -> Option<T>
where F: Fn(&T,&T) -> bool,
      G: Fn(T, T) -> T,
{
    match list {
        List::Nil => None,
        List::Cons(hd, box list) => {
            match list {
                List::Nil => Some(hd),
                List::Cons(hd2, tl) => {
                    let hd3 = (*g)(hd,hd2) ;
                    let list = contract(f, g, List::Cons(hd3, tl)) ;
                    reduce (f, g, list)
                },
                // - - - - - boilerplate cases - - - - - -
                List::Name(_,tl) => reduce (f, g, *tl),
                List::Art(art)   => reduce (f, g, *force(art)),
            }},
        // - - - - - boilerplate cases - - - - - -
        List::Name(_,tl) => reduce(f, g, *tl),
        List::Art(art)   => reduce(f, g, *force(art)),
    }
}

pub fn merge<'x,T:'x,Ord:'x>
(ord:&'x Ord, list1:List<'x,T>, list2:List<'x,T>) -> List<'x,T>
where Ord: Fn(&T,&T) -> bool
{
    match (list1, list2) {
        (List::Nil, list2) => list2,
        (list1, List::Nil) => list1,
        (List::Cons(hd1,tl1),
         List::Cons(hd2,tl2)) =>
            if (*ord)(&hd1,&hd2) {
                List::Cons(hd1, box merge(ord, *tl1, List::Cons(hd2,tl2)))
            } else {
                List::Cons(hd2, box merge(ord, List::Cons(hd1,tl1), *tl2))
            },
        // - - - - - boilerplate cases - - - - -
        (List::Name(nm,tl), list2) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box merge(ord, *tl, list2)) ;
            List::Name(nm2, box List::Art(art))
        },
        (list1, List::Name(nm,tl)) => {
            let (nm1,nm2) = fork(nm) ;
            let art = nart!(nm1, box merge(ord, list1, *tl)) ;
            List::Name(nm2, box List::Art(art))
        },
        (List::Art(art), list2) => merge(ord, *force(art), list2),
        (list1, List::Art(art)) => merge(ord, list1, *force(art)),
    }
}

pub fn singletons<'x,T:'x>
    (nameop:Option<Name>, list:List<'x,T>) -> List<'x,List<'x,T>>
{
    match list {
        List::Nil => List::Nil,
        List::Cons(hd, tl) => {
            List::Cons( match nameop {
                None => List::Cons(hd, box List::Nil),
                Some(nm) => List::Name(nm, box List::Cons(hd, box List::Nil))
            }, box singletons(None,*tl) )
        },
        List::Art(art) => singletons(nameop,*force(art)),
        List::Name(nm, tl) => {
            let (nm1, nm) = fork(nm) ;
            let (nm2, nm3) = fork(nm) ;
            let art = nart!(nm2, box singletons(Some(nm3), *tl)) ;
            List::Name(nm1, box List::Art(art))
        }
    }
}

pub fn mergesort<'x,T:'x,Ord:'x>
(ord:&'x Ord, list:List<'x,T>) -> List<'x,T>
where Ord: Fn(&T,&T) -> bool, T:Hash
{
    let c = move |&: list1:&List<'x,T>,list2:&List<'x,T>|
    hash::hash(list1) < hash::hash(list2);

    let m = move |&: list1:List<'x,T>,list2:List<'x,T>|
    merge(ord,list1,list2);

    match reduce(&c, &m, singletons(None, list)) {
        None => List::Nil,
        Some(list) => list
    }
}

#[test]
pub fn construct_list () {
    let z : List<int> = List::Nil;
    let y : List<int> = List::Cons(1, box z);
    let x : List<int> = List::Art(cell(symbol(format!("two")), box y));
    let l : List<int> = List::Name(symbol(format!("one")), box x);
    println!("constructed list: {}", l);
}

// TODO: Rustup: Fix this:

 /// An iterator over the items in a list.
pub struct ListItems<'x, T: 'x> {
    list: &'x List<'x,T>
}

impl<'x,T> List<'x,T> {
    type Item = &'x T ;
    /// Get an iterator over the items in a list.
    pub fn iter(&'x self) -> ListItems<'x, T> {
        ListItems {
            list: self
        }
    }

}

impl<'x, T:'x> Iterator for ListItems<'x, T> {
    type Item = &'x T ;
    fn next(&mut self) -> Option<&'x T> {
        match *self.list {
            List::Cons(ref hd, ref tl) => {
                self.list = &**tl;
                Some(hd)
            },
            List::Name(_, ref list) => {
                self.list = &**list;
                self.next()
            },
            List::Art(ref art) => {
                self.list = &**force_ref(art);
                self.next()
            },
            List::Nil => None
        }
    }
}

pub enum NameOrContent<T> { Name(Name),Content(T) }

// pub fn clone_iter<'x, 'y, T:'y>
// (iter:&'x mut Iterator where ) -> List<'y,T>
// where T : Clone,

// {
//     match iter.next() {
//         None => List::Nil,
//         Some(x) => match x {
//             NameOrContent::Content(ref hd) => List::Cons(hd.clone(), box clone_iter(iter)),
//             NameOrContent::Name(ref nm) => {
//                 let (nm1,nm2) = fork(nm.clone());
//                 let rest = clone_iter(iter);
//                 List::Name(nm1, box List::Art( cell(nm2, box rest )))
//             }
//         }
//     }
// }

// pub fn from_iter<'x, 'y, T:'y>
// (iter:&'x mut Iterator) -> List<'y,T>
// where T : Clone
// {
//     match iter.next() {
//         None => List::Nil,
//         Some(x) => match x {
//             NameOrContent::Content(hd) => List::Cons(hd, box from_iter(iter)),
//             NameOrContent::Name(nm) => {
//                 let (nm1,nm2) = fork(nm.clone());
//                 let rest = from_iter(iter);
//                 List::Name(nm1, box List::Art( cell(nm2, box rest )))
//             }
//         }
//     }
// }
<|endoftext|>


<commit_before>use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
use syn::{
    parse::{Parse, ParseStream},
    parse_quote,
    punctuated::Punctuated,
    AngleBracketedGenericArguments, Attribute, Data, DeriveInput, Field, Fields, GenericArgument,
    GenericParam, Generics, Ident, ImplGenerics, ParenthesizedGenericArguments, PathArguments,
    Token, Type, TypeGenerics, TypePath, TypeReference, TypeSlice, Variant,
};

use crate::util::import_ruma_serde;

enum StructKind {
    Struct,
    Tuple,
}

enum DataKind {
    Struct(Vec<Field>, StructKind),
    Enum(Vec<Variant>),
    Unit,
}

pub fn expand_derive_outgoing(input: DeriveInput) -> syn::Result<TokenStream> {
    let ruma_serde = import_ruma_serde();

    let mut derives = vec![quote! { Debug }];
    let mut derive_deserialize = true;

    derives.extend(
        input
            .attrs
            .iter()
            .filter(|attr| attr.path.is_ident("incoming_derive"))
            .map(|attr| attr.parse_args())
            .collect::<syn::Result<Vec<Meta>>>()?
            .into_iter()
            .flat_map(|meta| meta.derive_macs)
            .filter_map(|derive_mac| match derive_mac {
                DeriveMac::Regular(id) => Some(quote! { #id }),
                DeriveMac::NegativeDeserialize => {
                    derive_deserialize = false;
                    None
                }
            }),
    );
    if derive_deserialize {
        derives.push(quote! { #ruma_serde::exports::serde::Deserialize });
    }

    let input_attrs =
        input.attrs.iter().filter(|attr| filter_input_attrs(attr)).collect::<Vec<_>>();

    let data = match input.data.clone() {
        Data::Union(_) => panic!("#[derive(Outgoing)] does not support Union types"),
        Data::Enum(e) => DataKind::Enum(e.variants.into_iter().collect()),
        Data::Struct(s) => match s.fields {
            Fields::Named(fs) => {
                DataKind::Struct(fs.named.into_iter().collect(), StructKind::Struct)
            }
            Fields::Unnamed(fs) => {
                DataKind::Struct(fs.unnamed.into_iter().collect(), StructKind::Tuple)
            }
            Fields::Unit => DataKind::Unit,
        },
    };

    match data {
        DataKind::Unit => Ok(impl_outgoing_with_incoming_self(&input, &ruma_serde)),
        DataKind::Enum(mut vars) => {
            let mut found_lifetime = false;
            for var in &mut vars {
                for field in &mut var.fields {
                    if strip_lifetimes(&mut field.ty) {
                        found_lifetime = true;
                    }
                }
            }

            let original_ident = &input.ident;
            let (original_impl_gen, original_ty_gen, _) = input.generics.split_for_impl();

            if !found_lifetime {
                return Ok(impl_outgoing_with_incoming_self(&input, &ruma_serde));
            }

            let vis = input.vis;
            let doc = format!("'Incoming' variant of [{ty}](enum.{ty}.html).", ty = &input.ident);
            let incoming_ident =
                format_ident!("Incoming{}", original_ident, span = Span::call_site());
            let mut gen_copy = input.generics.clone();
            let (impl_gen, ty_gen) = split_for_impl_lifetime_less(&mut gen_copy);

            Ok(quote! {
                #[doc = #doc]
                #[derive( #( #derives ),* )]
                #( #input_attrs )*
                #vis enum #incoming_ident #ty_gen { #( #vars, )* }

                impl #original_impl_gen #ruma_serde::Outgoing for #original_ident #original_ty_gen {
                    type Incoming = #incoming_ident #impl_gen;
                }
            })
        }
        DataKind::Struct(mut fields, struct_kind) => {
            let mut found_lifetime = false;
            for field in &mut fields {
                if !matches!(field.vis, syn::Visibility::Public(_)) {
                    return Err(syn::Error::new_spanned(field, "All fields must be marked `pub`"));
                }
                if strip_lifetimes(&mut field.ty) {
                    found_lifetime = true;
                }
            }

            let original_ident = &input.ident;
            let (original_impl_gen, original_ty_gen, _) = input.generics.split_for_impl();

            if !found_lifetime {
                return Ok(impl_outgoing_with_incoming_self(&input, &ruma_serde));
            }

            let vis = input.vis;
            let doc = format!("'Incoming' variant of [{ty}](struct.{ty}.html).", ty = &input.ident);
            let incoming_ident =
                format_ident!("Incoming{}", original_ident, span = Span::call_site());
            let mut gen_copy = input.generics.clone();
            let (impl_gen, ty_gen) = split_for_impl_lifetime_less(&mut gen_copy);

            let struct_def = match struct_kind {
                StructKind::Struct => quote! { { #(#fields,)* } },
                StructKind::Tuple => quote! { ( #(#fields,)* ); },
            };

            Ok(quote! {
                #[doc = #doc]
                #[derive( #( #derives ),* )]
                #( #input_attrs )*
                #vis struct #incoming_ident #ty_gen #struct_def

                impl #original_impl_gen #ruma_serde::Outgoing for #original_ident #original_ty_gen {
                    type Incoming = #incoming_ident #impl_gen;
                }
            })
        }
    }
}

/// Keep any `serde` or `non_exhaustive` attributes found and
/// pass them to the Incoming variant.
fn filter_input_attrs(attr: &Attribute) -> bool {
    attr.path.is_ident("serde") || attr.path.is_ident("non_exhaustive")
}

fn impl_outgoing_with_incoming_self(input: &DeriveInput, ruma_serde: &TokenStream) -> TokenStream {
    let ident = &input.ident;
    let (impl_gen, ty_gen, _) = input.generics.split_for_impl();

    quote! {
        impl #impl_gen #ruma_serde::Outgoing for #ident #ty_gen {
            type Incoming = Self;
        }
    }
}

fn split_for_impl_lifetime_less(generics: &mut Generics) -> (ImplGenerics, TypeGenerics) {
    generics.params = generics
        .params
        .clone()
        .into_iter()
        .filter(|param| !matches!(param, GenericParam::Lifetime(_)))
        .collect();

    let (impl_gen, ty_gen, _) = generics.split_for_impl();
    (impl_gen, ty_gen)
}

fn strip_lifetimes(field_type: &mut Type) -> bool {
    match field_type {
        // T<'a> -> IncomingT
        // The IncomingT has to be declared by the user of this derive macro.
        Type::Path(TypePath { path, .. }) => {
            let mut has_lifetimes = false;
            let mut is_lifetime_generic = false;

            for seg in &mut path.segments {
                // strip generic lifetimes
                match &mut seg.arguments {
                    PathArguments::AngleBracketed(AngleBracketedGenericArguments {
                        args, ..
                    }) => {
                        *args = args
                            .clone()
                            .into_iter()
                            .map(|mut ty| {
                                if let GenericArgument::Type(ty) = &mut ty {
                                    if strip_lifetimes(ty) {
                                        has_lifetimes = true;
                                    };
                                }
                                ty
                            })
                            .filter(|arg| {
                                if let GenericArgument::Lifetime(_) = arg {
                                    is_lifetime_generic = true;
                                    false
                                } else {
                                    true
                                }
                            })
                            .collect();
                    }
                    PathArguments::Parenthesized(ParenthesizedGenericArguments {
                        inputs, ..
                    }) => {
                        *inputs = inputs
                            .clone()
                            .into_iter()
                            .map(|mut ty| {
                                if strip_lifetimes(&mut ty) {
                                    has_lifetimes = true;
                                };
                                ty
                            })
                            .collect();
                    }
                    _ => {}
                }
            }

            // If a type has a generic lifetime parameter there must be an `Incoming` variant of
            // that type.
            if is_lifetime_generic {
                if let Some(name) = path.segments.last_mut() {
                    let incoming_ty_ident = format_ident!("Incoming{}", name.ident);
                    name.ident = incoming_ty_ident;
                }
            }

            has_lifetimes || is_lifetime_generic
        }
        Type::Reference(TypeReference { elem, .. }) => {
            let special_replacement = match &mut **elem {
                Type::Path(ty) => {
                    let path = &ty.path;
                    let last_seg = path.segments.last().unwrap();

                    if last_seg.ident == "str" {
                        // &str -> String
                        Some(parse_quote! { ::std::string::String })
                    } else if last_seg.ident == "DeviceId"
                        || last_seg.ident == "ServerName"
                        || last_seg.ident == "RawJsonValue"
                    {
                        // The identifiers that need to be boxed `Box<T>` since they are DST's.
                        Some(parse_quote! { ::std::boxed::Box<#path> })
                    } else {
                        None
                    }
                }
                // &[T] -> Vec<T>
                Type::Slice(TypeSlice { elem, .. }) => {
                    // Recursively strip the lifetimes of the slice's elements.
                    strip_lifetimes(&mut *elem);
                    Some(parse_quote! { Vec<#elem> })
                }
                _ => None,
            };

            *field_type = match special_replacement {
                Some(ty) => ty,
                None => {
                    // Strip lifetimes of `elem`.
                    strip_lifetimes(elem);
                    // Replace reference with `elem`.
                    (**elem).clone()
                }
            };

            true
        }
        Type::Tuple(syn::TypeTuple { elems, .. }) => {
            let mut has_lifetime = false;
            for elem in elems {
                if strip_lifetimes(elem) {
                    has_lifetime = true;
                }
            }
            has_lifetime
        }
        _ => false,
    }
}

pub struct Meta {
    derive_macs: Vec<DeriveMac>,
}

impl Parse for Meta {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        Ok(Self {
            derive_macs: Punctuated::<_, Token![,]>::parse_terminated(input)?.into_iter().collect(),
        })
    }
}

pub enum DeriveMac {
    Regular(Ident),
    NegativeDeserialize,
}

impl Parse for DeriveMac {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        if input.peek(Token![!]) {
            let _: Token![!] = input.parse()?;
            let mac: Ident = input.parse()?;

            if mac != "Deserialize" {
                return Err(syn::Error::new_spanned(
                    mac,
                    "Negative incoming_derive can only be used for Deserialize",
                ));
            }

            Ok(Self::NegativeDeserialize)
        } else {
            let mac = input.parse()?;
            Ok(Self::Regular(mac))
        }
    }
}
<commit_msg>Outgoing derive: Copy `cfg` and `cfg_attr` attributes to Incoming type<commit_after>use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
use syn::{
    parse::{Parse, ParseStream},
    parse_quote,
    punctuated::Punctuated,
    AngleBracketedGenericArguments, Attribute, Data, DeriveInput, Field, Fields, GenericArgument,
    GenericParam, Generics, Ident, ImplGenerics, ParenthesizedGenericArguments, PathArguments,
    Token, Type, TypeGenerics, TypePath, TypeReference, TypeSlice, Variant,
};

use crate::util::import_ruma_serde;

enum StructKind {
    Struct,
    Tuple,
}

enum DataKind {
    Struct(Vec<Field>, StructKind),
    Enum(Vec<Variant>),
    Unit,
}

pub fn expand_derive_outgoing(input: DeriveInput) -> syn::Result<TokenStream> {
    let ruma_serde = import_ruma_serde();

    let mut derives = vec![quote! { Debug }];
    let mut derive_deserialize = true;

    derives.extend(
        input
            .attrs
            .iter()
            .filter(|attr| attr.path.is_ident("incoming_derive"))
            .map(|attr| attr.parse_args())
            .collect::<syn::Result<Vec<Meta>>>()?
            .into_iter()
            .flat_map(|meta| meta.derive_macs)
            .filter_map(|derive_mac| match derive_mac {
                DeriveMac::Regular(id) => Some(quote! { #id }),
                DeriveMac::NegativeDeserialize => {
                    derive_deserialize = false;
                    None
                }
            }),
    );
    if derive_deserialize {
        derives.push(quote! { #ruma_serde::exports::serde::Deserialize });
    }

    let input_attrs =
        input.attrs.iter().filter(|attr| filter_input_attrs(attr)).collect::<Vec<_>>();

    let data = match input.data.clone() {
        Data::Union(_) => panic!("#[derive(Outgoing)] does not support Union types"),
        Data::Enum(e) => DataKind::Enum(e.variants.into_iter().collect()),
        Data::Struct(s) => match s.fields {
            Fields::Named(fs) => {
                DataKind::Struct(fs.named.into_iter().collect(), StructKind::Struct)
            }
            Fields::Unnamed(fs) => {
                DataKind::Struct(fs.unnamed.into_iter().collect(), StructKind::Tuple)
            }
            Fields::Unit => DataKind::Unit,
        },
    };

    match data {
        DataKind::Unit => Ok(impl_outgoing_with_incoming_self(&input, &ruma_serde)),
        DataKind::Enum(mut vars) => {
            let mut found_lifetime = false;
            for var in &mut vars {
                for field in &mut var.fields {
                    if strip_lifetimes(&mut field.ty) {
                        found_lifetime = true;
                    }
                }
            }

            let original_ident = &input.ident;
            let (original_impl_gen, original_ty_gen, _) = input.generics.split_for_impl();

            if !found_lifetime {
                return Ok(impl_outgoing_with_incoming_self(&input, &ruma_serde));
            }

            let vis = input.vis;
            let doc = format!("'Incoming' variant of [{ty}](enum.{ty}.html).", ty = &input.ident);
            let incoming_ident =
                format_ident!("Incoming{}", original_ident, span = Span::call_site());
            let mut gen_copy = input.generics.clone();
            let (impl_gen, ty_gen) = split_for_impl_lifetime_less(&mut gen_copy);

            Ok(quote! {
                #[doc = #doc]
                #[derive( #( #derives ),* )]
                #( #input_attrs )*
                #vis enum #incoming_ident #ty_gen { #( #vars, )* }

                impl #original_impl_gen #ruma_serde::Outgoing for #original_ident #original_ty_gen {
                    type Incoming = #incoming_ident #impl_gen;
                }
            })
        }
        DataKind::Struct(mut fields, struct_kind) => {
            let mut found_lifetime = false;
            for field in &mut fields {
                if !matches!(field.vis, syn::Visibility::Public(_)) {
                    return Err(syn::Error::new_spanned(field, "All fields must be marked `pub`"));
                }
                if strip_lifetimes(&mut field.ty) {
                    found_lifetime = true;
                }
            }

            let original_ident = &input.ident;
            let (original_impl_gen, original_ty_gen, _) = input.generics.split_for_impl();

            if !found_lifetime {
                return Ok(impl_outgoing_with_incoming_self(&input, &ruma_serde));
            }

            let vis = input.vis;
            let doc = format!("'Incoming' variant of [{ty}](struct.{ty}.html).", ty = &input.ident);
            let incoming_ident =
                format_ident!("Incoming{}", original_ident, span = Span::call_site());
            let mut gen_copy = input.generics.clone();
            let (impl_gen, ty_gen) = split_for_impl_lifetime_less(&mut gen_copy);

            let struct_def = match struct_kind {
                StructKind::Struct => quote! { { #(#fields,)* } },
                StructKind::Tuple => quote! { ( #(#fields,)* ); },
            };

            Ok(quote! {
                #[doc = #doc]
                #[derive( #( #derives ),* )]
                #( #input_attrs )*
                #vis struct #incoming_ident #ty_gen #struct_def

                impl #original_impl_gen #ruma_serde::Outgoing for #original_ident #original_ty_gen {
                    type Incoming = #incoming_ident #impl_gen;
                }
            })
        }
    }
}

/// Keep any `cfg`, `cfg_attr`, `serde` or `non_exhaustive` attributes found and pass them to the
/// Incoming variant.
fn filter_input_attrs(attr: &Attribute) -> bool {
    attr.path.is_ident("cfg")
        || attr.path.is_ident("cfg_attr")
        || attr.path.is_ident("serde")
        || attr.path.is_ident("non_exhaustive")
}

fn impl_outgoing_with_incoming_self(input: &DeriveInput, ruma_serde: &TokenStream) -> TokenStream {
    let ident = &input.ident;
    let (impl_gen, ty_gen, _) = input.generics.split_for_impl();

    quote! {
        impl #impl_gen #ruma_serde::Outgoing for #ident #ty_gen {
            type Incoming = Self;
        }
    }
}

fn split_for_impl_lifetime_less(generics: &mut Generics) -> (ImplGenerics, TypeGenerics) {
    generics.params = generics
        .params
        .clone()
        .into_iter()
        .filter(|param| !matches!(param, GenericParam::Lifetime(_)))
        .collect();

    let (impl_gen, ty_gen, _) = generics.split_for_impl();
    (impl_gen, ty_gen)
}

fn strip_lifetimes(field_type: &mut Type) -> bool {
    match field_type {
        // T<'a> -> IncomingT
        // The IncomingT has to be declared by the user of this derive macro.
        Type::Path(TypePath { path, .. }) => {
            let mut has_lifetimes = false;
            let mut is_lifetime_generic = false;

            for seg in &mut path.segments {
                // strip generic lifetimes
                match &mut seg.arguments {
                    PathArguments::AngleBracketed(AngleBracketedGenericArguments {
                        args, ..
                    }) => {
                        *args = args
                            .clone()
                            .into_iter()
                            .map(|mut ty| {
                                if let GenericArgument::Type(ty) = &mut ty {
                                    if strip_lifetimes(ty) {
                                        has_lifetimes = true;
                                    };
                                }
                                ty
                            })
                            .filter(|arg| {
                                if let GenericArgument::Lifetime(_) = arg {
                                    is_lifetime_generic = true;
                                    false
                                } else {
                                    true
                                }
                            })
                            .collect();
                    }
                    PathArguments::Parenthesized(ParenthesizedGenericArguments {
                        inputs, ..
                    }) => {
                        *inputs = inputs
                            .clone()
                            .into_iter()
                            .map(|mut ty| {
                                if strip_lifetimes(&mut ty) {
                                    has_lifetimes = true;
                                };
                                ty
                            })
                            .collect();
                    }
                    _ => {}
                }
            }

            // If a type has a generic lifetime parameter there must be an `Incoming` variant of
            // that type.
            if is_lifetime_generic {
                if let Some(name) = path.segments.last_mut() {
                    let incoming_ty_ident = format_ident!("Incoming{}", name.ident);
                    name.ident = incoming_ty_ident;
                }
            }

            has_lifetimes || is_lifetime_generic
        }
        Type::Reference(TypeReference { elem, .. }) => {
            let special_replacement = match &mut **elem {
                Type::Path(ty) => {
                    let path = &ty.path;
                    let last_seg = path.segments.last().unwrap();

                    if last_seg.ident == "str" {
                        // &str -> String
                        Some(parse_quote! { ::std::string::String })
                    } else if last_seg.ident == "DeviceId"
                        || last_seg.ident == "ServerName"
                        || last_seg.ident == "RawJsonValue"
                    {
                        // The identifiers that need to be boxed `Box<T>` since they are DST's.
                        Some(parse_quote! { ::std::boxed::Box<#path> })
                    } else {
                        None
                    }
                }
                // &[T] -> Vec<T>
                Type::Slice(TypeSlice { elem, .. }) => {
                    // Recursively strip the lifetimes of the slice's elements.
                    strip_lifetimes(&mut *elem);
                    Some(parse_quote! { Vec<#elem> })
                }
                _ => None,
            };

            *field_type = match special_replacement {
                Some(ty) => ty,
                None => {
                    // Strip lifetimes of `elem`.
                    strip_lifetimes(elem);
                    // Replace reference with `elem`.
                    (**elem).clone()
                }
            };

            true
        }
        Type::Tuple(syn::TypeTuple { elems, .. }) => {
            let mut has_lifetime = false;
            for elem in elems {
                if strip_lifetimes(elem) {
                    has_lifetime = true;
                }
            }
            has_lifetime
        }
        _ => false,
    }
}

pub struct Meta {
    derive_macs: Vec<DeriveMac>,
}

impl Parse for Meta {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        Ok(Self {
            derive_macs: Punctuated::<_, Token![,]>::parse_terminated(input)?.into_iter().collect(),
        })
    }
}

pub enum DeriveMac {
    Regular(Ident),
    NegativeDeserialize,
}

impl Parse for DeriveMac {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        if input.peek(Token![!]) {
            let _: Token![!] = input.parse()?;
            let mac: Ident = input.parse()?;

            if mac != "Deserialize" {
                return Err(syn::Error::new_spanned(
                    mac,
                    "Negative incoming_derive can only be used for Deserialize",
                ));
            }

            Ok(Self::NegativeDeserialize)
        } else {
            let mac = input.parse()?;
            Ok(Self::Regular(mac))
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
#[macro_use]
extern crate more_asserts;

pub mod bitpacked;
pub mod linearinterpol;

pub trait CodecReader: Sized {
    /// reads the metadata and returns the CodecReader
    fn open_from_bytes(bytes: &[u8]) -> std::io::Result<Self>;

    fn get_u64(&self, doc: u64, data: &[u8]) -> u64;

    fn min_value(&self) -> u64;
    fn max_value(&self) -> u64;
}

/// FastFieldDataAccess is the trait to access fast field data during serialization and estimation.
pub trait FastFieldDataAccess: Clone {
    /// Return the value associated to the given document.
    ///
    /// Whenever possible use the Iterator passed to the fastfield creation instead, for performance reasons.
    ///
    /// # Panics
    ///
    /// May panic if `doc` is greater than the segment
    fn get(&self, doc: u32) -> u64;
}

/// The FastFieldSerializerEstimate trait is required on all variants
/// of fast field compressions, to decide which one to choose.
pub trait FastFieldSerializerEstimate {
    /// returns an estimate of the compression ratio.
    /// The baseline is uncompressed 64bit data.
    ///
    /// It could make sense to also return a value representing
    /// computational complexity.
    fn estimate(fastfield_accessor: &impl FastFieldDataAccess, stats: FastFieldStats) -> f32;
}

/// `CodecId` is required by each Codec.
///
/// It needs to provide a unique name and id, which is
/// used for debugging and de/serialization.
pub trait CodecId {
    const NAME: &'static str;
    const ID: u8;
}

#[derive(Debug, Clone)]
pub struct FastFieldStats {
    pub min_value: u64,
    pub max_value: u64,
    pub num_vals: u64,
}

impl<'a> FastFieldDataAccess for &'a [u64] {
    fn get(&self, doc: u32) -> u64 {
        self[doc as usize]
    }
}

impl FastFieldDataAccess for Vec<u64> {
    fn get(&self, doc: u32) -> u64 {
        self[doc as usize]
    }
}

#[cfg(test)]
mod tests {
    use crate::{
        bitpacked::BitpackedFastFieldSerializer, linearinterpol::LinearInterpolFastFieldSerializer,
    };

    pub fn get_codec_test_data_sets() -> Vec<(Vec<u64>, &'static str)> {
        let mut data_and_names = vec![];

        let data = (10..=20_u64).collect::<Vec<_>>();
        data_and_names.push((data, "simple monotonically increasing"));

        data_and_names.push((
            vec![5, 6, 7, 8, 9, 10, 99, 100],
            "offset in linear interpol",
        ));
        data_and_names.push((vec![5, 50, 3, 13, 1, 1000, 35], "rand small"));
        data_and_names.push((vec![10], "single value"));

        data_and_names
    }

    use super::*;
    pub fn stats_from_vec(data: &[u64]) -> FastFieldStats {
        let min_value = data.iter().cloned().min().unwrap_or(0);
        let max_value = data.iter().cloned().max().unwrap_or(0);
        FastFieldStats {
            min_value,
            max_value,
            num_vals: data.len() as u64,
        }
    }

    #[test]
    fn estimation_good_interpolation_case() {
        let data = (10..=20_u64).collect::<Vec<_>>();

        let linear_interpol_estimation =
            LinearInterpolFastFieldSerializer::estimate(&data, stats_from_vec(&data));
        assert_le!(linear_interpol_estimation, 0.1);

        let bitpacked_estimation =
            BitpackedFastFieldSerializer::<Vec<u8>>::estimate(&data, stats_from_vec(&data));
        assert_le!(linear_interpol_estimation, bitpacked_estimation);
    }
    #[test]
    fn estimation_test_bad_interpolation_case() {
        let data = vec![200, 10, 10, 10, 10, 1000, 20];

        let linear_interpol_estimation =
            LinearInterpolFastFieldSerializer::estimate(&data, stats_from_vec(&data));
        assert_le!(linear_interpol_estimation, 0.3);

        let bitpacked_estimation =
            BitpackedFastFieldSerializer::<Vec<u8>>::estimate(&data, stats_from_vec(&data));
        assert_le!(bitpacked_estimation, linear_interpol_estimation);
    }
    #[test]
    fn estimation_test_bad_interpolation_case_monotonically_increasing() {
        let mut data = (200..=20000_u64).collect::<Vec<_>>();
        data.push(1_000_000);

        // in this case the linear interpolation can't in fact not be worse than bitpacking,
        // but the estimator adds some threshold, which leads to estimated worse behavior
        let linear_interpol_estimation =
            LinearInterpolFastFieldSerializer::estimate(&data, stats_from_vec(&data));
        assert_le!(linear_interpol_estimation, 0.35);

        let bitpacked_estimation =
            BitpackedFastFieldSerializer::<Vec<u8>>::estimate(&data, stats_from_vec(&data));
        assert_le!(bitpacked_estimation, 0.32);
        assert_le!(bitpacked_estimation, linear_interpol_estimation);
    }
}
<commit_msg>fix estimation test<commit_after>#[cfg(test)]
#[macro_use]
extern crate more_asserts;

pub mod bitpacked;
pub mod linearinterpol;

pub trait CodecReader: Sized {
    /// reads the metadata and returns the CodecReader
    fn open_from_bytes(bytes: &[u8]) -> std::io::Result<Self>;

    fn get_u64(&self, doc: u64, data: &[u8]) -> u64;

    fn min_value(&self) -> u64;
    fn max_value(&self) -> u64;
}

/// FastFieldDataAccess is the trait to access fast field data during serialization and estimation.
pub trait FastFieldDataAccess: Clone {
    /// Return the value associated to the given document.
    ///
    /// Whenever possible use the Iterator passed to the fastfield creation instead, for performance reasons.
    ///
    /// # Panics
    ///
    /// May panic if `doc` is greater than the segment
    fn get(&self, doc: u32) -> u64;
}

/// The FastFieldSerializerEstimate trait is required on all variants
/// of fast field compressions, to decide which one to choose.
pub trait FastFieldSerializerEstimate {
    /// returns an estimate of the compression ratio.
    /// The baseline is uncompressed 64bit data.
    ///
    /// It could make sense to also return a value representing
    /// computational complexity.
    fn estimate(fastfield_accessor: &impl FastFieldDataAccess, stats: FastFieldStats) -> f32;
}

/// `CodecId` is required by each Codec.
///
/// It needs to provide a unique name and id, which is
/// used for debugging and de/serialization.
pub trait CodecId {
    const NAME: &'static str;
    const ID: u8;
}

#[derive(Debug, Clone)]
pub struct FastFieldStats {
    pub min_value: u64,
    pub max_value: u64,
    pub num_vals: u64,
}

impl<'a> FastFieldDataAccess for &'a [u64] {
    fn get(&self, doc: u32) -> u64 {
        self[doc as usize]
    }
}

impl FastFieldDataAccess for Vec<u64> {
    fn get(&self, doc: u32) -> u64 {
        self[doc as usize]
    }
}

#[cfg(test)]
mod tests {
    use crate::{
        bitpacked::BitpackedFastFieldSerializer, linearinterpol::LinearInterpolFastFieldSerializer,
    };

    pub fn get_codec_test_data_sets() -> Vec<(Vec<u64>, &'static str)> {
        let mut data_and_names = vec![];

        let data = (10..=20_u64).collect::<Vec<_>>();
        data_and_names.push((data, "simple monotonically increasing"));

        data_and_names.push((
            vec![5, 6, 7, 8, 9, 10, 99, 100],
            "offset in linear interpol",
        ));
        data_and_names.push((vec![5, 50, 3, 13, 1, 1000, 35], "rand small"));
        data_and_names.push((vec![10], "single value"));

        data_and_names
    }

    use super::*;
    pub fn stats_from_vec(data: &[u64]) -> FastFieldStats {
        let min_value = data.iter().cloned().min().unwrap_or(0);
        let max_value = data.iter().cloned().max().unwrap_or(0);
        FastFieldStats {
            min_value,
            max_value,
            num_vals: data.len() as u64,
        }
    }

    #[test]
    fn estimation_good_interpolation_case() {
        let data = (10..=200_u64).collect::<Vec<_>>();

        let linear_interpol_estimation =
            LinearInterpolFastFieldSerializer::estimate(&data, stats_from_vec(&data));
        assert_le!(linear_interpol_estimation, 0.1);

        let bitpacked_estimation =
            BitpackedFastFieldSerializer::<Vec<u8>>::estimate(&data, stats_from_vec(&data));
        assert_le!(linear_interpol_estimation, bitpacked_estimation);
    }
    #[test]
    fn estimation_test_bad_interpolation_case() {
        let data = vec![200, 10, 10, 10, 10, 1000, 20];

        let linear_interpol_estimation =
            LinearInterpolFastFieldSerializer::estimate(&data, stats_from_vec(&data));
        assert_le!(linear_interpol_estimation, 0.32);

        let bitpacked_estimation =
            BitpackedFastFieldSerializer::<Vec<u8>>::estimate(&data, stats_from_vec(&data));
        assert_le!(bitpacked_estimation, linear_interpol_estimation);
    }
    #[test]
    fn estimation_test_bad_interpolation_case_monotonically_increasing() {
        let mut data = (200..=20000_u64).collect::<Vec<_>>();
        data.push(1_000_000);

        // in this case the linear interpolation can't in fact not be worse than bitpacking,
        // but the estimator adds some threshold, which leads to estimated worse behavior
        let linear_interpol_estimation =
            LinearInterpolFastFieldSerializer::estimate(&data, stats_from_vec(&data));
        assert_le!(linear_interpol_estimation, 0.35);

        let bitpacked_estimation =
            BitpackedFastFieldSerializer::<Vec<u8>>::estimate(&data, stats_from_vec(&data));
        assert_le!(bitpacked_estimation, 0.32);
        assert_le!(bitpacked_estimation, linear_interpol_estimation);
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Read};
use std::cmp;
use std::fmt;

use parse::{self, ParseError};
use value::{Value, Args, FromLisp, ToLisp};
use valtype::Type;
use env::Env;

pub type FuncResult = Result<Value, FuncError>;

pub enum FuncError {
    InvalidArguments {
        expected: Args,
        got: usize,
    },
    InvalidType {
        expected: Vec<Type>,
        got: Value,
    },
    UndeclaredSymbol(String),

    AttemptToCallNonFunction(Value),
    AttemptToEvalEmptyList,

    GivenEmptyList,

    IoError(io::Error),

    ParsingErr(ParseError),
}

pub struct Lisp {
    pub scopes: Vec<Env>,
}

impl Lisp {
    pub fn new() -> Lisp {
        Lisp {
            scopes: vec![Env::std_lib()],
        }
    }

    pub fn new_no_stdlib() -> Lisp {
        Lisp {
            scopes: vec![Env::new()],
        }
    }

    pub fn eval<T: FromLisp>(&mut self, code: &str) -> Result<T, FuncError> {
        let result = try!(self.eval_raw(code));

        return T::from_lisp(result);
    }

    pub fn eval_reader<R: Read>(&mut self, mut code: R) -> FuncResult {
        let mut read_string = String::new();
        match code.read_to_string(&mut read_string) {
            Ok(_) => (),
            Err(err) => return Err(FuncError::IoError(err)),
        }

        self.eval_raw(&read_string)
    }

    pub fn eval_raw(&mut self, code: &str) -> FuncResult {
        let tokens = match parse::parse_str(code) {
            Ok(tok) => tok,
            Err(err) => return Err(FuncError::ParsingErr(err)),
        };

        self.eval_token_vec(tokens)
    }

    pub fn eval_token_vec(&mut self, mut tokens: Vec<Value>) -> FuncResult {
        let ret_token = match tokens.pop() {
            Some(token) => token,
            None => unreachable!(),
        };

        for token in tokens {
            try!(self.eval_token(token));
        }

        self.eval_token(ret_token)
    }

    pub fn eval_token(&mut self, token: Value) -> FuncResult {
        match token {
            Value::Symbol(sym) => {
                for env in self.scopes.iter().rev() {
                    if let Some(val) = env.map.get(&sym) {
                        return Ok(val.clone());
                    }
                }

                Err(FuncError::UndeclaredSymbol(sym))
            },
            Value::List(mut tokens) => {
                if tokens.len() == 0 {
                  return Err(FuncError::AttemptToEvalEmptyList);
                }

                let val = tokens.remove(0);
                let func = try!(self.eval_token(val.clone()));
                self.sub_scope(); // each list has its own scope

                match func {
                    Value::HardFunc(hard_func) => {
                        let mut args = Vec::new();

                        for token in tokens {
                            args.push(try!(self.eval_token(token)));
                        }

                        match hard_func.args {
                            Args::Variant => (),
                            Args::Fixed(count) => {
                                if args.len() != count {
                                    invalid_args!(self, Args::Fixed(count), args);
                                }
                            },
                            Args::Multiple(possible_counts) => {
                                let mut arg_match = false;

                                // I wish I could label match statements and break out of them...
                                for count in &possible_counts {
                                    if args.len() == *count {
                                        arg_match = true;
                                        break;
                                    }
                                }

                                if !arg_match {
                                    invalid_args!(self, Args::Multiple(possible_counts), args);
                                }
                            },
                            Args::Atleast(count) => {
                                if args.len() < count {
                                    invalid_args!(self, Args::Atleast(count), args);
                                }
                            }
                        }

                        let result = (hard_func.func)(args, self);
                        self.exit_scope();

                        result
                    },
                    Value::Lambda { args, body } => {
                        if tokens.len() != args.len() {
                            invalid_args!(self, Args::Fixed(args.len()), tokens);
                        }

                        for sym in args.iter() {
                            let value = try!(self.eval_token(tokens.remove(0)));
                            self.cur_scope().set(sym, value);
                        }

                        let result = self.eval_token_vec(body);
                        self.exit_scope();

                        result
                    },
                    _ => return Err(FuncError::AttemptToCallNonFunction(val)),
                }
            },
            Value::Quote(val) => Ok(*val),
            _ => Ok(token),
        }
    }

    pub fn set_global<T: ToLisp>(&mut self, name: &str, value: T) {
        self.scopes[0].set(name, value);
    }

    pub fn sub_scope(&mut self) {
        self.scopes.push(Env::new());
    }

    pub fn exit_scope(&mut self) {
        self.scopes.pop();
    }

    pub fn cur_scope(&mut self) -> &mut Env {
        let index = self.scopes.len() - 1;
        &mut self.scopes[index]
    }

    pub fn parent_scope(&mut self) -> &mut Env {
        let index = cmp::max(self.scopes.len() as i32 - 2, 0) as usize;
        &mut self.scopes[index]
    }
}

impl fmt::Debug for Value {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Value::List(ref values) => parse::write_list(fmt, values, "(", " ", ")"),
            &Value::String(ref string) => write!(fmt, "{:?}", string),
            &Value::Symbol(ref string) => write!(fmt, "{}", string),
            &Value::Number(num) => write!(fmt, "{}", num),
            &Value::HardFunc(ref func) => write!(fmt, "HardFunc({:?})", func.args),
            &Value::Lambda { ref args, ref body }=> write!(fmt, "λ {:?} => {:?}", args, body),
            &Value::Nil => write!(fmt, "nil"),
            &Value::Bool(val) => write!(fmt, "{}", val),
            &Value::Quote(ref tok) => write!(fmt, "'{:?}", tok),
            &Value::Type(ref typ) => write!(fmt, "{:?}", typ),
            &Value::Foreign(ref val) => write!(fmt, "{:?}", val),
        }
    }
}
<commit_msg>Rename function<commit_after>use std::io::{self, Read};
use std::cmp;
use std::fmt;

use parse::{self, ParseError};
use value::{Value, Args, FromLisp, ToLisp};
use valtype::Type;
use env::Env;

pub type FuncResult = Result<Value, FuncError>;

pub enum FuncError {
    InvalidArguments {
        expected: Args,
        got: usize,
    },
    InvalidType {
        expected: Vec<Type>,
        got: Value,
    },
    UndeclaredSymbol(String),

    AttemptToCallNonFunction(Value),
    AttemptToEvalEmptyList,

    GivenEmptyList,

    IoError(io::Error),

    ParsingErr(ParseError),
}

pub struct Lisp {
    pub scopes: Vec<Env>,
}

impl Lisp {
    pub fn new() -> Lisp {
        Lisp {
            scopes: vec![Env::std_lib()],
        }
    }

    pub fn new_empty_env() -> Lisp {
        Lisp {
            scopes: vec![Env::new()],
        }
    }

    pub fn eval<T: FromLisp>(&mut self, code: &str) -> Result<T, FuncError> {
        let result = try!(self.eval_raw(code));

        return T::from_lisp(result);
    }

    pub fn eval_reader<R: Read>(&mut self, mut code: R) -> FuncResult {
        let mut read_string = String::new();
        match code.read_to_string(&mut read_string) {
            Ok(_) => (),
            Err(err) => return Err(FuncError::IoError(err)),
        }

        self.eval_raw(&read_string)
    }

    pub fn eval_raw(&mut self, code: &str) -> FuncResult {
        let tokens = match parse::parse_str(code) {
            Ok(tok) => tok,
            Err(err) => return Err(FuncError::ParsingErr(err)),
        };

        self.eval_token_vec(tokens)
    }

    pub fn eval_token_vec(&mut self, mut tokens: Vec<Value>) -> FuncResult {
        let ret_token = match tokens.pop() {
            Some(token) => token,
            None => unreachable!(),
        };

        for token in tokens {
            try!(self.eval_token(token));
        }

        self.eval_token(ret_token)
    }

    pub fn eval_token(&mut self, token: Value) -> FuncResult {
        match token {
            Value::Symbol(sym) => {
                for env in self.scopes.iter().rev() {
                    if let Some(val) = env.map.get(&sym) {
                        return Ok(val.clone());
                    }
                }

                Err(FuncError::UndeclaredSymbol(sym))
            },
            Value::List(mut tokens) => {
                if tokens.len() == 0 {
                  return Err(FuncError::AttemptToEvalEmptyList);
                }

                let val = tokens.remove(0);
                let func = try!(self.eval_token(val.clone()));
                self.sub_scope(); // each list has its own scope

                match func {
                    Value::HardFunc(hard_func) => {
                        let mut args = Vec::new();

                        for token in tokens {
                            args.push(try!(self.eval_token(token)));
                        }

                        match hard_func.args {
                            Args::Variant => (),
                            Args::Fixed(count) => {
                                if args.len() != count {
                                    invalid_args!(self, Args::Fixed(count), args);
                                }
                            },
                            Args::Multiple(possible_counts) => {
                                let mut arg_match = false;

                                // I wish I could label match statements and break out of them...
                                for count in &possible_counts {
                                    if args.len() == *count {
                                        arg_match = true;
                                        break;
                                    }
                                }

                                if !arg_match {
                                    invalid_args!(self, Args::Multiple(possible_counts), args);
                                }
                            },
                            Args::Atleast(count) => {
                                if args.len() < count {
                                    invalid_args!(self, Args::Atleast(count), args);
                                }
                            }
                        }

                        let result = (hard_func.func)(args, self);
                        self.exit_scope();

                        result
                    },
                    Value::Lambda { args, body } => {
                        if tokens.len() != args.len() {
                            invalid_args!(self, Args::Fixed(args.len()), tokens);
                        }

                        for sym in args.iter() {
                            let value = try!(self.eval_token(tokens.remove(0)));
                            self.cur_scope().set(sym, value);
                        }

                        let result = self.eval_token_vec(body);
                        self.exit_scope();

                        result
                    },
                    _ => return Err(FuncError::AttemptToCallNonFunction(val)),
                }
            },
            Value::Quote(val) => Ok(*val),
            _ => Ok(token),
        }
    }

    pub fn set_global<T: ToLisp>(&mut self, name: &str, value: T) {
        self.scopes[0].set(name, value);
    }

    pub fn sub_scope(&mut self) {
        self.scopes.push(Env::new());
    }

    pub fn exit_scope(&mut self) {
        self.scopes.pop();
    }

    pub fn cur_scope(&mut self) -> &mut Env {
        let index = self.scopes.len() - 1;
        &mut self.scopes[index]
    }

    pub fn parent_scope(&mut self) -> &mut Env {
        let index = cmp::max(self.scopes.len() as i32 - 2, 0) as usize;
        &mut self.scopes[index]
    }
}

impl fmt::Debug for Value {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Value::List(ref values) => parse::write_list(fmt, values, "(", " ", ")"),
            &Value::String(ref string) => write!(fmt, "{:?}", string),
            &Value::Symbol(ref string) => write!(fmt, "{}", string),
            &Value::Number(num) => write!(fmt, "{}", num),
            &Value::HardFunc(ref func) => write!(fmt, "HardFunc({:?})", func.args),
            &Value::Lambda { ref args, ref body }=> write!(fmt, "λ {:?} => {:?}", args, body),
            &Value::Nil => write!(fmt, "nil"),
            &Value::Bool(val) => write!(fmt, "{}", val),
            &Value::Quote(ref tok) => write!(fmt, "'{:?}", tok),
            &Value::Type(ref typ) => write!(fmt, "{:?}", typ),
            &Value::Foreign(ref val) => write!(fmt, "{:?}", val),
        }
    }
}
<|endoftext|>


<commit_before>//! A simple program that recursively changes the mode of all directories or
//! files to the given mode under the given directory. The following child
//! process will be executed and waited on, and it's exit code returned
//! `sh -c "find PATH -type TYPE -exec chmod MODE {} \;"`.
use std::env;
use std::fmt::Write as FmtWrite;
use std::io;
use std::path::Path;
use std::process;
use std::process::Command;

// Successful execution
const ESUCCESS: i32 = 0x00;
// No exit code found
const ENOEXIT: i32 = 0x01;
// Invalid usage
const EUSAGE: i32 = 0x02;

// Shell arguments (compatibility wrapper)
const SHELL_ARGS: &[&str] = &[
    "sh", "-c"
];
// Chmod arguments (recursive typed chmod)
const CHMOD_ARGS: &[&str] = &[
    "find", "-type", "-exec", "chmod", "{}", "\\;"
];

// The program name
const NAME: &str = "chmodrt";
// The program usage
const USAGE: &str = "Usage: chmodrt TYPE MODE PATH";
// The program options
const TYPES: &[&[&str]] = &[
    &["-d", "Change the mode of directories"],
    &["-f", "Change the mode of files"],
];

// Prepends the program name to the given message
macro_rules! formats {
    ($fmt:expr) => (format!(concat!("{}: ", $fmt), NAME));
    ($fmt:expr, $($arg:tt)*) => (format!(concat!("{}: ", $fmt), NAME, $($arg)*));
}

// Writes a formatted system message to the standard error
macro_rules! sprint {
    ($fmt:expr) => (eprint!("{}", formats!($fmt)));
    ($fmt:expr, $($arg:tt)*) => (eprint!("{}", formats!($fmt, $($arg)*)));
}

// Writes a formatted system message to the standard error with a new line
macro_rules! sprintln {
    () => (sprint!("\n"));
    ($fmt:expr) => (sprint!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (sprint!(concat!($fmt, "\n"), $($arg)*));
}

fn main() {
    process::exit(chmodrt(env::args().collect()));
}

fn chmodrt(args: Vec<String>) -> i32 {

    // Enforce correct usage
    if args.len() != 4 {
        print!("{}\n\n{}", USAGE, options());
        return EUSAGE;
    }

    // Check if the type is not a directory or a file
    if args[1] == TYPES[0][0] || args[1] == TYPES[1][0] {} else {
        sprintln!("unknown type: '{}'", args[1]);
        return EUSAGE;
    }

    // Authorize absolute paths
    if Path::new(&args[3]).has_root() {
        let stdin_err = formats!("cannot read from stdin");
        loop {
            // Reset the input buffer with every pass
            let mut input = String::new();

            // Print a confirmation prompt and wait for input
            sprint!("path is absolute - continue? [y/n] ");
            io::stdin().read_line(&mut input).expect(&stdin_err);

            // Normalize the input for comparison
            input = input.trim().to_lowercase();

            // The response must be 'y' or 'n'
            match input.as_str() {
                "y" => break,
                "n" => {
                    sprintln!("abort");
                    return ESUCCESS;
                },
                _ => continue,
            }
        }
    }

    // Construct the child process and error messages
    let find_command = format!("{} {} {} {} {} {} {} {} {}",
                               CHMOD_ARGS[0], args[3], CHMOD_ARGS[1], args[1].trim_left_matches("-"),
                               CHMOD_ARGS[2], CHMOD_ARGS[3], args[2], CHMOD_ARGS[4], CHMOD_ARGS[5]);
    let child_exec_err = formats!("failed to execute the child process: `{}`", SHELL_ARGS[0]);
    let child_wait_err = formats!("failed to wait on the child process: `{}`", SHELL_ARGS[0]);

    // Execute and wait on the child process
    let child = Command::new(SHELL_ARGS[0])
        .arg(SHELL_ARGS[1])
        .arg(find_command)
        .spawn().expect(&child_exec_err)
        .wait().expect(&child_wait_err);

    // Return the child exit code if it exists
    match child.code() {
        None => return ENOEXIT,
        Some(code) => return code,
    }
}

fn options() -> String {

    // Initialize the buffer and write the options header
    let mut buffer = String::with_capacity(128);
    writeln!(&mut buffer, "Types:").unwrap();

    // Enumerate the options and return the buffer
    for outer in TYPES.iter() {
        for inner in outer.iter() {
            write!(&mut buffer, "{:2}{}", "", inner).unwrap();
        }
        writeln!(&mut buffer, "").unwrap();
    }
    return buffer;
}
<commit_msg>Minor change<commit_after>//! A simple program that recursively changes the mode of all directories or
//! files to the given mode under the given directory. The following child
//! process will be executed and waited on, and it's exit code returned
//! `sh -c "find PATH -type TYPE -exec chmod MODE {} \;"`.
use std::env;
use std::fmt::Write as FmtWrite;
use std::io;
use std::path::Path;
use std::process;
use std::process::Command;

// Successful execution
const ESUCCESS: i32 = 0x00;
// No exit code found
const ENOEXIT: i32 = 0x01;
// Invalid usage
const EUSAGE: i32 = 0x02;

// Shell arguments (compatibility wrapper)
const SHELL_ARGS: &[&str] = &[
    "sh", "-c"
];
// Chmod arguments (recursive typed chmod)
const CHMOD_ARGS: &[&str] = &[
    "find", "-type", "-exec", "chmod", "{}", "\\;"
];

// The program name
const NAME: &str = "chmodrt";
// The program usage
const USAGE: &str = "Usage: chmodrt TYPE MODE PATH";
// The program options
const TYPES: &[&[&str]] = &[
    &["-d", "Change the mode of directories"],
    &["-f", "Change the mode of files"],
];

// Prepends the program name to the given message
macro_rules! formats {
    ($fmt:expr) => (format!(concat!("{}: ", $fmt), NAME));
    ($fmt:expr, $($arg:tt)*) => (format!(concat!("{}: ", $fmt), NAME, $($arg)*));
}

// Writes a formatted system message to the standard error
macro_rules! sprint {
    ($fmt:expr) => (eprint!("{}", formats!($fmt)));
    ($fmt:expr, $($arg:tt)*) => (eprint!("{}", formats!($fmt, $($arg)*)));
}

// Writes a formatted system message to the standard error with a new line
macro_rules! sprintln {
    () => (sprint!("\n"));
    ($fmt:expr) => (sprint!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (sprint!(concat!($fmt, "\n"), $($arg)*));
}

fn main() {
    process::exit(chmodrt(env::args().collect()));
}

fn chmodrt(args: Vec<String>) -> i32 {
    // Enforce correct usage
    if args.len() != 4 {
        print!("{}\n\n{}", USAGE, options());
        return EUSAGE;
    }

    // Check if the type is not a directory or a file
    if args[1] == TYPES[0][0] || args[1] == TYPES[1][0] {} else {
        sprintln!("unknown type: '{}'", args[1]);
        return EUSAGE;
    }

    // Authorize absolute paths
    if Path::new(&args[3]).has_root() {
        let stdin_err = formats!("cannot read from stdin");
        let mut input = String::new();
        loop {
            // Prompt the user and normalize the input
            sprint!("path is absolute - continue? [y/n] ");
            io::stdin().read_line(&mut input).expect(&stdin_err);
            input = input.trim().to_lowercase();

            // The response must be 'y' or 'n'
            match input.as_str() {
                "y" => break,
                "n" => {
                    sprintln!("abort");
                    return ESUCCESS;
                },
                _ => {
                    input.clear();
                    continue;
                },
            }
        }
    }

    // Construct the child process and error messages
    let find_command = format!("{} {} {} {} {} {} {} {} {}",
                               CHMOD_ARGS[0], args[3], CHMOD_ARGS[1], args[1].trim_left_matches("-"),
                               CHMOD_ARGS[2], CHMOD_ARGS[3], args[2], CHMOD_ARGS[4], CHMOD_ARGS[5]);
    let child_exec_err = formats!("failed to execute the child process: `{}`", SHELL_ARGS[0]);
    let child_wait_err = formats!("failed to wait on the child process: `{}`", SHELL_ARGS[0]);

    // Execute and wait on the child process
    let child = Command::new(SHELL_ARGS[0])
        .arg(SHELL_ARGS[1])
        .arg(find_command)
        .spawn().expect(&child_exec_err)
        .wait().expect(&child_wait_err);

    // Return the child exit code if it exists
    match child.code() {
        None => return ENOEXIT,
        Some(code) => return code,
    }
}

fn options() -> String {
    // Initialize the buffer and write the options header
    let mut buffer = String::with_capacity(128);
    writeln!(&mut buffer, "Types:").unwrap();

    // Enumerate the options and return the buffer
    for outer in TYPES.iter() {
        for inner in outer.iter() {
            write!(&mut buffer, "{:2}{}", "", inner).unwrap();
        }
        writeln!(&mut buffer, "").unwrap();
    }
    return buffer;
}
<|endoftext|>