<commit_before>use clock::Clock;

//
// Clock Creation
//

#[test]
fn test_on_the_hour() {
    assert_eq!(Clock::new(8, 0).to_string(), "08:00");
}

#[test]
fn test_past_the_hour() {
    assert_eq!(Clock::new(11, 9).to_string(), "11:09");
}

#[test]
fn test_midnight_is_zero_hours() {
    assert_eq!(Clock::new(24, 0).to_string(), "00:00");
}

#[test]
fn test_hour_rolls_over() {
    assert_eq!(Clock::new(25, 0).to_string(), "01:00");
}

#[test]
fn test_hour_rolls_over_continuously() {
    assert_eq!(Clock::new(100, 0).to_string(), "04:00");
}

#[test]
fn test_sixty_minutes_is_next_hour() {
    assert_eq!(Clock::new(1, 60).to_string(), "02:00");
}

#[test]
fn test_minutes_roll_over() {
    assert_eq!(Clock::new(0, 160).to_string(), "02:40");
}

#[test]
fn test_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(0, 1723).to_string(), "04:43");
}

#[test]
fn test_hours_and_minutes_roll_over() {
    assert_eq!(Clock::new(25, 160).to_string(), "03:40");
}

#[test]
fn test_hours_and_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(201, 3001).to_string(), "11:01");
}

#[test]
fn test_hours_and_minutes_roll_over_to_exactly_midnight() {
    assert_eq!(Clock::new(72, 8640).to_string(), "00:00");
}

#[test]
fn test_negative_hour() {
    assert_eq!(Clock::new(-1, 15).to_string(), "23:15");
}

#[test]
#[ignore]
fn test_negative_hour_roll_over() {
    assert_eq!(Clock::new(-25, 00).to_string(), "23:00");
}

#[test]
#[ignore]
fn test_negative_hour_roll_over_continuously() {
    assert_eq!(Clock::new(-91, 00).to_string(), "05:00");
}

#[test]
#[ignore]
fn test_negative_minutes() {
    assert_eq!(Clock::new(1, -40).to_string(), "00:20");
}

#[test]
#[ignore]
fn test_negative_minutes_roll_over() {
    assert_eq!(Clock::new(1, -160).to_string(), "22:20");
}

#[test]
#[ignore]
fn test_negative_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(1, -4820).to_string(), "16:40");
}

#[test]
#[ignore]
fn test_negative_sixty_minutes_is_prev_hour() {
    assert_eq!(Clock::new(2, -60).to_string(), "01:00");
}

#[test]
#[ignore]
fn test_negative_one_twenty_minutes_is_two_prev_hours() {
    assert_eq!(Clock::new(1, -120).to_string(), "23:00");
}

#[test]
#[ignore]
fn test_negative_hour_and_minutes_both_roll_over() {
    assert_eq!(Clock::new(-25, -160).to_string(), "20:20");
}

#[test]
#[ignore]
fn test_negative_hour_and_minutes_both_roll_over_continuously() {
    assert_eq!(Clock::new(-121, -5810).to_string(), "22:10");
}

#[test]
#[ignore]
fn test_zero_hour_and_negative_minutes() {
    assert_eq!(Clock::new(0, -22).to_string(), "23:38");
}

//
// Clock Math
//

#[test]
#[ignore]
fn test_add_minutes() {
    let clock = Clock::new(10, 0).add_minutes(3);
    assert_eq!(clock.to_string(), "10:03");
}

#[test]
#[ignore]
fn test_add_no_minutes() {
    let clock = Clock::new(6, 41).add_minutes(0);
    assert_eq!(clock.to_string(), "06:41");
}

#[test]
#[ignore]
fn test_add_to_next_hour() {
    let clock = Clock::new(0, 45).add_minutes(40);
    assert_eq!(clock.to_string(), "01:25");
}

#[test]
#[ignore]
fn test_add_more_than_one_hour() {
    let clock = Clock::new(10, 0).add_minutes(61);
    assert_eq!(clock.to_string(), "11:01");
}

#[test]
#[ignore]
fn test_add_more_than_two_hours_with_carry() {
    let clock = Clock::new(0, 45).add_minutes(160);
    assert_eq!(clock.to_string(), "03:25");
}

#[test]
#[ignore]
fn test_add_across_midnight() {
    let clock = Clock::new(23, 59).add_minutes(2);
    assert_eq!(clock.to_string(), "00:01");
}

#[test]
#[ignore]
fn test_add_more_than_one_day() {
    let clock = Clock::new(5, 32).add_minutes(1500);
    assert_eq!(clock.to_string(), "06:32");
}

#[test]
#[ignore]
fn test_add_more_than_two_days() {
    let clock = Clock::new(1, 1).add_minutes(3500);
    assert_eq!(clock.to_string(), "11:21");
}

#[test]
#[ignore]
fn test_subtract_minutes() {
    let clock = Clock::new(10, 3).add_minutes(-3);
    assert_eq!(clock.to_string(), "10:00");
}

#[test]
#[ignore]
fn test_subtract_to_previous_hour() {
    let clock = Clock::new(10, 3).add_minutes(-30);
    assert_eq!(clock.to_string(), "09:33");
}

#[test]
#[ignore]
fn test_subtract_more_than_an_hour() {
    let clock = Clock::new(10, 3).add_minutes(-70);
    assert_eq!(clock.to_string(), "08:53");
}

#[test]
#[ignore]
fn test_subtract_across_midnight() {
    let clock = Clock::new(0, 3).add_minutes(-4);
    assert_eq!(clock.to_string(), "23:59");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_hours() {
    let clock = Clock::new(0, 0).add_minutes(-160);
    assert_eq!(clock.to_string(), "21:20");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_hours_with_borrow() {
    let clock = Clock::new(6, 15).add_minutes(-160);
    assert_eq!(clock.to_string(), "03:35");
}

#[test]
#[ignore]
fn test_subtract_more_than_one_day() {
    let clock = Clock::new(5, 32).add_minutes(-1500);
    assert_eq!(clock.to_string(), "04:32");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_days() {
    let clock = Clock::new(2, 20).add_minutes(-3000);
    assert_eq!(clock.to_string(), "00:20");
}

//
// Test Equality
//

#[test]
#[ignore]
fn test_compare_clocks_for_equality() {
    assert_eq!(Clock::new(15, 37), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_a_minute_apart() {
    assert_ne!(Clock::new(15, 36), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_an_hour_apart() {
    assert_ne!(Clock::new(14, 37), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_with_hour_overflow() {
    assert_eq!(Clock::new(10, 37), Clock::new(34, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_with_hour_overflow_by_several_days() {
    assert_eq!(Clock::new(99, 11), Clock::new(3, 11));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour() {
    assert_eq!(Clock::new(-2, 40), Clock::new(22, 40));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour_that_wraps() {
    assert_eq!(Clock::new(-31, 3), Clock::new(17, 3));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour_that_wraps_multiple_times() {
    assert_eq!(Clock::new(-83, 49), Clock::new(13, 49));
}

#[test]
#[ignore]
fn test_compare_clocks_with_minutes_overflow() {
    assert_eq!(Clock::new(0, 1441), Clock::new(0, 1));
}

#[test]
#[ignore]
fn test_compare_clocks_with_minutes_overflow_by_several_days() {
    assert_eq!(Clock::new(2, 4322), Clock::new(2, 2));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute() {
    assert_eq!(Clock::new(3, -20), Clock::new(2, 40));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute_that_wraps() {
    assert_eq!(Clock::new(5, -1490), Clock::new(4, 10));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute_that_wraps_multiple() {
    assert_eq!(Clock::new(6, -4305), Clock::new(6, 15));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hours_and_minutes() {
    assert_eq!(Clock::new(-12, -268), Clock::new(7, 32));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hours_and_minutes_that_wrap() {
    assert_eq!(Clock::new(-54, -11_513), Clock::new(18, 7));
}

#[test]
#[ignore]
fn test_compare_full_clock_and_zeroed_clock() {
    assert_eq!(Clock::new(24, 0), Clock::new(0, 0));
}
<commit_msg>Uncomment passing tests<commit_after>use clock::Clock;

//
// Clock Creation
//

#[test]
fn test_on_the_hour() {
    assert_eq!(Clock::new(8, 0).to_string(), "08:00");
}

#[test]
fn test_past_the_hour() {
    assert_eq!(Clock::new(11, 9).to_string(), "11:09");
}

#[test]
fn test_midnight_is_zero_hours() {
    assert_eq!(Clock::new(24, 0).to_string(), "00:00");
}

#[test]
fn test_hour_rolls_over() {
    assert_eq!(Clock::new(25, 0).to_string(), "01:00");
}

#[test]
fn test_hour_rolls_over_continuously() {
    assert_eq!(Clock::new(100, 0).to_string(), "04:00");
}

#[test]
fn test_sixty_minutes_is_next_hour() {
    assert_eq!(Clock::new(1, 60).to_string(), "02:00");
}

#[test]
fn test_minutes_roll_over() {
    assert_eq!(Clock::new(0, 160).to_string(), "02:40");
}

#[test]
fn test_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(0, 1723).to_string(), "04:43");
}

#[test]
fn test_hours_and_minutes_roll_over() {
    assert_eq!(Clock::new(25, 160).to_string(), "03:40");
}

#[test]
fn test_hours_and_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(201, 3001).to_string(), "11:01");
}

#[test]
fn test_hours_and_minutes_roll_over_to_exactly_midnight() {
    assert_eq!(Clock::new(72, 8640).to_string(), "00:00");
}

#[test]
fn test_negative_hour() {
    assert_eq!(Clock::new(-1, 15).to_string(), "23:15");
}

#[test]
fn test_negative_hour_roll_over() {
    assert_eq!(Clock::new(-25, 00).to_string(), "23:00");
}

#[test]
fn test_negative_hour_roll_over_continuously() {
    assert_eq!(Clock::new(-91, 00).to_string(), "05:00");
}

#[test]
#[ignore]
fn test_negative_minutes() {
    assert_eq!(Clock::new(1, -40).to_string(), "00:20");
}

#[test]
#[ignore]
fn test_negative_minutes_roll_over() {
    assert_eq!(Clock::new(1, -160).to_string(), "22:20");
}

#[test]
#[ignore]
fn test_negative_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(1, -4820).to_string(), "16:40");
}

#[test]
#[ignore]
fn test_negative_sixty_minutes_is_prev_hour() {
    assert_eq!(Clock::new(2, -60).to_string(), "01:00");
}

#[test]
#[ignore]
fn test_negative_one_twenty_minutes_is_two_prev_hours() {
    assert_eq!(Clock::new(1, -120).to_string(), "23:00");
}

#[test]
#[ignore]
fn test_negative_hour_and_minutes_both_roll_over() {
    assert_eq!(Clock::new(-25, -160).to_string(), "20:20");
}

#[test]
#[ignore]
fn test_negative_hour_and_minutes_both_roll_over_continuously() {
    assert_eq!(Clock::new(-121, -5810).to_string(), "22:10");
}

#[test]
#[ignore]
fn test_zero_hour_and_negative_minutes() {
    assert_eq!(Clock::new(0, -22).to_string(), "23:38");
}

//
// Clock Math
//

#[test]
#[ignore]
fn test_add_minutes() {
    let clock = Clock::new(10, 0).add_minutes(3);
    assert_eq!(clock.to_string(), "10:03");
}

#[test]
#[ignore]
fn test_add_no_minutes() {
    let clock = Clock::new(6, 41).add_minutes(0);
    assert_eq!(clock.to_string(), "06:41");
}

#[test]
#[ignore]
fn test_add_to_next_hour() {
    let clock = Clock::new(0, 45).add_minutes(40);
    assert_eq!(clock.to_string(), "01:25");
}

#[test]
#[ignore]
fn test_add_more_than_one_hour() {
    let clock = Clock::new(10, 0).add_minutes(61);
    assert_eq!(clock.to_string(), "11:01");
}

#[test]
#[ignore]
fn test_add_more_than_two_hours_with_carry() {
    let clock = Clock::new(0, 45).add_minutes(160);
    assert_eq!(clock.to_string(), "03:25");
}

#[test]
#[ignore]
fn test_add_across_midnight() {
    let clock = Clock::new(23, 59).add_minutes(2);
    assert_eq!(clock.to_string(), "00:01");
}

#[test]
#[ignore]
fn test_add_more_than_one_day() {
    let clock = Clock::new(5, 32).add_minutes(1500);
    assert_eq!(clock.to_string(), "06:32");
}

#[test]
#[ignore]
fn test_add_more_than_two_days() {
    let clock = Clock::new(1, 1).add_minutes(3500);
    assert_eq!(clock.to_string(), "11:21");
}

#[test]
#[ignore]
fn test_subtract_minutes() {
    let clock = Clock::new(10, 3).add_minutes(-3);
    assert_eq!(clock.to_string(), "10:00");
}

#[test]
#[ignore]
fn test_subtract_to_previous_hour() {
    let clock = Clock::new(10, 3).add_minutes(-30);
    assert_eq!(clock.to_string(), "09:33");
}

#[test]
#[ignore]
fn test_subtract_more_than_an_hour() {
    let clock = Clock::new(10, 3).add_minutes(-70);
    assert_eq!(clock.to_string(), "08:53");
}

#[test]
#[ignore]
fn test_subtract_across_midnight() {
    let clock = Clock::new(0, 3).add_minutes(-4);
    assert_eq!(clock.to_string(), "23:59");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_hours() {
    let clock = Clock::new(0, 0).add_minutes(-160);
    assert_eq!(clock.to_string(), "21:20");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_hours_with_borrow() {
    let clock = Clock::new(6, 15).add_minutes(-160);
    assert_eq!(clock.to_string(), "03:35");
}

#[test]
#[ignore]
fn test_subtract_more_than_one_day() {
    let clock = Clock::new(5, 32).add_minutes(-1500);
    assert_eq!(clock.to_string(), "04:32");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_days() {
    let clock = Clock::new(2, 20).add_minutes(-3000);
    assert_eq!(clock.to_string(), "00:20");
}

//
// Test Equality
//

#[test]
#[ignore]
fn test_compare_clocks_for_equality() {
    assert_eq!(Clock::new(15, 37), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_a_minute_apart() {
    assert_ne!(Clock::new(15, 36), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_an_hour_apart() {
    assert_ne!(Clock::new(14, 37), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_with_hour_overflow() {
    assert_eq!(Clock::new(10, 37), Clock::new(34, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_with_hour_overflow_by_several_days() {
    assert_eq!(Clock::new(99, 11), Clock::new(3, 11));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour() {
    assert_eq!(Clock::new(-2, 40), Clock::new(22, 40));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour_that_wraps() {
    assert_eq!(Clock::new(-31, 3), Clock::new(17, 3));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour_that_wraps_multiple_times() {
    assert_eq!(Clock::new(-83, 49), Clock::new(13, 49));
}

#[test]
#[ignore]
fn test_compare_clocks_with_minutes_overflow() {
    assert_eq!(Clock::new(0, 1441), Clock::new(0, 1));
}

#[test]
#[ignore]
fn test_compare_clocks_with_minutes_overflow_by_several_days() {
    assert_eq!(Clock::new(2, 4322), Clock::new(2, 2));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute() {
    assert_eq!(Clock::new(3, -20), Clock::new(2, 40));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute_that_wraps() {
    assert_eq!(Clock::new(5, -1490), Clock::new(4, 10));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute_that_wraps_multiple() {
    assert_eq!(Clock::new(6, -4305), Clock::new(6, 15));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hours_and_minutes() {
    assert_eq!(Clock::new(-12, -268), Clock::new(7, 32));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hours_and_minutes_that_wrap() {
    assert_eq!(Clock::new(-54, -11_513), Clock::new(18, 7));
}

#[test]
#[ignore]
fn test_compare_full_clock_and_zeroed_clock() {
    assert_eq!(Clock::new(24, 0), Clock::new(0, 0));
}
<|endoftext|>


<commit_before>use std::ops::*;

const P: i64 = 1_000_000_007;

/// Calculates `x^n`. O(log n) time.
/// By Fermat's little theorem, `x^(-1) = pow(x, P - 2)`.
pub fn pow(x: i64, n: i64) -> i64 {
    let (mut x, mut y, mut n) = (x % P, 1_i64, n);
    while n > 0 {
        if n % 2 != 0 {
            y = (y * x) % P;
            n -= 1;
        }

        x = (x * x) % P;
        n /= 2;
    }
    y
}

/// Calculates `a^(-1)` for each `a` in `1..n`.
pub fn inv_dp(n: usize) -> Vec<i64> {
    let mut dp = vec![0; n];
    if n >= 2 {
        dp[1] = 1;
        for i in 2..n {
            let mut z = P - dp[(P % i as i64) as usize];
            z %= P;
            z *= P / i as i64;
            z %= P;
            dp[i] = z;
        }
    }
    dp
}

/// Represents an element of finite field.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
struct Finite<T>(T);

trait Normalize {
    fn normalize(&mut self);
}

impl<T> From<T> for Finite<T>
where
    Finite<T>: Normalize,
{
    fn from(value: T) -> Self {
        let mut it = Finite(value);
        it.normalize();
        it
    }
}

// Derive binary operation trait from the `FooAssign` impl.
// Define `x + y` as `{ let mut x = x.clone(); x += y; x }`.
macro_rules! impl_binary_op_for_finite {
    ($op_trait:ident, $op:ident, $assign_trait:ident, $assign:ident) => {
        impl<T: $op_trait<T, Output = T>> $op_trait<T> for Finite<T>
        where
            Finite<T>: Clone + $assign_trait<T>,
        {
            type Output = Self;

            fn $op(self, other: T) -> Self {
                let mut it = self.clone();
                it.$assign(other);
                it
            }
        }

        impl<T: $op_trait<T, Output = T>> $op_trait<Finite<T>> for Finite<T>
        where
            Finite<T>: Clone + $assign_trait<Finite<T>>,
        {
            type Output = Self;

            fn $op(self, other: Self) -> Self {
                let mut it = self.clone();
                it.$assign(other);
                it
            }
        }
    };
}

// Derive assign operation trait by unwrapping the right hand side.
macro_rules! impl_binary_op_assign_with_finite_for_finite {
    ($op_trait:ident, $op:ident) => {
        impl<T> $op_trait<Finite<T>> for Finite<T>
        where
            Finite<T>: $op_trait<T>,
        {
            fn $op(&mut self, other: Self) {
                self.$op(other.0);
            }
        }
    };
}

// Derive assign operation trait from impl for inner type.
macro_rules! impl_binary_op_assign_with_inner_for_finite {
    ($op_trait:ident, $op:ident) => {
        impl<T: $op_trait<T>> $op_trait<T> for Finite<T>
        where
            Finite<T>: Normalize,
        {
            fn $op(&mut self, other: T) {
                let mut other = Finite::from(other);
                other.normalize();
                (self.0).$op(other.0);
                self.normalize();
            }
        }
    };
}

impl_binary_op_for_finite! {Add, add, AddAssign, add_assign}
impl_binary_op_for_finite! {Sub, sub, SubAssign, sub_assign}
impl_binary_op_for_finite! {Mul, mul, MulAssign, mul_assign}
impl_binary_op_for_finite! {Div, div, DivAssign, div_assign}
impl_binary_op_assign_with_inner_for_finite! {AddAssign, add_assign}
impl_binary_op_assign_with_inner_for_finite! {SubAssign, sub_assign}
impl_binary_op_assign_with_inner_for_finite! {MulAssign, mul_assign}
impl_binary_op_assign_with_finite_for_finite! {AddAssign, add_assign}
impl_binary_op_assign_with_finite_for_finite! {SubAssign, sub_assign}
impl_binary_op_assign_with_finite_for_finite! {MulAssign, mul_assign}
impl_binary_op_assign_with_finite_for_finite! {DivAssign, div_assign}

impl Finite<i64> {
    fn pow(self, e: i64) -> Self {
        pow(self.0, e).into()
    }
}

impl Normalize for Finite<i64> {
    fn normalize(&mut self) {
        self.0 %= P;
        self.0 += P;
        self.0 %= P;
    }
}

impl DivAssign<i64> for Finite<i64> {
    fn div_assign(&mut self, other: i64) {
        *self *= Self::from(other).pow(P - 2);
    }
}

#[cfg(test)]
mod tests {
    use super::{inv_dp, pow, Finite, P};
    use std;

    #[test]
    fn test_pow_edges() {
        assert_eq!(pow(0, 0), 1);
        assert_eq!(pow(2, 0), 1);
        assert_eq!(pow(3, 1), 3);
        assert_eq!(pow(5, 6), (5 * 5 * 5) * (5 * 5 * 5));
        assert_eq!(pow(std::i64::MAX % P, std::i64::MAX), 856225998);
    }

    #[test]
    fn test_pow_small() {
        for x in 0..100_i64 {
            for n in 0..100_i64 {
                let actual = pow(x, n);
                let expected = (0..n).fold(1_i64, |acc, _| (acc * x) % P);
                assert_eq!(actual, expected, "{}^{}", x, n);
            }
        }
    }

    #[test]
    fn test_inv_dp() {
        let n = 10000;
        let dp = inv_dp(n);
        for i in 1..n {
            let mut z = dp[i] * i as i64;
            z %= P;
            z += P;
            z %= P;
            assert_eq!(z, 1);
        }
    }

    #[test]
    fn test_finite() {
        let x = Finite::from(P + 2);

        // `from` should normalize the value.
        assert_eq!(x.0, 2);

        // Operations.
        assert_eq!(x + 7, (2 + 7).into());
        assert_eq!(x - 7, (P + (2 - 7)).into());
        assert_eq!(x * 3, (2 * 3).into());
        assert_eq!((x / 11) * 11, 2.into());

        assert_eq!(x + Finite::from(7), (2 + 7).into());
        assert_eq!(x - Finite::from(7), (P + (2 - 7)).into());
        assert_eq!(x * Finite::from(3), (2 * 3).into());
        assert_eq!((x / Finite::from(11)) * 11, 2.into());

        let mut x = x;
        x += 7;
        assert_eq!(x, 9.into());
        x -= 5;
        assert_eq!(x, 4.into());
        x *= 6;
        assert_eq!(x, 24.into());
        x /= 3;
        assert_eq!(x, 8.into());
    }
}
<commit_msg>feat: Write custom Debug impl for `Finite`<commit_after>use std;
use std::fmt::{Debug, Formatter};
use std::ops::*;

const P: i64 = 1_000_000_007;

/// Calculates `x^n`. O(log n) time.
/// By Fermat's little theorem, `x^(-1) = pow(x, P - 2)`.
pub fn pow(x: i64, n: i64) -> i64 {
    let (mut x, mut y, mut n) = (x % P, 1_i64, n);
    while n > 0 {
        if n % 2 != 0 {
            y = (y * x) % P;
            n -= 1;
        }

        x = (x * x) % P;
        n /= 2;
    }
    y
}

/// Calculates `a^(-1)` for each `a` in `1..n`.
pub fn inv_dp(n: usize) -> Vec<i64> {
    let mut dp = vec![0; n];
    if n >= 2 {
        dp[1] = 1;
        for i in 2..n {
            let mut z = P - dp[(P % i as i64) as usize];
            z %= P;
            z *= P / i as i64;
            z %= P;
            dp[i] = z;
        }
    }
    dp
}

/// Represents an element of finite field.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
struct Finite<T>(T);

impl<T: Debug> Debug for Finite<T> {
    fn fmt(&self, formatter: &mut Formatter) -> std::fmt::Result {
        formatter.write_fmt(format_args!("{:?}", self.0))
    }
}

trait Normalize {
    fn normalize(&mut self);
}

impl<T> From<T> for Finite<T>
where
    Finite<T>: Normalize,
{
    fn from(value: T) -> Self {
        let mut it = Finite(value);
        it.normalize();
        it
    }
}

// Derive binary operation trait from the `FooAssign` impl.
// Define `x + y` as `{ let mut x = x.clone(); x += y; x }`.
macro_rules! impl_binary_op_for_finite {
    ($op_trait:ident, $op:ident, $assign_trait:ident, $assign:ident) => {
        impl<T: $op_trait<T, Output = T>> $op_trait<T> for Finite<T>
        where
            Finite<T>: Clone + $assign_trait<T>,
        {
            type Output = Self;

            fn $op(self, other: T) -> Self {
                let mut it = self.clone();
                it.$assign(other);
                it
            }
        }

        impl<T: $op_trait<T, Output = T>> $op_trait<Finite<T>> for Finite<T>
        where
            Finite<T>: Clone + $assign_trait<Finite<T>>,
        {
            type Output = Self;

            fn $op(self, other: Self) -> Self {
                let mut it = self.clone();
                it.$assign(other);
                it
            }
        }
    };
}

// Derive assign operation trait by unwrapping the right hand side.
macro_rules! impl_binary_op_assign_with_finite_for_finite {
    ($op_trait:ident, $op:ident) => {
        impl<T> $op_trait<Finite<T>> for Finite<T>
        where
            Finite<T>: $op_trait<T>,
        {
            fn $op(&mut self, other: Self) {
                self.$op(other.0);
            }
        }
    };
}

// Derive assign operation trait from impl for inner type.
macro_rules! impl_binary_op_assign_with_inner_for_finite {
    ($op_trait:ident, $op:ident) => {
        impl<T: $op_trait<T>> $op_trait<T> for Finite<T>
        where
            Finite<T>: Normalize,
        {
            fn $op(&mut self, other: T) {
                let mut other = Finite::from(other);
                other.normalize();
                (self.0).$op(other.0);
                self.normalize();
            }
        }
    };
}

impl_binary_op_for_finite! {Add, add, AddAssign, add_assign}
impl_binary_op_for_finite! {Sub, sub, SubAssign, sub_assign}
impl_binary_op_for_finite! {Mul, mul, MulAssign, mul_assign}
impl_binary_op_for_finite! {Div, div, DivAssign, div_assign}
impl_binary_op_assign_with_inner_for_finite! {AddAssign, add_assign}
impl_binary_op_assign_with_inner_for_finite! {SubAssign, sub_assign}
impl_binary_op_assign_with_inner_for_finite! {MulAssign, mul_assign}
impl_binary_op_assign_with_finite_for_finite! {AddAssign, add_assign}
impl_binary_op_assign_with_finite_for_finite! {SubAssign, sub_assign}
impl_binary_op_assign_with_finite_for_finite! {MulAssign, mul_assign}
impl_binary_op_assign_with_finite_for_finite! {DivAssign, div_assign}

impl Finite<i64> {
    fn pow(self, e: i64) -> Self {
        pow(self.0, e).into()
    }
}

impl Normalize for Finite<i64> {
    fn normalize(&mut self) {
        self.0 %= P;
        self.0 += P;
        self.0 %= P;
    }
}

impl DivAssign<i64> for Finite<i64> {
    fn div_assign(&mut self, other: i64) {
        *self *= Self::from(other).pow(P - 2);
    }
}

#[cfg(test)]
mod tests {
    use super::{inv_dp, pow, Finite, P};
    use std;

    #[test]
    fn test_pow_edges() {
        assert_eq!(pow(0, 0), 1);
        assert_eq!(pow(2, 0), 1);
        assert_eq!(pow(3, 1), 3);
        assert_eq!(pow(5, 6), (5 * 5 * 5) * (5 * 5 * 5));
        assert_eq!(pow(std::i64::MAX % P, std::i64::MAX), 856225998);
    }

    #[test]
    fn test_pow_small() {
        for x in 0..100_i64 {
            for n in 0..100_i64 {
                let actual = pow(x, n);
                let expected = (0..n).fold(1_i64, |acc, _| (acc * x) % P);
                assert_eq!(actual, expected, "{}^{}", x, n);
            }
        }
    }

    #[test]
    fn test_inv_dp() {
        let n = 10000;
        let dp = inv_dp(n);
        for i in 1..n {
            let mut z = dp[i] * i as i64;
            z %= P;
            z += P;
            z %= P;
            assert_eq!(z, 1);
        }
    }

    #[test]
    fn test_finite() {
        let x = Finite::from(P + 2);

        // `from` should normalize the value.
        assert_eq!(x.0, 2);

        // Operations.
        assert_eq!(x + 7, (2 + 7).into());
        assert_eq!(x - 7, (P + (2 - 7)).into());
        assert_eq!(x * 3, (2 * 3).into());
        assert_eq!((x / 11) * 11, 2.into());

        assert_eq!(x + Finite::from(7), (2 + 7).into());
        assert_eq!(x - Finite::from(7), (P + (2 - 7)).into());
        assert_eq!(x * Finite::from(3), (2 * 3).into());
        assert_eq!((x / Finite::from(11)) * 11, 2.into());

        let mut x = x;
        x += 7;
        assert_eq!(x, 9.into());
        x -= 5;
        assert_eq!(x, 4.into());
        x *= 6;
        assert_eq!(x, 24.into());
        x /= 3;
        assert_eq!(x, 8.into());
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "image")]
use image;

/// A trait that must be implemented for any type that can represent the value of a pixel.
pub trait PixelValue: Copy + Send + 'static {     // TODO: Clone, but [T, ..N] doesn't impl Clone
    /// Returns corresponding client format.
    fn get_format() -> super::ClientFormat;
}

impl PixelValue for i8 {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I8
    }
}

impl PixelValue for (i8, i8) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I8I8
    }
}

impl PixelValue for (i8, i8, i8) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I8I8I8
    }
}

impl PixelValue for (i8, i8, i8, i8) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I8I8I8I8
    }
}

impl PixelValue for u8 {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U8
    }
}

impl PixelValue for (u8, u8) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U8U8
    }
}

impl PixelValue for (u8, u8, u8) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U8U8U8
    }
}

impl PixelValue for (u8, u8, u8, u8) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U8U8U8U8
    }
}

impl PixelValue for i16 {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I16
    }
}

impl PixelValue for (i16, i16) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I16I16
    }
}

impl PixelValue for (i16, i16, i16) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I16I16I16
    }
}

impl PixelValue for (i16, i16, i16, i16) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I16I16I16I16
    }
}

impl PixelValue for u16 {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U16
    }
}

impl PixelValue for (u16, u16) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U16U16
    }
}

impl PixelValue for (u16, u16, u16) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U16U16U16
    }
}

impl PixelValue for (u16, u16, u16, u16) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U16U16U16U16
    }
}

impl PixelValue for i32 {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I32
    }
}

impl PixelValue for (i32, i32) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I32I32
    }
}

impl PixelValue for (i32, i32, i32) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I32I32I32
    }
}

impl PixelValue for (i32, i32, i32, i32) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I32I32I32I32
    }
}

impl PixelValue for u32 {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U32
    }
}

impl PixelValue for (u32, u32) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U32U32
    }
}

impl PixelValue for (u32, u32, u32) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U32U32U32
    }
}

impl PixelValue for (u32, u32, u32, u32) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U32U32U32U32
    }
}

impl PixelValue for f32 {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::F32
    }
}

impl PixelValue for (f32, f32) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::F32F32
    }
}

impl PixelValue for (f32, f32, f32) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::F32F32F32
    }
}

impl PixelValue for (f32, f32, f32, f32) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::F32F32F32F32
    }
}

#[cfg(feature = "image")]
impl PixelValue for image::Rgb<u8> {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U8U8U8
    }
}

#[cfg(feature = "image")]
impl PixelValue for image::Rgba<u8> {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U8U8U8U8
    }
}

#[cfg(feature = "image")]
impl PixelValue for image::Luma<u8> {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U8
    }
}

#[cfg(feature = "image")]
impl PixelValue for image::Luma<u16> {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U16
    }
}

#[cfg(feature = "image")]
impl PixelValue for image::Luma<f32> {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::F32
    }
}

#[cfg(feature = "image")]
impl PixelValue for image::LumaA<u8> {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U8U8
    }
}

#[cfg(feature = "image")]
impl PixelValue for image::LumaA<u16> {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U16U16
    }
}

#[cfg(feature = "image")]
impl PixelValue for image::LumaA<f32> {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::F32F32
    }
}
<commit_msg>Make the PixelValue trait unsafe<commit_after>#[cfg(feature = "image")]
use image;

/// A trait that must be implemented for any type that can represent the value of a pixel.
pub unsafe trait PixelValue: Copy + Clone + Send + 'static {
    /// Returns corresponding client format.
    fn get_format() -> super::ClientFormat;
}

unsafe impl PixelValue for i8 {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I8
    }
}

unsafe impl PixelValue for (i8, i8) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I8I8
    }
}

unsafe impl PixelValue for (i8, i8, i8) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I8I8I8
    }
}

unsafe impl PixelValue for (i8, i8, i8, i8) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I8I8I8I8
    }
}

unsafe impl PixelValue for u8 {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U8
    }
}

unsafe impl PixelValue for (u8, u8) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U8U8
    }
}

unsafe impl PixelValue for (u8, u8, u8) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U8U8U8
    }
}

unsafe impl PixelValue for (u8, u8, u8, u8) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U8U8U8U8
    }
}

unsafe impl PixelValue for i16 {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I16
    }
}

unsafe impl PixelValue for (i16, i16) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I16I16
    }
}

unsafe impl PixelValue for (i16, i16, i16) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I16I16I16
    }
}

unsafe impl PixelValue for (i16, i16, i16, i16) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I16I16I16I16
    }
}

unsafe impl PixelValue for u16 {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U16
    }
}

unsafe impl PixelValue for (u16, u16) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U16U16
    }
}

unsafe impl PixelValue for (u16, u16, u16) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U16U16U16
    }
}

unsafe impl PixelValue for (u16, u16, u16, u16) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U16U16U16U16
    }
}

unsafe impl PixelValue for i32 {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I32
    }
}

unsafe impl PixelValue for (i32, i32) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I32I32
    }
}

unsafe impl PixelValue for (i32, i32, i32) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I32I32I32
    }
}

unsafe impl PixelValue for (i32, i32, i32, i32) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::I32I32I32I32
    }
}

unsafe impl PixelValue for u32 {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U32
    }
}

unsafe impl PixelValue for (u32, u32) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U32U32
    }
}

unsafe impl PixelValue for (u32, u32, u32) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U32U32U32
    }
}

unsafe impl PixelValue for (u32, u32, u32, u32) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U32U32U32U32
    }
}

unsafe impl PixelValue for f32 {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::F32
    }
}

unsafe impl PixelValue for (f32, f32) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::F32F32
    }
}

unsafe impl PixelValue for (f32, f32, f32) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::F32F32F32
    }
}

unsafe impl PixelValue for (f32, f32, f32, f32) {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::F32F32F32F32
    }
}

#[cfg(feature = "image")]
unsafe impl PixelValue for image::Rgb<u8> {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U8U8U8
    }
}

#[cfg(feature = "image")]
unsafe impl PixelValue for image::Rgba<u8> {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U8U8U8U8
    }
}

#[cfg(feature = "image")]
unsafe impl PixelValue for image::Luma<u8> {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U8
    }
}

#[cfg(feature = "image")]
unsafe impl PixelValue for image::Luma<u16> {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U16
    }
}

#[cfg(feature = "image")]
unsafe impl PixelValue for image::Luma<f32> {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::F32
    }
}

#[cfg(feature = "image")]
unsafe impl PixelValue for image::LumaA<u8> {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U8U8
    }
}

#[cfg(feature = "image")]
unsafe impl PixelValue for image::LumaA<u16> {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::U16U16
    }
}

#[cfg(feature = "image")]
unsafe impl PixelValue for image::LumaA<f32> {
    fn get_format() -> super::ClientFormat {
        super::ClientFormat::F32F32
    }
}
<|endoftext|>


<commit_before>use anyhow::Result;
use clap::Parser;
use regex::Regex;
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;

use polars::frame::DataFrame;
use polars::prelude::*;

use log::{info, warn};

pub mod augment;
pub mod configuration;
pub mod filtering;
pub mod sdrf;

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
    /// Path where input has been copied. Must contain the config files
    #[clap(short, long, multiple_values(true))]
    input: PathBuf,

    /// An output file
    #[clap(short, long)]
    output: String,

    /// The column to select. If files have no headers, use "column_N"
    #[clap(short, long, multiple_values(true))]
    select: Vec<String>,
}

fn load_df_add_experiment(path: &PathBuf) -> Result<DataFrame, polars::prelude::PolarsError> {
    info!("Loading experiment data from {:?}", path);
    let exp_name = path
        .file_name()
        .unwrap()
        .to_str()
        .unwrap()
        .split('-')
        .collect::<Vec<&str>>()[0..=2]
        .join("-")
        .replace("_A", "");

    let mut exp_df: DataFrame = CsvReader::from_path(&path)?
        .has_header(true)
        .with_delimiter(b'\t')
        .with_null_values(Some(NullValues::AllColumns("NA".to_string())))
        .infer_schema(None)
        .finish()
        .unwrap_or_else(|x| panic!("Failed on {:?} with error {:?}", path, x));

    // hstack the experiment name (derived from the filename) into the DataFrame
    let mut exp_col_arr = Utf8ChunkedBuilder::new("experiment", exp_df.height(), 128);
    for _i in 0..exp_df.height() {
        exp_col_arr.append_value(&exp_name);
    }
    // let iter_exp = std::iter::repeat([&exp_name].into_iter()).take(exp_df.height());
    let exp_col: Series = exp_col_arr.finish().into_series();
    exp_df.hstack_mut(&[exp_col]).unwrap();

    if !&exp_df.get_column_names().contains(&"GeneID") {
        // normalise column names
        info!("Standard column heading not found, normalising column names");
        info!("Column names were {:?}", &exp_df.get_column_names());
        if exp_df.get_column_names().contains(&"Gene ID") {
            exp_df.rename("Gene ID", "GeneID")?;
        } else if exp_df.get_column_names().contains(&"Gene.ID") {
            exp_df.rename("Gene.ID", "GeneID")?;
        }
        info!("Column names are now {:?}", &exp_df.get_column_names());
    }

    Ok(exp_df)
}

fn main() -> Result<()> {
    env_logger::init();
    info!("Starting Expression Atlas parser");
    let args = Args::parse();

    // Parse the config files first
    // set up the regex
    let config_re = Regex::new(r"configuration.xml").unwrap();
    let mut config_lookup: HashMap<String, configuration::Config> = HashMap::new();
    for file in fs::read_dir(&args.input)? {
        let file = file?;
        let path = file.path();
        if config_re.is_match(path.to_str().unwrap()) {
            let exp_name = path
                .file_name()
                .unwrap()
                .to_str()
                .unwrap()
                .split('-')
                .collect::<Vec<&str>>()[0..=2]
                .join("-")
                .replace("configuration", ""); // yeah...
            let config = configuration::parse_config(&path)?;
            config_lookup.insert(exp_name, config);
        }
    }

    // Now have a hashmap with exp_name:config. We can loop over it and
    // - Check config for experiment type
    // - Construct appropriate filenames
    // - Dispatch filenames for loading, appropriate error handling if they don't exist
    // - Construct new df to merge with big one

    let differential_re = Regex::new(r".*diff.*").unwrap();

    let mut big_df = DataFrame::default();
     // String::new();
    //  data_path = PathBuf::from(&args.input);
    // let mut sdrf_path = PathBuf::from(&args.input);

    let mut gene_count: usize = 0;

    for (exp_name, config) in &config_lookup {
        let mut exp_df = DataFrame::default();
        let mut data_path = PathBuf::from(&args.input);
        let mut sdrf_path = PathBuf::from(&args.input);
        if differential_re.is_match(&config.exp_type) {
            for analysis in &config.analytics {
                let array_design = analysis.array_design.as_deref().unwrap_or("");
                if !array_design.is_empty() {
                    let data_filename: String = format!("{}_{}-analytics.tsv", exp_name, array_design);
                    data_path.push(&data_filename);

                    if !data_path.exists() {
                        warn!(
                            "File {} does not exist, skipping this experiment",
                            data_path.to_str().unwrap()
                        );
                        data_path.pop();
                        continue;
                    }

                    // Load the data
                    if exp_df.height() == 0 {
                        exp_df = load_df_add_experiment(&data_path)?;
                        data_path.pop();
                    } else {
                        exp_df = exp_df
                            .lazy()
                            .join(
                                load_df_add_experiment(&data_path)?.lazy(),
                                [col("GeneID")],
                                [col("GeneID")],
                                JoinType::Inner,
                            )
                            .select(&[col("*").exclude([
                                "Gene Name_right",
                                "experiment_right",
                                "Design Element_right",
                            ])])
                            .collect()?;
                        data_path.pop();
                    }
                } else {
                    let data_filename: String  = format!("{}-analytics.tsv", exp_name);
                    data_path.push(&data_filename);

                    if !data_path.exists() {
                        warn!(
                            "File {} does not exist, skipping this experiment",
                            data_path.to_str().unwrap()
                        );
                        data_path.pop();
                        continue;
                    }

                    exp_df = load_df_add_experiment(&data_path)?;
                    data_path.pop();
                }
            }
        } else {
            let data_filename: String = format!("{}-tpms.tsv", exp_name);
            data_path.push(&data_filename);

            if !data_path.exists() {
                warn!(
                    "File {} does not exist, skipping this experiment",
                    data_path.to_str().unwrap()
                );
                data_path.pop();
                continue;
            }

            exp_df = load_df_add_experiment(&data_path)?;
            data_path.pop();
        }

        let sdrf_filename: String = format!("{}.condensed-sdrf.tsv", exp_name);
        sdrf_path.push(&sdrf_filename);

        if !sdrf_path.exists() {
            warn!(
                "File {} does not exist, skipping this experiment",
                sdrf_path.to_str().unwrap()
            );
            sdrf_path.pop();
            data_path.pop();
            continue;
        }

        // Now load the sdrf
        let sdrf_df = sdrf::parse_condensed_sdrf(&sdrf_path)?;
        // println!("{:?}", sdrf_df);
        // filter based on differential or baseline
        if differential_re.is_match(&config.exp_type) {
            info!("Filtering experiment dataset with differential filters");
            exp_df = filtering::filter_differential(&mut exp_df)?;
            exp_df = augment::augment_differential_df(&mut exp_df, &config, &sdrf_df)?;
        } else {
            info!("Filtering with baseline filters");
            exp_df = filtering::filter_baseline(&mut exp_df);
            exp_df = augment::augment_baseline_df(&mut exp_df, &config, &sdrf_df)?;
        }

        data_path.pop();
        sdrf_path.pop();

        info!("dataframe remaining: {}", exp_df.height());
        gene_count += exp_df.height();

        // Add the newly parsed data to the big df ready for export
        if big_df.height() == 0 {
            big_df = exp_df.clone();
        } else {
            big_df.vstack_mut(&exp_df)?;
        }
    }

    info!(
        "Parsed a total of {} lines, from which {} were selected ({}%)",
        gene_count,
        big_df.height(),
        100.0 * (big_df.height() as f64) / (gene_count as f64)
    );
    println!("{:?}", big_df.height());

    info!("All files parsed, preparing to write import csvs");

    let mut output_file = fs::File::create(&args.output)?;
    CsvWriter::new(&mut output_file)
        .has_header(true)
        .finish(&mut big_df)?;

    Ok(())
}
<commit_msg>Change Expression Atlas parser output to jsonlines<commit_after>use anyhow::Result;
use clap::Parser;
use regex::Regex;
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;

use polars::frame::DataFrame;
use polars::prelude::*;

use log::{info, warn};

pub mod augment;
pub mod configuration;
pub mod filtering;
pub mod sdrf;

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
    /// Path where input has been copied. Must contain the config files
    #[clap(short, long, multiple_values(true))]
    input: PathBuf,

    /// An output file
    #[clap(short, long)]
    output: String,

    /// The column to select. If files have no headers, use "column_N"
    #[clap(short, long, multiple_values(true))]
    select: Vec<String>,
}

fn load_df_add_experiment(path: &PathBuf) -> Result<DataFrame, polars::prelude::PolarsError> {
    info!("Loading experiment data from {:?}", path);
    let exp_name = path
        .file_name()
        .unwrap()
        .to_str()
        .unwrap()
        .split('-')
        .collect::<Vec<&str>>()[0..=2]
        .join("-")
        .replace("_A", "");

    let mut exp_df: DataFrame = CsvReader::from_path(&path)?
        .has_header(true)
        .with_delimiter(b'\t')
        .with_null_values(Some(NullValues::AllColumns("NA".to_string())))
        .infer_schema(None)
        .finish()
        .unwrap_or_else(|x| panic!("Failed on {:?} with error {:?}", path, x));

    // hstack the experiment name (derived from the filename) into the DataFrame
    let mut exp_col_arr = Utf8ChunkedBuilder::new("experiment", exp_df.height(), 128);
    for _i in 0..exp_df.height() {
        exp_col_arr.append_value(&exp_name);
    }
    // let iter_exp = std::iter::repeat([&exp_name].into_iter()).take(exp_df.height());
    let exp_col: Series = exp_col_arr.finish().into_series();
    exp_df.hstack_mut(&[exp_col]).unwrap();

    if !&exp_df.get_column_names().contains(&"GeneID") {
        // normalise column names
        info!("Standard column heading not found, normalising column names");
        info!("Column names were {:?}", &exp_df.get_column_names());
        if exp_df.get_column_names().contains(&"Gene ID") {
            exp_df.rename("Gene ID", "GeneID")?;
        } else if exp_df.get_column_names().contains(&"Gene.ID") {
            exp_df.rename("Gene.ID", "GeneID")?;
        }
        info!("Column names are now {:?}", &exp_df.get_column_names());
    }

    Ok(exp_df)
}

fn main() -> Result<()> {
    env_logger::init();
    info!("Starting Expression Atlas parser");
    let args = Args::parse();

    // Parse the config files first
    // set up the regex
    let config_re = Regex::new(r"configuration.xml").unwrap();
    let mut config_lookup: HashMap<String, configuration::Config> = HashMap::new();
    for file in fs::read_dir(&args.input)? {
        let file = file?;
        let path = file.path();
        if config_re.is_match(path.to_str().unwrap()) {
            let exp_name = path
                .file_name()
                .unwrap()
                .to_str()
                .unwrap()
                .split('-')
                .collect::<Vec<&str>>()[0..=2]
                .join("-")
                .replace("configuration", ""); // yeah...
            let config = configuration::parse_config(&path)?;
            config_lookup.insert(exp_name, config);
        }
    }

    // Now have a hashmap with exp_name:config. We can loop over it and
    // - Check config for experiment type
    // - Construct appropriate filenames
    // - Dispatch filenames for loading, appropriate error handling if they don't exist
    // - Construct new df to merge with big one

    let differential_re = Regex::new(r".*diff.*").unwrap();

    let mut big_df = DataFrame::default();
     // String::new();
    //  data_path = PathBuf::from(&args.input);
    // let mut sdrf_path = PathBuf::from(&args.input);

    let mut gene_count: usize = 0;

    for (exp_name, config) in &config_lookup {
        let mut exp_df = DataFrame::default();
        let mut data_path = PathBuf::from(&args.input);
        let mut sdrf_path = PathBuf::from(&args.input);
        if differential_re.is_match(&config.exp_type) {
            for analysis in &config.analytics {
                let array_design = analysis.array_design.as_deref().unwrap_or("");
                if !array_design.is_empty() {
                    let data_filename: String = format!("{}_{}-analytics.tsv", exp_name, array_design);
                    data_path.push(&data_filename);

                    if !data_path.exists() {
                        warn!(
                            "File {} does not exist, skipping this experiment",
                            data_path.to_str().unwrap()
                        );
                        data_path.pop();
                        continue;
                    }

                    // Load the data
                    if exp_df.height() == 0 {
                        exp_df = load_df_add_experiment(&data_path)?;
                        data_path.pop();
                    } else {
                        exp_df = exp_df
                            .lazy()
                            .join(
                                load_df_add_experiment(&data_path)?.lazy(),
                                [col("GeneID")],
                                [col("GeneID")],
                                JoinType::Inner,
                            )
                            .select(&[col("*").exclude([
                                "Gene Name_right",
                                "experiment_right",
                                "Design Element_right",
                            ])])
                            .collect()?;
                        data_path.pop();
                    }
                } else {
                    let data_filename: String  = format!("{}-analytics.tsv", exp_name);
                    data_path.push(&data_filename);

                    if !data_path.exists() {
                        warn!(
                            "File {} does not exist, skipping this experiment",
                            data_path.to_str().unwrap()
                        );
                        data_path.pop();
                        continue;
                    }

                    exp_df = load_df_add_experiment(&data_path)?;
                    data_path.pop();
                }
            }
        } else {
            let data_filename: String = format!("{}-tpms.tsv", exp_name);
            data_path.push(&data_filename);

            if !data_path.exists() {
                warn!(
                    "File {} does not exist, skipping this experiment",
                    data_path.to_str().unwrap()
                );
                data_path.pop();
                continue;
            }

            exp_df = load_df_add_experiment(&data_path)?;
            data_path.pop();
        }

        let sdrf_filename: String = format!("{}.condensed-sdrf.tsv", exp_name);
        sdrf_path.push(&sdrf_filename);

        if !sdrf_path.exists() {
            warn!(
                "File {} does not exist, skipping this experiment",
                sdrf_path.to_str().unwrap()
            );
            sdrf_path.pop();
            data_path.pop();
            continue;
        }

        // Now load the sdrf
        let sdrf_df = sdrf::parse_condensed_sdrf(&sdrf_path)?;
        // println!("{:?}", sdrf_df);
        // filter based on differential or baseline
        if differential_re.is_match(&config.exp_type) {
            info!("Filtering experiment dataset with differential filters");
            exp_df = filtering::filter_differential(&mut exp_df)?;
            exp_df = augment::augment_differential_df(&mut exp_df, &config, &sdrf_df)?;
        } else {
            info!("Filtering with baseline filters");
            exp_df = filtering::filter_baseline(&mut exp_df);
            exp_df = augment::augment_baseline_df(&mut exp_df, &config, &sdrf_df)?;
        }

        data_path.pop();
        sdrf_path.pop();

        info!("dataframe remaining: {}", exp_df.height());
        gene_count += exp_df.height();

        // Add the newly parsed data to the big df ready for export
        if big_df.height() == 0 {
            big_df = exp_df.clone();
        } else {
            big_df.vstack_mut(&exp_df)?;
        }
    }

    info!(
        "Parsed a total of {} lines, from which {} were selected ({}%)",
        gene_count,
        big_df.height(),
        100.0 * (big_df.height() as f64) / (gene_count as f64)
    );
    println!("{:?}", big_df.height());

    info!("All files parsed, preparing to write import csvs");

    let mut output_file = fs::File::create(&args.output)?;
    JsonWriter::new(&mut output_file)
        .with_json_format(::JsonFormat::JsonLines)
        .finish(&mut big_df)?;

    Ok(())
}
<|endoftext|>


<commit_before>//! Types for Vec-based storage with stack-like pushable states.

use std::fmt;
use std::mem;
use std::ptr;
use std::slice;
use std::convert::From;
use std::default::Default;
use std::ops::{Deref, DerefMut, Index, Range, RangeFrom, RangeFull, RangeTo};

/// Vec-like type with support for saving and restoring states via stack-like
/// operations
///
///
#[derive(Clone)]
pub struct SplitVec<T> {
    data: Vec<T>,
    splits: Vec<usize>
}

impl<T> SplitVec<T> {

    /// Create a new, empty SplitVec instance.
    #[inline]
    pub fn new() -> Self {
        SplitVec{data: Vec::new(), splits: Vec::new()}
    }

    /// Create a new, empty SplitVec instance with space for the specified
    /// number of entries.
    #[inline]
    pub fn with_capacity(data_capacity: usize, splits_capacity: usize) -> Self {
        SplitVec{data: Vec::with_capacity(data_capacity), splits: Vec::with_capacity(splits_capacity)}
    }

    /// Determine the offset of the first item in the current state.
    #[inline]
    fn offset(&self) -> usize {
        self.splits.last().cloned().unwrap_or_else(|| 0)
    }

    /// Mark a split above the current working state.
    ///
    /// This creates a new, empty state at the top of the `SplitVec`'s stack;
    /// you can use `pop_state` to return to the previous state or
    /// `pop_and_merge_states` to merge the current state with the
    /// previous one.
    #[inline]
    pub fn push_state(&mut self) {
        self.splits.push(self.data.len());
    }

    /// Mark a split above the current working state, then copy the contents of
    /// that state into the new working area.
    pub fn push_and_copy_state(&mut self) where T: Copy {
        let ofs = self.offset();
        let count = self.len();
        self.push_state();
        self.data.reserve(count);
        unsafe {
            let src = self.data.as_ptr().offset(ofs as isize);
            let dst = self.data.as_mut_ptr().offset((ofs + count) as isize);
            ptr::copy_nonoverlapping(src,
                                     dst,
                                     count);
            self.data.set_len(ofs + 2 * count);
        }
    }

    /// Restore the most-recently-pushed state, discarding all data added to
    /// the working vector since the last call to `push_state`.
    #[inline]
    pub fn pop_state(&mut self) {
        self.data.truncate(self.splits.pop().expect("Call to `pop_state` without prior matching `push_state` call"));
    }

    /// Remove the split between the current and previous states; this has the
    /// effect of merging their contents into the previous state.
    ///
    /// Calling this method will have no effect if no prior state exists.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate cripes;
    /// # use cripes::util::splitvec::SplitVec;
    /// # fn main() {
    /// let mut s = SplitVec::from(vec![1, 2, 3]);
    /// s.push_state();
    ///
    /// s.extend_from_slice(&[4, 5, 6]);
    /// assert_eq!(&*s, &[4, 5, 6]);
    ///
    /// s.pop_and_merge_states();
    /// assert_eq!(&*s, &[1, 2, 3, 4, 5, 6]);
    /// # }
    /// ```
    #[inline]
    pub fn pop_and_merge_states(&mut self) {
        self.splits.pop();
    }

    /// Get the number of items in the working state.
    #[inline]
    pub fn len(&self) -> usize {
        self.data.len() - self.offset()
    }

    /// Truncate the working state to at most a given number of elements.
    #[inline]
    pub fn truncate(&mut self, len: usize) {
        let ofs = self.offset();
        self.data.truncate(ofs + len)
    }

    /// Push an item onto the end of the working state.
    pub fn push(&mut self, value: T) {
        self.data.push(value)
    }

    /// Remove the top-most item from the working state and return it.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate cripes;
    /// # use cripes::util::splitvec::SplitVec;
    /// # fn main() {
    /// let mut s = SplitVec::new();
    /// assert_eq!(None, s.pop());
    ///
    /// s.extend_from_slice(&[1, 2, 3]);
    /// assert_eq!(Some(3), s.pop());
    /// # }
    /// ```
    ///
    /// `pop` works only within the current state, and will return `None` if the
    /// current state is empty even if a prior state is not:
    ///
    /// ```rust
    /// # extern crate cripes;
    /// # use cripes::util::splitvec::SplitVec;
    /// # fn main() {
    /// let mut s = SplitVec::from(vec![1, 2, 3]);
    /// s.push_state();
    ///
    /// assert_eq!(None, s.pop());
    /// # }
    /// ```
    pub fn pop(&mut self) -> Option<T> {
        if self.len() > 0 { self.data.pop() }
        else { None }
    }

    /// Extend the current working state from a slice.
    #[inline]
    pub fn extend_from_slice<'a>(&mut self, slice: &'a [T]) where T: Copy {
        self.data.extend_from_slice(slice)
    }

    /// Get a reference to the current working state as a slice.
    #[inline]
    pub fn as_slice(&self) -> &[T] {
        self
    }

    /// Remove adjacent duplicates in the working state.
    pub fn dedup(&mut self) where T: PartialEq {
        unsafe {
            let ofs = self.offset();
            let ln = self.data.len();
            if ln <= ofs {
                return;
            }

            let p = self.data.as_mut_ptr();
            let mut r: usize = 1 + ofs;
            let mut w: usize = 1 + ofs;

            while r < ln {
                let p_r = p.offset(r as isize);
                let p_wm1 = p.offset((w - 1) as isize);
                if *p_r != *p_wm1 {
                    if r != w {
                        let p_w = p_wm1.offset(1);
                        mem::swap(&mut *p_r, &mut *p_w);
                    }
                    w += 1;
                }
                r += 1;
            }

            self.truncate(w - ofs);
        }
    }

    /// Iterate over all states contained within the SplitVec.
    ///
    /// The final state is guaranteed to be the current working state.
    pub fn iter_states<'a>(&'a self) -> StateIter<'a, T> {
        StateIter{splits_iter: self.splits.iter(), data: &self.data[..], last_split: Some(0)}
    }
}

/// Iterator over the states of a SplitVec as slices.
///
/// Instances of `StateIter` are obtained by calling `iter_states` on
/// a [`SplitVec`](struct.SplitVec.html).
pub struct StateIter<'a,T> where T: 'a {
    splits_iter: slice::Iter<'a,usize>,
    data: &'a [T],
    last_split: Option<usize>
}

impl<'a, T: 'a> Iterator for StateIter<'a, T> {
    type Item = &'a [T];
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(start) = self.last_split {
            if let Some(end) = self.splits_iter.next() {
                self.last_split = Some(*end);
                Some(&self.data[start..*end])
            } else {
                self.last_split = None;
                Some(&self.data[start..])
            }
        } else { None }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.splits_iter.size_hint()
    }
}

use itertools::Itertools;
impl<T> fmt::Debug for SplitVec<T> where T: fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{}]",
               self.iter_states().map(|s| s.iter().map(|ref elt| format!("{:?}", elt)).join(", "))
               .join(" | "))
    }
}

macro_rules! impl_from_array_reference_types {
    ($($N: expr)+) => {
        $(
            impl<'a,T> From<&'a [T; $N]> for SplitVec<T> where T: Copy {
                  fn from(a: &'a [T; $N]) -> Self {
                      let mut sv = SplitVec::new();
                      sv.extend_from_slice(a);
                      sv
                  }
            }
        )+
    }
}

impl_from_array_reference_types!{
    0  1  2  3  4  5  6  7  8  9
   10 11 12 13 14 15 16 17 18 19
   20 21 22 23 24 25 26 27 28 29
   30 31 32
}

impl<T> AsRef<SplitVec<T>> for SplitVec<T> {
    fn as_ref(&self) -> &Self {
        self
    }
}
impl<T> AsMut<SplitVec<T>> for SplitVec<T> {
    fn as_mut(&mut self) -> &mut Self {
        self
    }
}

impl<T> AsRef<[T]> for SplitVec<T> {
    fn as_ref(&self) -> &[T] {
        self
    }
}
impl<T> AsMut<[T]> for SplitVec<T> {
    fn as_mut(&mut self) -> &mut [T] {
        self
    }
}

impl<T> From<Vec<T>> for SplitVec<T> {
    fn from(v: Vec<T>) -> Self {
        SplitVec{data: v, splits: Vec::new()}
    }
}

impl<'a,T> From<&'a [T]> for SplitVec<T> where T: Clone {
    fn from(s: &'a [T]) -> Self {
        SplitVec{data: s.into(), splits: Vec::new()}
    }
}

impl<T> Default for SplitVec<T> {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

impl<T> Extend<T> for SplitVec<T> {
    fn extend<I>(&mut self, iter: I) where I: IntoIterator<Item=T> {
        self.data.extend(iter);
    }
}

impl<T> Deref for SplitVec<T> {
    type Target = [T];
    fn deref(&self) -> &Self::Target {
        let o = self.offset();
        &self.data[o..]
    }
}

impl<T> DerefMut for SplitVec<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        let o = self.offset();
        &mut self.data[o..]
    }
}

impl<T> Index<usize> for SplitVec<T> {
    type Output = T;
    #[inline]
    fn index<'a>(&'a self, idx: usize) -> &'a T {
        let o = self.offset();
        &self.data[idx + o]
    }
}

impl<T> Index<Range<usize>> for SplitVec<T> {
    type Output = [T];
    #[inline]
    fn index<'a>(&'a self, r: Range<usize>) -> &'a [T] {
        let o = self.offset();
        &self.data[(o + r.start)..(o + r.end)]
    }
}
impl<T> Index<RangeFrom<usize>> for SplitVec<T> {
    type Output = [T];
    #[inline]
    fn index<'a>(&'a self, r: RangeFrom<usize>) -> &'a [T] {
        let o = self.offset();
        &self.data[(o + r.start)..]
    }
}
impl<T> Index<RangeTo<usize>> for SplitVec<T> {
    type Output = [T];
    #[inline]
    fn index<'a>(&'a self, r: RangeTo<usize>) -> &'a [T] {
        let o = self.offset();
        &self.data[..(o + r.end)]
    }
}
impl<T> Index<RangeFull> for SplitVec<T> {
    type Output = [T];
    #[inline(always)]
    fn index<'a>(&'a self, _: RangeFull) -> &'a [T] {
        let o = self.offset();
        &self.data[o..]
    }
}
<commit_msg>util/splitvec: Allow access to previous state of a SplitVec<commit_after>//! Types for Vec-based storage with stack-like pushable states.

use std::fmt;
use std::mem;
use std::ptr;
use std::slice;
use std::convert::From;
use std::default::Default;
use std::ops::{Deref, DerefMut, Index, Range, RangeFrom, RangeFull, RangeTo};

/// Vec-like type with support for saving and restoring states via stack-like
/// operations
///
///
#[derive(Clone)]
pub struct SplitVec<T> {
    data: Vec<T>,
    splits: Vec<usize>
}

impl<T> SplitVec<T> {

    /// Create a new, empty SplitVec instance.
    #[inline]
    pub fn new() -> Self {
        SplitVec{data: Vec::new(), splits: Vec::new()}
    }

    /// Create a new, empty SplitVec instance with space for the specified
    /// number of entries.
    #[inline]
    pub fn with_capacity(data_capacity: usize, splits_capacity: usize) -> Self {
        SplitVec{data: Vec::with_capacity(data_capacity), splits: Vec::with_capacity(splits_capacity)}
    }

    /// Determine the offset of the first item in the current state.
    #[inline]
    fn offset(&self) -> usize {
        self.splits.last().cloned().unwrap_or_else(|| 0)
    }

    /// Mark a split above the current working state.
    ///
    /// This creates a new, empty state at the top of the `SplitVec`'s stack;
    /// you can use `pop_state` to return to the previous state or
    /// `pop_and_merge_states` to merge the current state with the
    /// previous one.
    #[inline]
    pub fn push_state(&mut self) {
        self.splits.push(self.data.len());
    }

    /// Mark a split above the current working state, then copy the contents of
    /// that state into the new working area.
    pub fn push_and_copy_state(&mut self) where T: Copy {
        let ofs = self.offset();
        let count = self.len();
        self.push_state();
        self.data.reserve(count);
        unsafe {
            let src = self.data.as_ptr().offset(ofs as isize);
            let dst = self.data.as_mut_ptr().offset((ofs + count) as isize);
            ptr::copy_nonoverlapping(src,
                                     dst,
                                     count);
            self.data.set_len(ofs + 2 * count);
        }
    }

    /// Restore the most-recently-pushed state, discarding all data added to
    /// the working vector since the last call to `push_state`.
    #[inline]
    pub fn pop_state(&mut self) {
        self.data.truncate(self.splits.pop().expect("Call to `pop_state` without prior matching `push_state` call"));
    }

    /// Remove the split between the current and previous states; this has the
    /// effect of merging their contents into the previous state.
    ///
    /// Calling this method will have no effect if no prior state exists.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate cripes;
    /// # use cripes::util::splitvec::SplitVec;
    /// # fn main() {
    /// let mut s = SplitVec::from(vec![1, 2, 3]);
    /// s.push_state();
    ///
    /// s.extend_from_slice(&[4, 5, 6]);
    /// assert_eq!(&*s, &[4, 5, 6]);
    ///
    /// s.pop_and_merge_states();
    /// assert_eq!(&*s, &[1, 2, 3, 4, 5, 6]);
    /// # }
    /// ```
    #[inline]
    pub fn pop_and_merge_states(&mut self) {
        self.splits.pop();
    }

    /// Get the number of items in the working state.
    #[inline]
    pub fn len(&self) -> usize {
        self.data.len() - self.offset()
    }

    /// Truncate the working state to at most a given number of elements.
    #[inline]
    pub fn truncate(&mut self, len: usize) {
        let ofs = self.offset();
        self.data.truncate(ofs + len)
    }

    /// Push an item onto the end of the working state.
    pub fn push(&mut self, value: T) {
        self.data.push(value)
    }

    /// Remove the top-most item from the working state and return it.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate cripes;
    /// # use cripes::util::splitvec::SplitVec;
    /// # fn main() {
    /// let mut s = SplitVec::new();
    /// assert_eq!(None, s.pop());
    ///
    /// s.extend_from_slice(&[1, 2, 3]);
    /// assert_eq!(Some(3), s.pop());
    /// # }
    /// ```
    ///
    /// `pop` works only within the current state, and will return `None` if the
    /// current state is empty even if a prior state is not:
    ///
    /// ```rust
    /// # extern crate cripes;
    /// # use cripes::util::splitvec::SplitVec;
    /// # fn main() {
    /// let mut s = SplitVec::from(vec![1, 2, 3]);
    /// s.push_state();
    ///
    /// assert_eq!(None, s.pop());
    /// # }
    /// ```
    pub fn pop(&mut self) -> Option<T> {
        if self.len() > 0 { self.data.pop() }
        else { None }
    }

    /// Extend the current working state from a slice.
    #[inline]
    pub fn extend_from_slice<'a>(&mut self, slice: &'a [T]) where T: Copy {
        self.data.extend_from_slice(slice)
    }

    /// Get a reference to the current working state as a slice.
    #[inline]
    pub fn as_slice(&self) -> &[T] {
        self
    }

    /// Remove adjacent duplicates in the working state.
    pub fn dedup(&mut self) where T: PartialEq {
        unsafe {
            let ofs = self.offset();
            let ln = self.data.len();
            if ln <= ofs {
                return;
            }

            let p = self.data.as_mut_ptr();
            let mut r: usize = 1 + ofs;
            let mut w: usize = 1 + ofs;

            while r < ln {
                let p_r = p.offset(r as isize);
                let p_wm1 = p.offset((w - 1) as isize);
                if *p_r != *p_wm1 {
                    if r != w {
                        let p_w = p_wm1.offset(1);
                        mem::swap(&mut *p_r, &mut *p_w);
                    }
                    w += 1;
                }
                r += 1;
            }

            self.truncate(w - ofs);
        }
    }

    /// Iterate over all states contained within the SplitVec.
    ///
    /// The final state is guaranteed to be the current working state.
    pub fn iter_states<'a>(&'a self) -> StateIter<'a, T> {
        StateIter{splits_iter: self.splits.iter(), data: &self.data[..], last_split: Some(0)}
    }

    /// Fetch a view of the previous state as a slice.
    pub fn prev_state<'a>(&'a self) -> Option<&'a [T]> {
        let len = self.splits.len();
        if len == 0 {
            None
        } else {
            let (a, b) =
                if len >= 2 { (self.splits[len - 2], self.splits[len - 1]) }
                else if len >= 1 { (0, self.splits[len - 1]) }
                else { unreachable!() };
            Some(&self.data[a..b])
        }
    }
}

/// Iterator over the states of a SplitVec as slices.
///
/// Instances of `StateIter` are obtained by calling `iter_states` on
/// a [`SplitVec`](struct.SplitVec.html).
pub struct StateIter<'a,T> where T: 'a {
    splits_iter: slice::Iter<'a,usize>,
    data: &'a [T],
    last_split: Option<usize>
}

impl<'a, T: 'a> Iterator for StateIter<'a, T> {
    type Item = &'a [T];
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(start) = self.last_split {
            if let Some(end) = self.splits_iter.next() {
                self.last_split = Some(*end);
                Some(&self.data[start..*end])
            } else {
                self.last_split = None;
                Some(&self.data[start..])
            }
        } else { None }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.splits_iter.size_hint()
    }
}

use itertools::Itertools;
impl<T> fmt::Debug for SplitVec<T> where T: fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{}]",
               self.iter_states().map(|s| s.iter().map(|ref elt| format!("{:?}", elt)).join(", "))
               .join(" | "))
    }
}

macro_rules! impl_from_array_reference_types {
    ($($N: expr)+) => {
        $(
            impl<'a,T> From<&'a [T; $N]> for SplitVec<T> where T: Copy {
                  fn from(a: &'a [T; $N]) -> Self {
                      let mut sv = SplitVec::new();
                      sv.extend_from_slice(a);
                      sv
                  }
            }
        )+
    }
}

impl_from_array_reference_types!{
    0  1  2  3  4  5  6  7  8  9
   10 11 12 13 14 15 16 17 18 19
   20 21 22 23 24 25 26 27 28 29
   30 31 32
}

impl<T> AsRef<SplitVec<T>> for SplitVec<T> {
    fn as_ref(&self) -> &Self {
        self
    }
}
impl<T> AsMut<SplitVec<T>> for SplitVec<T> {
    fn as_mut(&mut self) -> &mut Self {
        self
    }
}

impl<T> AsRef<[T]> for SplitVec<T> {
    fn as_ref(&self) -> &[T] {
        self
    }
}
impl<T> AsMut<[T]> for SplitVec<T> {
    fn as_mut(&mut self) -> &mut [T] {
        self
    }
}

impl<T> From<Vec<T>> for SplitVec<T> {
    fn from(v: Vec<T>) -> Self {
        SplitVec{data: v, splits: Vec::new()}
    }
}

impl<'a,T> From<&'a [T]> for SplitVec<T> where T: Clone {
    fn from(s: &'a [T]) -> Self {
        SplitVec{data: s.into(), splits: Vec::new()}
    }
}

impl<T> Default for SplitVec<T> {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

impl<T> Extend<T> for SplitVec<T> {
    fn extend<I>(&mut self, iter: I) where I: IntoIterator<Item=T> {
        self.data.extend(iter);
    }
}

impl<T> Deref for SplitVec<T> {
    type Target = [T];
    fn deref(&self) -> &Self::Target {
        let o = self.offset();
        &self.data[o..]
    }
}

impl<T> DerefMut for SplitVec<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        let o = self.offset();
        &mut self.data[o..]
    }
}

impl<T> Index<usize> for SplitVec<T> {
    type Output = T;
    #[inline]
    fn index<'a>(&'a self, idx: usize) -> &'a T {
        let o = self.offset();
        &self.data[idx + o]
    }
}

impl<T> Index<Range<usize>> for SplitVec<T> {
    type Output = [T];
    #[inline]
    fn index<'a>(&'a self, r: Range<usize>) -> &'a [T] {
        let o = self.offset();
        &self.data[(o + r.start)..(o + r.end)]
    }
}
impl<T> Index<RangeFrom<usize>> for SplitVec<T> {
    type Output = [T];
    #[inline]
    fn index<'a>(&'a self, r: RangeFrom<usize>) -> &'a [T] {
        let o = self.offset();
        &self.data[(o + r.start)..]
    }
}
impl<T> Index<RangeTo<usize>> for SplitVec<T> {
    type Output = [T];
    #[inline]
    fn index<'a>(&'a self, r: RangeTo<usize>) -> &'a [T] {
        let o = self.offset();
        &self.data[..(o + r.end)]
    }
}
impl<T> Index<RangeFull> for SplitVec<T> {
    type Output = [T];
    #[inline(always)]
    fn index<'a>(&'a self, _: RangeFull) -> &'a [T] {
        let o = self.offset();
        &self.data[o..]
    }
}
<|endoftext|>


<commit_before>
extern mod sax;

use extra::treemap::TreeSet;
use self::sax::*;

pub struct Registry {
    groups: ~[Group],
    enums: ~[EnumNs],
    cmds: ~[CmdNs],
}

impl Registry {
    /// Generate a registry from the supplied XML string
    pub fn from_xml(data: &str) -> Registry {
        RegistryBuilder::parse(data)
    }

    /// Returns a set of all the types used in the supplied registry. This is useful
    /// for working out what conversions are needed for the specific registry.
    pub fn get_tys(&self) -> TreeSet<~str> {
        let mut tys = TreeSet::new();
        for cmds in self.cmds.iter() {
            for def in cmds.defs.iter() {
                tys.insert(def.proto.ty.clone());
                for param in def.params.iter() {
                    tys.insert(param.ty.clone());
                }
            }
        }
        tys
    }
}

pub struct Group {
    name: ~str,
    enums: ~[~str],
}

pub struct EnumNs {
    namespace: ~str,
    group: Option<~str>,
    ty: Option<~str>,
    start: Option<~str>,
    end: Option<~str>,
    vendor: Option<~str>,
    comment: Option<~str>,
    defs: ~[Enum],
}

pub struct Enum {
    ident: ~str,
    value: ~str,
    alias: Option<~str>,
}

pub struct CmdNs {
    namespace: ~str,
    defs: ~[Cmd],
}

pub struct Binding {
    ident: ~str,
    ty: ~str,
    group: Option<~str>,
}

pub struct Cmd {
    proto: Binding,
    params: ~[Binding],
    alias: Option<~str>,
    vecequiv: Option<~str>,
    glx: Option<GlxOpcode>,
}

pub struct GlxOpcode {
    ty: ~str,
    opcode: ~str,
    name: Option<~str>,
    comment: Option<~str>,
}

struct RegistryBuilder {
    priv port: SaxPort,
}

impl<'self> RegistryBuilder {
    fn parse(data: &str) -> Registry {
        RegistryBuilder {
            port: parse_xml(data)
        }.consume_registry()
    }

    fn recv(&self) -> ParseEvent {
        loop {
            match self.port.recv() {
                Ok(StartDocument) => (),
                Ok(Comment(_)) => (),
                Ok(Characters(ref ch)) if ch.is_whitespace() => (),
                Ok(EndDocument) => fail!("The end of the document has been reached"),
                Ok(event) => return event,
                Err(err) => fail!("XML error: %s", err.to_str()),
            }
        }
    }

    fn expect_characters(&self) -> ~str {
        match self.recv() {
            Characters(ref ch) => ch.clone(),
            msg => fail!("Expected characters, found: %s", msg.to_str()),
        }
    }

    fn expect_start_element(&self, name: &str) -> Attributes {
        match self.recv() {
            StartElement(ref n, ref atts) if name == *n => atts.clone(),
            msg => fail!("Expected <%s>, found: %s", name, msg.to_str()),
        }
    }

    fn expect_end_element(&self, name: &str) {
        match self.recv() {
            EndElement(ref n) if name == *n => (),
            msg => fail!("Expected </%s>, found: %s", name, msg.to_str()),
        }
    }

    fn skip_until(&self, event: ParseEvent) {
        loop {
            let msg = self.recv();
            if msg == event || msg == EndDocument { break }
        }
    }

    fn consume_registry(&self) -> Registry {
        self.expect_start_element("registry");
        let mut registry = Registry {
            groups: ~[],
            enums: ~[],
            cmds: ~[]
        };
        loop {
            match self.recv() {
                // ignores
                Characters(_) | Comment(_) => (),
                StartElement(~"comment", _) => self.skip_until(EndElement(~"comment")),
                StartElement(~"types", _) => self.skip_until(EndElement(~"types")),
                StartElement(~"feature", _) => self.skip_until(EndElement(~"feature")),
                StartElement(~"extensions", _) => self.skip_until(EndElement(~"extensions")),

                // add groups
                StartElement(~"groups", _) => {
                    loop {
                        match self.recv() {
                            StartElement(~"enums", ref atts) => {
                                registry.groups.push(
                                    self.consume_group(atts.get_clone("name"))
                                );
                            }
                            EndElement(~"groups") => break,
                            msg => fail!("Expected </groups>, found: %s", msg.to_str()),
                        }
                    }
                }

                // add enum namespace
                StartElement(~"enums", ref atts) => {
                    registry.enums.push(
                        EnumNs {
                            namespace:  atts.get_clone("namespace"),
                            group:      atts.find_clone("group"),
                            ty:         atts.find_clone("type"),
                            start:      atts.find_clone("start"),
                            end:        atts.find_clone("end"),
                            vendor:     atts.find_clone("vendor"),
                            comment:    atts.find_clone("comment"),
                            defs:       self.consume_enums(),
                        }
                    )
                }

                // add command namespace
                StartElement(~"commands", ref atts) => {
                    registry.cmds.push(
                        CmdNs {
                            namespace:  atts.get_clone("namespace"),
                            defs:       self.consume_cmds(),
                        }
                    );
                }

                // finished building the registry
                EndElement(~"registry") => break,

                // error handling
                msg => fail!("Expected </registry>, found: %s", msg.to_str()),
            }
        }
        registry
    }

    fn consume_group(&self, name: ~str) -> Group {
        let mut enms = ~[];
        loop {
            match self.recv() {
                StartElement(~"enum", ref atts) => {
                    enms.push(atts.get_clone("name"));
                    self.expect_end_element("enum");
                }
                EndElement(~"group") => break,
                msg => fail!("Expected </group>, found: %s", msg.to_str()),
            }
        }
        Group {
            name: name,
            enums: enms,
        }
    }

    fn consume_enums(&self) -> ~[Enum] {
        let mut enums = ~[];
        loop {
            match self.recv() {
                // ignores
                Characters(_) | Comment(_) => (),
                StartElement(~"unused", _) => self.skip_until(EndElement(~"unused")),

                // add enum definition
                StartElement(~"enum", ref atts) => {
                    enums.push(
                        Enum {
                            ident:  atts.get_clone("name"),
                            value:  atts.get_clone("value"),
                            alias:  atts.find_clone("alias"),
                        }
                    );
                    self.expect_end_element("enum");
                }

                // finished building the namespace
                EndElement(~"enums") => break,
                // error handling
                msg => fail!("Expected </enums>, found: %s", msg.to_str()),
            }
        }
        enums
    }

    fn consume_cmds(&self) -> ~[Cmd] {
        let mut cmds = ~[];
        loop {
            match self.recv() {
                // add command definition
                StartElement(~"command", _) => {
                    cmds.push(self.consume_cmd());
                }
                // finished building the namespace
                EndElement(~"commands") => break,
                // error handling
                msg => fail!("Expected </commands>, found: %s", msg.to_str()),
            }
        }
        cmds
    }

    fn consume_cmd(&self) -> Cmd {
        // consume command prototype
        let proto_atts = self.expect_start_element("proto");
        let proto = self.consume_binding(proto_atts.find_clone("group"));
        self.expect_end_element("proto");

        let mut params = ~[];
        let mut alias = None;
        let mut vecequiv = None;
        let mut glx = None;
        loop {
            match self.recv() {
                StartElement(~"param", ref atts) => {
                    params.push(
                        self.consume_binding(atts.find_clone("group"))
                    );
                    self.expect_end_element("param");
                }
                StartElement(~"alias", ref atts) => {
                    alias = atts.find_clone("alias");
                    self.expect_end_element("alias");
                }
                StartElement(~"vecequiv", ref atts) => {
                    vecequiv = atts.find_clone("vecequiv");
                    self.expect_end_element("vecequiv");
                }
                StartElement(~"glx", ref atts) => {
                    glx = Some(GlxOpcode {
                        ty:      atts.get_clone("type"),
                        opcode:  atts.get_clone("opcode"),
                        name:    atts.find_clone("name"),
                        comment: atts.find_clone("comment"),
                    });
                    self.expect_end_element("glx");
                }
                EndElement(~"command") => break,
                msg => fail!("Expected </command>, found: %s", msg.to_str()),
            }
        }

        Cmd {
            proto: proto,
            params: params,
            alias: alias,
            vecequiv: vecequiv,
            glx: glx,
        }
    }

    fn consume_binding(&self, group: Option<~str>) -> Binding {
        // consume type
        let mut ty = ~"";
        loop {
            match self.recv() {
                Characters(ch) => ty.push_str(ch),
                StartElement(~"ptype", _) => (),
                EndElement(~"ptype") => (),
                StartElement(~"name", _) => break,
                msg => fail!("Expected binding, found: %s", msg.to_str()),
            }
        }
        // consume identifier
        let ident = self.expect_characters();
        self.expect_end_element("name");
        Binding {
            ident: ident,
            ty: ty,
            group: group,
        }
    }
}
<commit_msg>Fix group accumulation<commit_after>
extern mod sax;

use extra::treemap::TreeSet;
use self::sax::*;

pub struct Registry {
    groups: ~[Group],
    enums: ~[EnumNs],
    cmds: ~[CmdNs],
}

impl Registry {
    /// Generate a registry from the supplied XML string
    pub fn from_xml(data: &str) -> Registry {
        RegistryBuilder::parse(data)
    }

    /// Returns a set of all the types used in the supplied registry. This is useful
    /// for working out what conversions are needed for the specific registry.
    pub fn get_tys(&self) -> TreeSet<~str> {
        let mut tys = TreeSet::new();
        for cmds in self.cmds.iter() {
            for def in cmds.defs.iter() {
                tys.insert(def.proto.ty.clone());
                for param in def.params.iter() {
                    tys.insert(param.ty.clone());
                }
            }
        }
        tys
    }
}

pub struct Group {
    name: ~str,
    enums: ~[~str],
}

pub struct EnumNs {
    namespace: ~str,
    group: Option<~str>,
    ty: Option<~str>,
    start: Option<~str>,
    end: Option<~str>,
    vendor: Option<~str>,
    comment: Option<~str>,
    defs: ~[Enum],
}

pub struct Enum {
    ident: ~str,
    value: ~str,
    alias: Option<~str>,
}

pub struct CmdNs {
    namespace: ~str,
    defs: ~[Cmd],
}

pub struct Binding {
    ident: ~str,
    ty: ~str,
    group: Option<~str>,
}

pub struct Cmd {
    proto: Binding,
    params: ~[Binding],
    alias: Option<~str>,
    vecequiv: Option<~str>,
    glx: Option<GlxOpcode>,
}

pub struct GlxOpcode {
    ty: ~str,
    opcode: ~str,
    name: Option<~str>,
    comment: Option<~str>,
}

struct RegistryBuilder {
    priv port: SaxPort,
}

/// A big, ugly, imperative impl with methods that accumulates a Registry struct
impl<'self> RegistryBuilder {
    fn parse(data: &str) -> Registry {
        RegistryBuilder {
            port: parse_xml(data)
        }.consume_registry()
    }

    fn recv(&self) -> ParseEvent {
        loop {
            match self.port.recv() {
                Ok(StartDocument) => (),
                Ok(Comment(_)) => (),
                Ok(Characters(ref ch)) if ch.is_whitespace() => (),
                Ok(EndDocument) => fail!("The end of the document has been reached"),
                Ok(event) => return event,
                Err(err) => fail!("XML error: %s", err.to_str()),
            }
        }
    }

    fn expect_characters(&self) -> ~str {
        match self.recv() {
            Characters(ref ch) => ch.clone(),
            msg => fail!("Expected characters, found: %s", msg.to_str()),
        }
    }

    fn expect_start_element(&self, name: &str) -> Attributes {
        match self.recv() {
            StartElement(ref n, ref atts) if name == *n => atts.clone(),
            msg => fail!("Expected <%s>, found: %s", name, msg.to_str()),
        }
    }

    fn expect_end_element(&self, name: &str) {
        match self.recv() {
            EndElement(ref n) if name == *n => (),
            msg => fail!("Expected </%s>, found: %s", name, msg.to_str()),
        }
    }

    fn skip_until(&self, event: ParseEvent) {
        loop {
            let msg = self.recv();
            if msg == event || msg == EndDocument { break }
        }
    }

    fn consume_registry(&self) -> Registry {
        self.expect_start_element("registry");
        let mut registry = Registry {
            groups: ~[],
            enums: ~[],
            cmds: ~[]
        };
        loop {
            match self.recv() {
                // ignores
                Characters(_) | Comment(_) => (),
                StartElement(~"comment", _) => self.skip_until(EndElement(~"comment")),
                StartElement(~"types", _) => self.skip_until(EndElement(~"types")),
                StartElement(~"feature", _) => self.skip_until(EndElement(~"feature")),
                StartElement(~"extensions", _) => self.skip_until(EndElement(~"extensions")),

                // add groups
                StartElement(~"groups", _) => {
                    loop {
                        match self.recv() {
                            StartElement(~"group", ref atts) => {
                                registry.groups.push(
                                    self.consume_group(atts.get_clone("name"))
                                );
                            }
                            EndElement(~"groups") => break,
                            msg => fail!("Expected </groups>, found: %s", msg.to_str()),
                        }
                    }
                }

                // add enum namespace
                StartElement(~"enums", ref atts) => {
                    registry.enums.push(
                        EnumNs {
                            namespace:  atts.get_clone("namespace"),
                            group:      atts.find_clone("group"),
                            ty:         atts.find_clone("type"),
                            start:      atts.find_clone("start"),
                            end:        atts.find_clone("end"),
                            vendor:     atts.find_clone("vendor"),
                            comment:    atts.find_clone("comment"),
                            defs:       self.consume_enums(),
                        }
                    )
                }

                // add command namespace
                StartElement(~"commands", ref atts) => {
                    registry.cmds.push(
                        CmdNs {
                            namespace:  atts.get_clone("namespace"),
                            defs:       self.consume_cmds(),
                        }
                    );
                }

                // finished building the registry
                EndElement(~"registry") => break,

                // error handling
                msg => fail!("Expected </registry>, found: %s", msg.to_str()),
            }
        }
        registry
    }

    fn consume_group(&self, name: ~str) -> Group {
        let mut enms = ~[];
        loop {
            match self.recv() {
                StartElement(~"enum", ref atts) => {
                    enms.push(atts.get_clone("name"));
                    self.expect_end_element("enum");
                }
                EndElement(~"group") => break,
                msg => fail!("Expected </group>, found: %s", msg.to_str()),
            }
        }
        Group {
            name: name,
            enums: enms,
        }
    }

    fn consume_enums(&self) -> ~[Enum] {
        let mut enums = ~[];
        loop {
            match self.recv() {
                // ignores
                Characters(_) | Comment(_) => (),
                StartElement(~"unused", _) => self.skip_until(EndElement(~"unused")),

                // add enum definition
                StartElement(~"enum", ref atts) => {
                    enums.push(
                        Enum {
                            ident:  atts.get_clone("name"),
                            value:  atts.get_clone("value"),
                            alias:  atts.find_clone("alias"),
                        }
                    );
                    self.expect_end_element("enum");
                }

                // finished building the namespace
                EndElement(~"enums") => break,
                // error handling
                msg => fail!("Expected </enums>, found: %s", msg.to_str()),
            }
        }
        enums
    }

    fn consume_cmds(&self) -> ~[Cmd] {
        let mut cmds = ~[];
        loop {
            match self.recv() {
                // add command definition
                StartElement(~"command", _) => {
                    cmds.push(self.consume_cmd());
                }
                // finished building the namespace
                EndElement(~"commands") => break,
                // error handling
                msg => fail!("Expected </commands>, found: %s", msg.to_str()),
            }
        }
        cmds
    }

    fn consume_cmd(&self) -> Cmd {
        // consume command prototype
        let proto_atts = self.expect_start_element("proto");
        let proto = self.consume_binding(proto_atts.find_clone("group"));
        self.expect_end_element("proto");

        let mut params = ~[];
        let mut alias = None;
        let mut vecequiv = None;
        let mut glx = None;
        loop {
            match self.recv() {
                StartElement(~"param", ref atts) => {
                    params.push(
                        self.consume_binding(atts.find_clone("group"))
                    );
                    self.expect_end_element("param");
                }
                StartElement(~"alias", ref atts) => {
                    alias = atts.find_clone("alias");
                    self.expect_end_element("alias");
                }
                StartElement(~"vecequiv", ref atts) => {
                    vecequiv = atts.find_clone("vecequiv");
                    self.expect_end_element("vecequiv");
                }
                StartElement(~"glx", ref atts) => {
                    glx = Some(GlxOpcode {
                        ty:      atts.get_clone("type"),
                        opcode:  atts.get_clone("opcode"),
                        name:    atts.find_clone("name"),
                        comment: atts.find_clone("comment"),
                    });
                    self.expect_end_element("glx");
                }
                EndElement(~"command") => break,
                msg => fail!("Expected </command>, found: %s", msg.to_str()),
            }
        }

        Cmd {
            proto: proto,
            params: params,
            alias: alias,
            vecequiv: vecequiv,
            glx: glx,
        }
    }

    fn consume_binding(&self, group: Option<~str>) -> Binding {
        // consume type
        let mut ty = ~"";
        loop {
            match self.recv() {
                Characters(ch) => ty.push_str(ch),
                StartElement(~"ptype", _) => (),
                EndElement(~"ptype") => (),
                StartElement(~"name", _) => break,
                msg => fail!("Expected binding, found: %s", msg.to_str()),
            }
        }
        // consume identifier
        let ident = self.expect_characters();
        self.expect_end_element("name");
        Binding {
            ident: ident,
            ty: ty,
            group: group,
        }
    }
}
<|endoftext|>