<commit_before>use super::definitions::{
    DataVector,
    VecResult,
    ErrorReason,
    DataVectorDomain};
use conv_types::*;
use RealNumber;
use num::traits::Zero;
use std::ops::Mul;
use std::fmt::Display;
use super::{
    GenericDataVector,
    RealTimeVector,
    ComplexFreqVector,
    ComplexTimeVector};
use super::time_freq_impl::{
    TimeDomainOperations,
    FrequencyDomainOperations
};
use multicore_support::{Chunk, Complexity};

/// Provides a convolution operation for data vectors.
///
/// In contrast to the convolution definition this library allows for convinience to define a convolution in frequency domain which will then correctly be executed as multiplication.
pub trait Convolution<T, C> : DataVector<T>
    where T : RealNumber {
    /// Convolves `self` with the convolution function `function`.
    /// The domain in which `function` resides defines in which domain the operation
    /// is performed. For performance reasons it is advised to pass `function` in
    /// frequency domain since this will significantly speed up the calculation in most cases.
    /// # Assumptions
    /// In frequency domain the operation assumes that the vector contains a full spectrum centered at 0 Hz. If half a spectrum
    /// or a fft shifted spectrum is provided the operation will come back with invalid results.
    /// # Failures
    /// VecResult may report the following `ErrorReason` members:
    ///
    /// 1. `VectorMustBeComplex`: if `self` is in real number space but `function` is in complex number space.
    /// 2. `VectorMustBeInTimeDomain`: if `self` is in frequency domain, `function` is in time domain and the vector can't be automatically converted to frequency domain since it is in real number space.
    fn convolve(self, function: C) -> VecResult<Self>;
}

macro_rules! add_conv_impl{
    ($($data_type:ident),*) => {
        $(
            impl<'a> Convolution<$data_type, &'a RealTimeConvFunction<$data_type>> for GenericDataVector<$data_type> {
                fn convolve(self, function: &RealTimeConvFunction<$data_type>) -> VecResult<Self> {
                    Ok(self.convolve_priv(
                            |data|data,
                            |temp|temp,
                            |x|function.calc(x)
                        ))
                }
            }

            impl<'a> Convolution<$data_type, &'a ComplexTimeConvFunction<$data_type>> for GenericDataVector<$data_type> {
                fn convolve(self, function: &ComplexTimeConvFunction<$data_type>) -> VecResult<Self> {
                    assert_complex!(self);
                    let was_time = self.domain == DataVectorDomain::Time;
                    let time =
                        if was_time {
                            self
                        } else {
                            try! { self.ifft() }
                        };

                    let result = time.convolve_priv(
                            |data|Self::array_to_complex(data),
                            |temp|Self::array_to_complex_mut(temp),
                            |x|function.calc(x)
                        );

                    if was_time {
                        Ok(result)
                    } else {
                        result.fft()
                    }
                }
            }

            impl GenericDataVector<$data_type> {
                fn convolve_priv<T,C,CMut,F>(
                    mut self,
                    convert: C,
                    convert_mut: CMut,
                    fun: F) -> Self
                        where
                            C: Fn(&[$data_type]) -> &[T],
                            CMut: Fn(&mut [$data_type]) -> &mut [T],
                            F: Fn($data_type)->T,
                            T: Zero + Mul<Output=T> + Copy + Display
                {
                    {
                        let len = self.len();
                        let delta = self.delta();
                        let complex = convert(&self.data[0..len]);
                        let dest = convert_mut(&mut self.temp[0..len]);
                        let conv_len = 11; // TODO make configurable
                        let mut i = 0;
                        for num in dest {
                            let start = if i > conv_len { i - conv_len } else { 0 };
                            let end = if i + conv_len < len { i + conv_len } else { len };
                            let mut sum = T::zero();
                            let center = i as $data_type;
                            let mut j = start as $data_type - center;
                            for c in &complex[start..end] {
                                let temp =  (*c) * fun(j * delta);
                                print!("i={}, j={} => {}\n", i, j, temp);
                                sum = sum + (*c) * fun(j * delta);
                                j += 1.0;
                            }
                            (*num) = sum;
                            i += 1;
                        }
                    }
                    self.swap_data_temp()
                }
            }

            impl<'a> Convolution<$data_type, &'a ComplexFrequencyConvFunction<$data_type>> for GenericDataVector<$data_type> {
                fn convolve(self, function: &ComplexFrequencyConvFunction<$data_type>) -> VecResult<Self> {
                    assert_complex!(self);
                    let was_time = self.domain == DataVectorDomain::Time;
                    let mut freq =
                        if was_time {
                            try!{ self.fft() }
                        } else {
                            self
                        };
                    {
                        let len = freq.len();
                        let points = freq.points();
                        let complex = Self::array_to_complex_mut(&mut freq.data[0..len]);
                        Chunk::execute_with_range(
                            Complexity::Medium, &freq.multicore_settings,
                            complex, points, 1, function,
                            move |array, range, function| {
                                let max = points as $data_type / 2.0;
                                let mut j = -((points + range.start) as $data_type) / 2.0;
                                for num in array {
                                    (*num) = (*num) * function.calc(j / max);
                                    j += 1.0;
                                }
                            });
                    }

                    if was_time {
                        freq.ifft()
                    } else {
                        Ok(freq)
                    }
                }
            }

            impl<'a> Convolution<$data_type, &'a RealFrequencyConvFunction<$data_type>> for GenericDataVector<$data_type> {
                fn convolve(self, function: &RealFrequencyConvFunction<$data_type>) -> VecResult<Self> {
                    assert_complex!(self);
                    let was_time = self.domain == DataVectorDomain::Time;
                    let mut freq =
                        if was_time {
                            try!{ self.fft() }
                        } else {
                            self
                        };
                    {
                        let len = freq.len();
                        let points = freq.points();
                        let complex = Self::array_to_complex_mut(&mut freq.data[0..len]);
                        Chunk::execute_with_range(
                            Complexity::Medium, &freq.multicore_settings,
                            complex, points, 1, function,
                            move |array, range, function| {
                                let max = points as $data_type / 2.0;
                                let mut j = -((points + range.start) as $data_type) / 2.0;
                                for num in array {
                                    (*num) = (*num) * function.calc(j / max);
                                    j += 1.0;
                                }
                            });
                    }

                    if was_time {
                        freq.ifft()
                    } else {
                        Ok(freq)
                    }
                }
            }
        )*
    }
}
add_conv_impl!(f32, f64);

macro_rules! add_conv_forw{
    ($($data_type:ident),*) => {
        $(
            impl<'a> Convolution<$data_type, &'a RealTimeConvFunction<$data_type>> for RealTimeVector<$data_type> {
                fn convolve(self, function: &RealTimeConvFunction<$data_type>) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().convolve(function))
                }
            }

            impl<'a> Convolution<$data_type, &'a RealTimeConvFunction<$data_type>> for ComplexTimeVector<$data_type> {
                fn convolve(self, function: &RealTimeConvFunction<$data_type>) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().convolve(function))
                }
            }

            impl<'a> Convolution<$data_type, &'a RealTimeConvFunction<$data_type>> for ComplexFreqVector<$data_type> {
                fn convolve(self, function: &RealTimeConvFunction<$data_type>) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().convolve(function))
                }
            }

            impl<'a> Convolution<$data_type, &'a ComplexTimeConvFunction<$data_type>> for ComplexTimeVector<$data_type> {
                fn convolve(self, function: &ComplexTimeConvFunction<$data_type>) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().convolve(function))
                }
            }

            impl<'a> Convolution<$data_type, &'a ComplexFrequencyConvFunction<$data_type>> for ComplexTimeVector<$data_type> {
                fn convolve(self, function: &ComplexFrequencyConvFunction<$data_type>) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().convolve(function))
                }
            }

            impl<'a> Convolution<$data_type, &'a ComplexTimeConvFunction<$data_type>> for ComplexFreqVector<$data_type> {
                fn convolve(self, function: &ComplexTimeConvFunction<$data_type>) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().convolve(function))
                }
            }

            impl<'a> Convolution<$data_type, &'a ComplexFrequencyConvFunction<$data_type>> for ComplexFreqVector<$data_type> {
                fn convolve(self, function: &ComplexFrequencyConvFunction<$data_type>) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().convolve(function))
                }
            }

            impl<'a> Convolution<$data_type, &'a RealFrequencyConvFunction<$data_type>> for ComplexTimeVector<$data_type> {
                fn convolve(self, function: &RealFrequencyConvFunction<$data_type>) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().convolve(function))
                }
            }

            impl<'a> Convolution<$data_type, &'a RealFrequencyConvFunction<$data_type>> for ComplexFreqVector<$data_type> {
                fn convolve(self, function: &RealFrequencyConvFunction<$data_type>) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().convolve(function))
                }
            }
        )*
    }
}
add_conv_forw!(f32, f64);

#[cfg(test)]
mod tests {
	use super::*;
    use super::super::{
        ComplexTimeVector32,
        ComplexFreqVector32,
        RealTimeVector32,
        DataVector};
    use conv_types::*;
    use RealNumber;
    use std::fmt::Debug;
    use num::complex::Complex32;

    fn assert_eq_tol<T>(left: &[T], right: &[T], tol: T)
        where T: RealNumber + Debug {
        assert_eq!(left.len(), right.len());
        for i in 0..left.len() {
            if (left[i] - right[i]).abs() > tol {
                panic!("assertion failed: {:?} != {:?}", left, right);
            }
        }
    }
    /*
	#[test]
	fn convolve_real_and_time32() {
        let result = {
            let vector = RealTimeVector32::from_constant(1.0, 10);
            let conv = RaiseCosineFuncton::new(0.35);
            vector.convolve(&conv).unwrap()
        };

        assert_eq!(result.data(), &[0.0; 10])
    }

    #[test]
	fn convolve_complex_time_and_time32() {
        let vector = ComplexTimeVector32::from_constant(Complex32::new(1.0, 0.0), 10);
        let rc = RaiseCosineFuncton::new(0.35);
        let real = RealTimeLinearTableLookup::<f32>::from_conv_function(&rc, 0.4, 10);
        let complex = real.to_complex();
        let result = vector.convolve(&complex as &ComplexTimeConvFunction<f32>).unwrap();
        assert_eq!(result.data(), &[0.0; 10])
    }

    #[test]
	fn convolve_complex_time_and_freq32() {
        let vector = ComplexTimeVector32::from_constant(Complex32::new(1.0, 0.0), 10);
        let rc = RaiseCosineFuncton::new(0.35);
        let real = RealTimeLinearTableLookup::<f32>::from_conv_function(&rc, 0.4, 10);
        let freq = real.to_complex().fft();
        let result = vector.convolve(&freq as &ComplexFrequencyConvFunction<f32>).unwrap();
        assert_eq!(result.data(), &[0.0; 10])
    }

    #[test]
	fn convolve_complex_freq_and_time32() {
        let vector = ComplexFreqVector32::from_constant(Complex32::new(1.0, 0.0), 10);
        let rc = RaiseCosineFuncton::new(0.35);
        let real = RealTimeLinearTableLookup::<f32>::from_conv_function(&rc, 0.4, 10);
        let complex = real.to_complex();
        let result = vector.convolve(&complex as &ComplexTimeConvFunction<f32>).unwrap();
        assert_eq!(result.data(), &[0.0; 10])
    }*/

    #[test]
	fn convolve_real_freq_and_freq32() {
        let vector = ComplexFreqVector32::from_constant(Complex32::new(1.0, 1.0), 10);
        let rc: RaisedCosineFuncton<f32> = RaisedCosineFuncton::new(1.0);
        let result = vector.convolve(&rc as &RealFrequencyConvFunction<f32>).unwrap();
        let expected =
            [0.0, 0.0, 0.3454914, 0.3454914, 0.9045085, 0.9045085, 0.9045085, 0.9045085, 0.3454914, 0.3454914];
        assert_eq_tol(result.data(), &expected, 1e-4);
    }

    #[test]
	fn convolve_real_time_and_time32() {
        let vector = RealTimeVector32::from_array_with_delta(&[0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0], 0.2);
        let rc: RaisedCosineFuncton<f32> = RaisedCosineFuncton::new(0.35);
        let result = vector.convolve(&rc as &RealTimeConvFunction<f32>).unwrap();
        let expected =
            [0.0, 0.2171850639713355, 0.4840621929215732, 0.7430526238101408, 0.9312114164253432,
             1.0, 0.9312114164253432, 0.7430526238101408, 0.4840621929215732, 0.2171850639713355];
        assert_eq_tol(result.data(), &expected, 1e-4);
    }
}<commit_msg>Fixed build warning.<commit_after>use super::definitions::{
    DataVector,
    VecResult,
    ErrorReason,
    DataVectorDomain};
use conv_types::*;
use RealNumber;
use num::traits::Zero;
use std::ops::Mul;
use std::fmt::Display;
use super::{
    GenericDataVector,
    RealTimeVector,
    ComplexFreqVector,
    ComplexTimeVector};
use super::time_freq_impl::{
    TimeDomainOperations,
    FrequencyDomainOperations
};
use multicore_support::{Chunk, Complexity};

/// Provides a convolution operation for data vectors.
///
/// In contrast to the convolution definition this library allows for convinience to define a convolution in frequency domain which will then correctly be executed as multiplication.
pub trait Convolution<T, C> : DataVector<T>
    where T : RealNumber {
    /// Convolves `self` with the convolution function `function`.
    /// The domain in which `function` resides defines in which domain the operation
    /// is performed. For performance reasons it is advised to pass `function` in
    /// frequency domain since this will significantly speed up the calculation in most cases.
    /// # Assumptions
    /// In frequency domain the operation assumes that the vector contains a full spectrum centered at 0 Hz. If half a spectrum
    /// or a fft shifted spectrum is provided the operation will come back with invalid results.
    /// # Failures
    /// VecResult may report the following `ErrorReason` members:
    ///
    /// 1. `VectorMustBeComplex`: if `self` is in real number space but `function` is in complex number space.
    /// 2. `VectorMustBeInTimeDomain`: if `self` is in frequency domain, `function` is in time domain and the vector can't be automatically converted to frequency domain since it is in real number space.
    fn convolve(self, function: C) -> VecResult<Self>;
}

macro_rules! add_conv_impl{
    ($($data_type:ident),*) => {
        $(
            impl<'a> Convolution<$data_type, &'a RealTimeConvFunction<$data_type>> for GenericDataVector<$data_type> {
                fn convolve(self, function: &RealTimeConvFunction<$data_type>) -> VecResult<Self> {
                    Ok(self.convolve_priv(
                            |data|data,
                            |temp|temp,
                            |x|function.calc(x)
                        ))
                }
            }

            impl<'a> Convolution<$data_type, &'a ComplexTimeConvFunction<$data_type>> for GenericDataVector<$data_type> {
                fn convolve(self, function: &ComplexTimeConvFunction<$data_type>) -> VecResult<Self> {
                    assert_complex!(self);
                    let was_time = self.domain == DataVectorDomain::Time;
                    let time =
                        if was_time {
                            self
                        } else {
                            try! { self.ifft() }
                        };

                    let result = time.convolve_priv(
                            |data|Self::array_to_complex(data),
                            |temp|Self::array_to_complex_mut(temp),
                            |x|function.calc(x)
                        );

                    if was_time {
                        Ok(result)
                    } else {
                        result.fft()
                    }
                }
            }

            impl GenericDataVector<$data_type> {
                fn convolve_priv<T,C,CMut,F>(
                    mut self,
                    convert: C,
                    convert_mut: CMut,
                    fun: F) -> Self
                        where
                            C: Fn(&[$data_type]) -> &[T],
                            CMut: Fn(&mut [$data_type]) -> &mut [T],
                            F: Fn($data_type)->T,
                            T: Zero + Mul<Output=T> + Copy + Display
                {
                    {
                        let len = self.len();
                        let delta = self.delta();
                        let complex = convert(&self.data[0..len]);
                        let dest = convert_mut(&mut self.temp[0..len]);
                        let conv_len = 11; // TODO make configurable
                        let mut i = 0;
                        for num in dest {
                            let start = if i > conv_len { i - conv_len } else { 0 };
                            let end = if i + conv_len < len { i + conv_len } else { len };
                            let mut sum = T::zero();
                            let center = i as $data_type;
                            let mut j = start as $data_type - center;
                            for c in &complex[start..end] {
                                let temp =  (*c) * fun(j * delta);
                                print!("i={}, j={} => {}\n", i, j, temp);
                                sum = sum + (*c) * fun(j * delta);
                                j += 1.0;
                            }
                            (*num) = sum;
                            i += 1;
                        }
                    }
                    self.swap_data_temp()
                }
            }

            impl<'a> Convolution<$data_type, &'a ComplexFrequencyConvFunction<$data_type>> for GenericDataVector<$data_type> {
                fn convolve(self, function: &ComplexFrequencyConvFunction<$data_type>) -> VecResult<Self> {
                    assert_complex!(self);
                    let was_time = self.domain == DataVectorDomain::Time;
                    let mut freq =
                        if was_time {
                            try!{ self.fft() }
                        } else {
                            self
                        };
                    {
                        let len = freq.len();
                        let points = freq.points();
                        let complex = Self::array_to_complex_mut(&mut freq.data[0..len]);
                        Chunk::execute_with_range(
                            Complexity::Medium, &freq.multicore_settings,
                            complex, points, 1, function,
                            move |array, range, function| {
                                let max = points as $data_type / 2.0;
                                let mut j = -((points + range.start) as $data_type) / 2.0;
                                for num in array {
                                    (*num) = (*num) * function.calc(j / max);
                                    j += 1.0;
                                }
                            });
                    }

                    if was_time {
                        freq.ifft()
                    } else {
                        Ok(freq)
                    }
                }
            }

            impl<'a> Convolution<$data_type, &'a RealFrequencyConvFunction<$data_type>> for GenericDataVector<$data_type> {
                fn convolve(self, function: &RealFrequencyConvFunction<$data_type>) -> VecResult<Self> {
                    assert_complex!(self);
                    let was_time = self.domain == DataVectorDomain::Time;
                    let mut freq =
                        if was_time {
                            try!{ self.fft() }
                        } else {
                            self
                        };
                    {
                        let len = freq.len();
                        let points = freq.points();
                        let complex = Self::array_to_complex_mut(&mut freq.data[0..len]);
                        Chunk::execute_with_range(
                            Complexity::Medium, &freq.multicore_settings,
                            complex, points, 1, function,
                            move |array, range, function| {
                                let max = points as $data_type / 2.0;
                                let mut j = -((points + range.start) as $data_type) / 2.0;
                                for num in array {
                                    (*num) = (*num) * function.calc(j / max);
                                    j += 1.0;
                                }
                            });
                    }

                    if was_time {
                        freq.ifft()
                    } else {
                        Ok(freq)
                    }
                }
            }
        )*
    }
}
add_conv_impl!(f32, f64);

macro_rules! add_conv_forw{
    ($($data_type:ident),*) => {
        $(
            impl<'a> Convolution<$data_type, &'a RealTimeConvFunction<$data_type>> for RealTimeVector<$data_type> {
                fn convolve(self, function: &RealTimeConvFunction<$data_type>) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().convolve(function))
                }
            }

            impl<'a> Convolution<$data_type, &'a RealTimeConvFunction<$data_type>> for ComplexTimeVector<$data_type> {
                fn convolve(self, function: &RealTimeConvFunction<$data_type>) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().convolve(function))
                }
            }

            impl<'a> Convolution<$data_type, &'a RealTimeConvFunction<$data_type>> for ComplexFreqVector<$data_type> {
                fn convolve(self, function: &RealTimeConvFunction<$data_type>) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().convolve(function))
                }
            }

            impl<'a> Convolution<$data_type, &'a ComplexTimeConvFunction<$data_type>> for ComplexTimeVector<$data_type> {
                fn convolve(self, function: &ComplexTimeConvFunction<$data_type>) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().convolve(function))
                }
            }

            impl<'a> Convolution<$data_type, &'a ComplexFrequencyConvFunction<$data_type>> for ComplexTimeVector<$data_type> {
                fn convolve(self, function: &ComplexFrequencyConvFunction<$data_type>) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().convolve(function))
                }
            }

            impl<'a> Convolution<$data_type, &'a ComplexTimeConvFunction<$data_type>> for ComplexFreqVector<$data_type> {
                fn convolve(self, function: &ComplexTimeConvFunction<$data_type>) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().convolve(function))
                }
            }

            impl<'a> Convolution<$data_type, &'a ComplexFrequencyConvFunction<$data_type>> for ComplexFreqVector<$data_type> {
                fn convolve(self, function: &ComplexFrequencyConvFunction<$data_type>) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().convolve(function))
                }
            }

            impl<'a> Convolution<$data_type, &'a RealFrequencyConvFunction<$data_type>> for ComplexTimeVector<$data_type> {
                fn convolve(self, function: &RealFrequencyConvFunction<$data_type>) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().convolve(function))
                }
            }

            impl<'a> Convolution<$data_type, &'a RealFrequencyConvFunction<$data_type>> for ComplexFreqVector<$data_type> {
                fn convolve(self, function: &RealFrequencyConvFunction<$data_type>) -> VecResult<Self> {
                    Self::from_genres(self.to_gen().convolve(function))
                }
            }
        )*
    }
}
add_conv_forw!(f32, f64);

#[cfg(test)]
mod tests {
	use super::*;
    use super::super::{
        ComplexFreqVector32,
        RealTimeVector32,
        DataVector};
    use conv_types::*;
    use RealNumber;
    use std::fmt::Debug;
    use num::complex::Complex32;

    fn assert_eq_tol<T>(left: &[T], right: &[T], tol: T)
        where T: RealNumber + Debug {
        assert_eq!(left.len(), right.len());
        for i in 0..left.len() {
            if (left[i] - right[i]).abs() > tol {
                panic!("assertion failed: {:?} != {:?}", left, right);
            }
        }
    }
    /*
	#[test]
	fn convolve_real_and_time32() {
        let result = {
            let vector = RealTimeVector32::from_constant(1.0, 10);
            let conv = RaiseCosineFuncton::new(0.35);
            vector.convolve(&conv).unwrap()
        };

        assert_eq!(result.data(), &[0.0; 10])
    }

    #[test]
	fn convolve_complex_time_and_time32() {
        let vector = ComplexTimeVector32::from_constant(Complex32::new(1.0, 0.0), 10);
        let rc = RaiseCosineFuncton::new(0.35);
        let real = RealTimeLinearTableLookup::<f32>::from_conv_function(&rc, 0.4, 10);
        let complex = real.to_complex();
        let result = vector.convolve(&complex as &ComplexTimeConvFunction<f32>).unwrap();
        assert_eq!(result.data(), &[0.0; 10])
    }

    #[test]
	fn convolve_complex_time_and_freq32() {
        let vector = ComplexTimeVector32::from_constant(Complex32::new(1.0, 0.0), 10);
        let rc = RaiseCosineFuncton::new(0.35);
        let real = RealTimeLinearTableLookup::<f32>::from_conv_function(&rc, 0.4, 10);
        let freq = real.to_complex().fft();
        let result = vector.convolve(&freq as &ComplexFrequencyConvFunction<f32>).unwrap();
        assert_eq!(result.data(), &[0.0; 10])
    }

    #[test]
	fn convolve_complex_freq_and_time32() {
        let vector = ComplexFreqVector32::from_constant(Complex32::new(1.0, 0.0), 10);
        let rc = RaiseCosineFuncton::new(0.35);
        let real = RealTimeLinearTableLookup::<f32>::from_conv_function(&rc, 0.4, 10);
        let complex = real.to_complex();
        let result = vector.convolve(&complex as &ComplexTimeConvFunction<f32>).unwrap();
        assert_eq!(result.data(), &[0.0; 10])
    }*/

    #[test]
	fn convolve_real_freq_and_freq32() {
        let vector = ComplexFreqVector32::from_constant(Complex32::new(1.0, 1.0), 10);
        let rc: RaisedCosineFuncton<f32> = RaisedCosineFuncton::new(1.0);
        let result = vector.convolve(&rc as &RealFrequencyConvFunction<f32>).unwrap();
        let expected =
            [0.0, 0.0, 0.3454914, 0.3454914, 0.9045085, 0.9045085, 0.9045085, 0.9045085, 0.3454914, 0.3454914];
        assert_eq_tol(result.data(), &expected, 1e-4);
    }

    #[test]
	fn convolve_real_time_and_time32() {
        let vector = RealTimeVector32::from_array_with_delta(&[0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0], 0.2);
        let rc: RaisedCosineFuncton<f32> = RaisedCosineFuncton::new(0.35);
        let result = vector.convolve(&rc as &RealTimeConvFunction<f32>).unwrap();
        let expected =
            [0.0, 0.2171850639713355, 0.4840621929215732, 0.7430526238101408, 0.9312114164253432,
             1.0, 0.9312114164253432, 0.7430526238101408, 0.4840621929215732, 0.2171850639713355];
        assert_eq_tol(result.data(), &expected, 1e-4);
    }
}<|endoftext|>


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

//! Local state for keys in the snapshot in progress (the "index").

use std::time::duration::{Duration};

use periodic_timer::{PeriodicTimer};
use process::{Process, MsgHandler};
use sqlite3::database::{Database};

use sqlite3::cursor::{Cursor};
use sqlite3::types::ResultCode::{SQLITE_ROW, SQLITE_DONE};
use sqlite3::{open};

use rustc_serialize::hex::{ToHex};

pub trait KeyEntry<KE> {
  fn id(&self) -> Option<u64>;
  fn parent_id(&self) -> Option<u64>;

  fn name(&self) -> Vec<u8>;
  fn size(&self) -> Option<u64>;

  // TODO(jos): SQLite3 supports only i64 precisely. Do we propagate this type or convert to it?
  // Currently, values larger than 1<<63 gets converted to doubles silently and breaks.
  fn created(&self) -> Option<u64>;
  fn modified(&self) -> Option<u64>;
  fn accessed(&self) -> Option<u64>;

  fn permissions(&self) -> Option<u64>;
  fn user_id(&self) -> Option<u64>;
  fn group_id(&self) -> Option<u64>;

  fn with_id(&self, u64) -> KE;
}

pub type KeyIndexProcess<KE> = Process<Msg<KE>, Reply>;

pub enum Msg<KeyEntryT> {

  /// Insert an entry in the key index.
  /// Returns `Id` with the new entry ID.
  Insert(KeyEntryT),

  /// Lookup an entry in the key index, to see if it exists.
  /// Returns either `Id` with the found entry ID or `Notfound`.
  LookupExact(KeyEntryT),

  /// Update the `payload` and `persistent_ref` of an entry.
  /// Returns `UpdateOK`.
  UpdateDataHash(KeyEntryT, Option<Vec<u8>>, Option<Vec<u8>>),

  /// List a directory (aka. `level`) in the index.
  /// Returns `ListResult` with all the entries under the given parent.
  ListDir(Option<u64>),

  /// Flush this key index.
  Flush,
}

pub enum Reply {
  Id(u64),
  NotFound,
  UpdateOK,
  ListResult(Vec<(u64, Vec<u8>, u64, u64, u64, Vec<u8>, Vec<u8>)>),
  FlushOK,
}

pub struct KeyIndex {
  path: String,
  dbh: Database,
  flush_timer: PeriodicTimer,
}

fn i64_to_u64_or_panic(x: i64) -> u64 {
  if x < 0 {
    panic!("expected u64, got {:?}", x);
  }
  return x as u64
}

impl KeyIndex {
  pub fn new(path: String) -> KeyIndex {
    let mut ki = match open(&path) {
      Ok(dbh) => {
        KeyIndex{path: path,
                 dbh: dbh,
                 flush_timer: PeriodicTimer::new(Duration::seconds(5))}
      },
      Err(err) => panic!("{:?}", err),
    };
    ki.exec_or_die("CREATE TABLE IF NOT EXISTS
                    key_index (rowid          INTEGER PRIMARY KEY,
                               parent         INTEGER,
                               name           BLOB,
                               created        UINT8,
                               modified       UINT8,
                               accessed       UINT8,
                               hash           BLOB,
                               persistent_ref BLOB
                            );");

    if cfg!(test) {
      ki.exec_or_die("CREATE UNIQUE INDEX IF NOT EXISTS
                      KeyIndex_UniqueParentName
                      ON key_index(parent, name)");
    }

    ki.exec_or_die("BEGIN");
    ki
  }

  #[cfg(test)]
  pub fn new_for_testing() -> KeyIndex {
    KeyIndex::new(":memory:".to_string())
  }

  fn exec_or_die(&mut self, sql: &str) {
    match self.dbh.exec(sql) {
      Ok(true) => (),
      Ok(false) => panic!("exec: {:?}, {}", self.dbh.get_errmsg(), sql),
      Err(msg) => panic!("exec: {:?}, {:?}, {}", msg, self.dbh.get_errmsg(), sql),
    }
  }

  fn prepare_or_die<'a>(&'a mut self, sql: &str) -> Cursor<'a> {
    match self.dbh.prepare(sql, &None) {
      Ok(s)  => s,
      Err(x) => panic!("sqlite error: {} ({:?})", self.dbh.get_errmsg(), x),
    }
  }

  pub fn maybe_flush(&mut self) {
    if self.flush_timer.did_fire() {
      self.flush();
    }
  }

  pub fn flush(&mut self) {
    self.exec_or_die("COMMIT; BEGIN");
  }
}

impl Clone for KeyIndex {
  fn clone(&self) -> KeyIndex {
    KeyIndex::new(self.path.clone())
  }
}

impl Drop for KeyIndex {
  fn drop(&mut self) {
    self.exec_or_die("COMMIT");
  }
}

impl <A: KeyEntry<A>> MsgHandler<Msg<A>, Reply> for KeyIndex {
  fn handle(&mut self, msg: Msg<A>, reply: Box<Fn(Reply)>) {
    match msg {

      Msg::Insert(entry) => {
        let parent = entry.parent_id().unwrap_or(0);

        self.exec_or_die(&format!(
          "INSERT OR REPLACE INTO key_index (parent, name, created, modified, accessed)
           VALUES ({:?}, x'{}', {}, {}, {})",
          parent, entry.name().to_hex(),
          entry.created().unwrap_or(0),
          entry.modified().unwrap_or(0),
          entry.accessed().unwrap_or(0)));

        let id = self.dbh.get_last_insert_rowid();
        return reply(Reply::Id(i64_to_u64_or_panic(id)));
      },

      Msg::LookupExact(entry) => {
        let parent = entry.parent_id().unwrap_or(0);
        let mut cursor = self.prepare_or_die(&format!(
          "SELECT rowid FROM key_index
           WHERE parent={:?} AND name=x'{}'
           AND created={} AND modified={} AND accessed={}
           LIMIT 1",
          parent, entry.name().to_hex(),
          entry.created().unwrap_or(0),
          entry.modified().unwrap_or(0),
          entry.accessed().unwrap_or(0)));
        if cursor.step() == SQLITE_ROW {
          assert!(cursor.step() == SQLITE_DONE);
          return reply(Reply::Id((i64_to_u64_or_panic(cursor.get_i64(0)))));
        } else {
          return reply(Reply::NotFound);
        }
      },

      Msg::UpdateDataHash(entry, hash_opt, persistent_ref_opt) => {
        let parent = entry.parent_id().unwrap_or(0);

        assert!(hash_opt.is_some() == persistent_ref_opt.is_some());

        if hash_opt.is_some() && persistent_ref_opt.is_some() {
          match entry.modified() {
            Some(modified) => {
              self.exec_or_die(&format!(
                "UPDATE key_index SET hash=x'{}', persistent_ref=x'{}'
                                                  , modified={}
                  WHERE parent={:?} AND rowid={:?} AND IFNULL(modified,0)<={}",
                hash_opt.unwrap().to_hex(),
                persistent_ref_opt.unwrap().to_hex(),
                modified, parent, entry.id().expect("UpdateDataHash"),
                modified));
            },
            None => {
              self.exec_or_die(&format!(
                "UPDATE key_index SET hash=x'{}', persistent_ref=x'{}'
                 WHERE parent={:?} AND rowid={:?}",
                hash_opt.unwrap().to_hex(),
                persistent_ref_opt.unwrap().to_hex(),
                parent, entry.id().expect("UpdateDataHash, None")));
            }
          }
        } else {
          match entry.modified() {
            Some(modified) => {
              self.exec_or_die(&format!(
                "UPDATE key_index SET hash=NULL, persistent_ref=NULL
                                               , modified={}
                 WHERE parent={:?} AND rowid={:?} AND IFNULL(modified, 0)<={}",
                modified, parent, entry.id().expect("UpdateDataHash2"), modified));
            },
            None => {
              self.exec_or_die(&format!(
                "UPDATE key_index SET hash=NULL, persistent_ref=NULL
                 WHERE parent={:?} AND rowid={}",
                parent, entry.id().expect("UpdateDataHash2, None")));
            }
          }
        }

        self.maybe_flush();
        return reply(Reply::UpdateOK);
      },

      Msg::Flush => {
        self.flush();
        return reply(Reply::FlushOK);
      },

      Msg::ListDir(parent_opt) => {
        let mut listing = Vec::new();
        let parent = parent_opt.unwrap_or(0);

        let mut cursor = self.prepare_or_die(&format!(
           "SELECT rowid, name, created, modified, accessed, hash, persistent_ref
            FROM key_index
            WHERE parent={:?}", parent));

        while cursor.step() == SQLITE_ROW {
          let id = i64_to_u64_or_panic(cursor.get_i64(0));
          let name = cursor.get_blob(1).expect("name").iter().map(|&x| x).collect();
          let created = cursor.get_i64(2);
          let modified = cursor.get_i64(3);
          let accessed = cursor.get_i64(4);
          let hash = cursor.get_blob(5).unwrap_or(&[]).iter().map(|&x| x).collect();
          let persistent_ref = cursor.get_blob(6).unwrap_or(&[]).iter().map(|&x| x).collect();

          listing.push((id, name,
                        created as u64, modified as u64, accessed as u64,
                        hash, persistent_ref));
        }

        return reply(Reply::ListResult(listing));
      },
    }
  }
}

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

  struct TestEntry {
    id: Option<u64>,
    parent: Option<u64>,
    name: Vec<u8>,
  }
  impl KeyEntry<TestEntry> for TestEntry {
    fn id(&self) -> Option<u64> {
      None
    }
    fn parent_id(&self) -> Option<u64>{
      self.parent.clone()
    }
    fn name(&self) -> Vec<u8> {
      self.name.clone()
    }

    fn size(&self) -> Option<u64> {
      None
    }

    fn created(&self) -> Option<u64> {
      None
    }
    fn modified(&self) -> Option<u64> {
      None
    }
    fn accessed(&self) -> Option<u64> {
      None
    }

    fn permissions(&self) -> Option<u64> {
      None
    }
    fn user_id(&self) -> Option<u64> {
      None
    }
    fn group_id(&self) -> Option<u64> {
      None
    }
    fn with_id(&self, id: u64) -> TestEntry {
      TestEntry{id:Some(id),
                parent: self.parent_id(),
                name: self.name()}
    }
  }

}
<commit_msg>Bugfix: Key index was trying to read values from a SQLite cursor that had moved past its row.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Local state for keys in the snapshot in progress (the "index").

use std::time::duration::{Duration};

use periodic_timer::{PeriodicTimer};
use process::{Process, MsgHandler};
use sqlite3::database::{Database};

use sqlite3::cursor::{Cursor};
use sqlite3::types::ResultCode::{SQLITE_ROW, SQLITE_DONE};
use sqlite3::{open};

use rustc_serialize::hex::{ToHex};

pub trait KeyEntry<KE> {
  fn id(&self) -> Option<u64>;
  fn parent_id(&self) -> Option<u64>;

  fn name(&self) -> Vec<u8>;
  fn size(&self) -> Option<u64>;

  // TODO(jos): SQLite3 supports only i64 precisely. Do we propagate this type or convert to it?
  // Currently, values larger than 1<<63 gets converted to doubles silently and breaks.
  fn created(&self) -> Option<u64>;
  fn modified(&self) -> Option<u64>;
  fn accessed(&self) -> Option<u64>;

  fn permissions(&self) -> Option<u64>;
  fn user_id(&self) -> Option<u64>;
  fn group_id(&self) -> Option<u64>;

  fn with_id(&self, u64) -> KE;
}

pub type KeyIndexProcess<KE> = Process<Msg<KE>, Reply>;

pub enum Msg<KeyEntryT> {

  /// Insert an entry in the key index.
  /// Returns `Id` with the new entry ID.
  Insert(KeyEntryT),

  /// Lookup an entry in the key index, to see if it exists.
  /// Returns either `Id` with the found entry ID or `Notfound`.
  LookupExact(KeyEntryT),

  /// Update the `payload` and `persistent_ref` of an entry.
  /// Returns `UpdateOK`.
  UpdateDataHash(KeyEntryT, Option<Vec<u8>>, Option<Vec<u8>>),

  /// List a directory (aka. `level`) in the index.
  /// Returns `ListResult` with all the entries under the given parent.
  ListDir(Option<u64>),

  /// Flush this key index.
  Flush,
}

pub enum Reply {
  Id(u64),
  NotFound,
  UpdateOK,
  ListResult(Vec<(u64, Vec<u8>, u64, u64, u64, Vec<u8>, Vec<u8>)>),
  FlushOK,
}

pub struct KeyIndex {
  path: String,
  dbh: Database,
  flush_timer: PeriodicTimer,
}

fn i64_to_u64_or_panic(x: i64) -> u64 {
  if x < 0 {
    panic!("expected u64, got {:?}", x);
  }
  return x as u64
}

impl KeyIndex {
  pub fn new(path: String) -> KeyIndex {
    let mut ki = match open(&path) {
      Ok(dbh) => {
        KeyIndex{path: path,
                 dbh: dbh,
                 flush_timer: PeriodicTimer::new(Duration::seconds(5))}
      },
      Err(err) => panic!("{:?}", err),
    };
    ki.exec_or_die("CREATE TABLE IF NOT EXISTS
                    key_index (rowid          INTEGER PRIMARY KEY,
                               parent         INTEGER,
                               name           BLOB,
                               created        UINT8,
                               modified       UINT8,
                               accessed       UINT8,
                               hash           BLOB,
                               persistent_ref BLOB
                            );");

    if cfg!(test) {
      ki.exec_or_die("CREATE UNIQUE INDEX IF NOT EXISTS
                      KeyIndex_UniqueParentName
                      ON key_index(parent, name)");
    }

    ki.exec_or_die("BEGIN");
    ki
  }

  #[cfg(test)]
  pub fn new_for_testing() -> KeyIndex {
    KeyIndex::new(":memory:".to_string())
  }

  fn exec_or_die(&mut self, sql: &str) {
    match self.dbh.exec(sql) {
      Ok(true) => (),
      Ok(false) => panic!("exec: {:?}, {}", self.dbh.get_errmsg(), sql),
      Err(msg) => panic!("exec: {:?}, {:?}, {}", msg, self.dbh.get_errmsg(), sql),
    }
  }

  fn prepare_or_die<'a>(&'a mut self, sql: &str) -> Cursor<'a> {
    match self.dbh.prepare(sql, &None) {
      Ok(s)  => s,
      Err(x) => panic!("sqlite error: {} ({:?})", self.dbh.get_errmsg(), x),
    }
  }

  pub fn maybe_flush(&mut self) {
    if self.flush_timer.did_fire() {
      self.flush();
    }
  }

  pub fn flush(&mut self) {
    self.exec_or_die("COMMIT; BEGIN");
  }
}

impl Clone for KeyIndex {
  fn clone(&self) -> KeyIndex {
    KeyIndex::new(self.path.clone())
  }
}

impl Drop for KeyIndex {
  fn drop(&mut self) {
    self.exec_or_die("COMMIT");
  }
}

impl <A: KeyEntry<A>> MsgHandler<Msg<A>, Reply> for KeyIndex {
  fn handle(&mut self, msg: Msg<A>, reply: Box<Fn(Reply)>) {
    match msg {

      Msg::Insert(entry) => {
        let parent = entry.parent_id().unwrap_or(0);

        self.exec_or_die(&format!(
          "INSERT OR REPLACE INTO key_index (parent, name, created, modified, accessed)
           VALUES ({:?}, x'{}', {}, {}, {})",
          parent, entry.name().to_hex(),
          entry.created().unwrap_or(0),
          entry.modified().unwrap_or(0),
          entry.accessed().unwrap_or(0)));

        let id = self.dbh.get_last_insert_rowid();
        return reply(Reply::Id(i64_to_u64_or_panic(id)));
      },

      Msg::LookupExact(entry) => {
        let parent = entry.parent_id().unwrap_or(0);
        let mut cursor = self.prepare_or_die(&format!(
          "SELECT rowid FROM key_index
           WHERE parent={:?} AND name=x'{}'
           AND created={} AND modified={} AND accessed={}
           LIMIT 1",
          parent, entry.name().to_hex(),
          entry.created().unwrap_or(0),
          entry.modified().unwrap_or(0),
          entry.accessed().unwrap_or(0)));
        if cursor.step() == SQLITE_ROW {
          let id = i64_to_u64_or_panic(cursor.get_i64(0));
          assert!(cursor.step() == SQLITE_DONE);
          return reply(Reply::Id(id));
        } else {
          return reply(Reply::NotFound);
        }
      },

      Msg::UpdateDataHash(entry, hash_opt, persistent_ref_opt) => {
        let parent = entry.parent_id().unwrap_or(0);

        assert!(hash_opt.is_some() == persistent_ref_opt.is_some());

        if hash_opt.is_some() && persistent_ref_opt.is_some() {
          match entry.modified() {
            Some(modified) => {
              self.exec_or_die(&format!(
                "UPDATE key_index SET hash=x'{}', persistent_ref=x'{}'
                                                  , modified={}
                  WHERE parent={:?} AND rowid={:?} AND IFNULL(modified,0)<={}",
                hash_opt.unwrap().to_hex(),
                persistent_ref_opt.unwrap().to_hex(),
                modified, parent, entry.id().expect("UpdateDataHash"),
                modified));
            },
            None => {
              self.exec_or_die(&format!(
                "UPDATE key_index SET hash=x'{}', persistent_ref=x'{}'
                 WHERE parent={:?} AND rowid={:?}",
                hash_opt.unwrap().to_hex(),
                persistent_ref_opt.unwrap().to_hex(),
                parent, entry.id().expect("UpdateDataHash, None")));
            }
          }
        } else {
          match entry.modified() {
            Some(modified) => {
              self.exec_or_die(&format!(
                "UPDATE key_index SET hash=NULL, persistent_ref=NULL
                                               , modified={}
                 WHERE parent={:?} AND rowid={:?} AND IFNULL(modified, 0)<={}",
                modified, parent, entry.id().expect("UpdateDataHash2"), modified));
            },
            None => {
              self.exec_or_die(&format!(
                "UPDATE key_index SET hash=NULL, persistent_ref=NULL
                 WHERE parent={:?} AND rowid={}",
                parent, entry.id().expect("UpdateDataHash2, None")));
            }
          }
        }

        self.maybe_flush();
        return reply(Reply::UpdateOK);
      },

      Msg::Flush => {
        self.flush();
        return reply(Reply::FlushOK);
      },

      Msg::ListDir(parent_opt) => {
        let mut listing = Vec::new();
        let parent = parent_opt.unwrap_or(0);

        let mut cursor = self.prepare_or_die(&format!(
           "SELECT rowid, name, created, modified, accessed, hash, persistent_ref
            FROM key_index
            WHERE parent={:?}", parent));

        while cursor.step() == SQLITE_ROW {
          let id = i64_to_u64_or_panic(cursor.get_i64(0));
          let name = cursor.get_blob(1).expect("name").iter().map(|&x| x).collect();
          let created = cursor.get_i64(2);
          let modified = cursor.get_i64(3);
          let accessed = cursor.get_i64(4);
          let hash = cursor.get_blob(5).unwrap_or(&[]).iter().map(|&x| x).collect();
          let persistent_ref = cursor.get_blob(6).unwrap_or(&[]).iter().map(|&x| x).collect();

          listing.push((id, name,
                        created as u64, modified as u64, accessed as u64,
                        hash, persistent_ref));
        }

        return reply(Reply::ListResult(listing));
      },
    }
  }
}

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

  struct TestEntry {
    id: Option<u64>,
    parent: Option<u64>,
    name: Vec<u8>,
  }
  impl KeyEntry<TestEntry> for TestEntry {
    fn id(&self) -> Option<u64> {
      None
    }
    fn parent_id(&self) -> Option<u64>{
      self.parent.clone()
    }
    fn name(&self) -> Vec<u8> {
      self.name.clone()
    }

    fn size(&self) -> Option<u64> {
      None
    }

    fn created(&self) -> Option<u64> {
      None
    }
    fn modified(&self) -> Option<u64> {
      None
    }
    fn accessed(&self) -> Option<u64> {
      None
    }

    fn permissions(&self) -> Option<u64> {
      None
    }
    fn user_id(&self) -> Option<u64> {
      None
    }
    fn group_id(&self) -> Option<u64> {
      None
    }
    fn with_id(&self, id: u64) -> TestEntry {
      TestEntry{id:Some(id),
                parent: self.parent_id(),
                name: self.name()}
    }
  }

}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Non-arch-specific paging.
use memory::{Addr, VAddr, PAddr, PAGE_SHIFT, PAGE_SIZE};
use memory::alloc::FrameAllocator;
use core::{ops, cmp};
use core::ops::Range;

pub use arch::memory::PhysicalPage;
pub use arch::memory::paging::*;

pub type PageRange = Range<VirtualPage>;
pub type FrameRange = Range<PhysicalPage>;

/// Trait for a page. These can be virtual pages or physical frames.
pub trait Page
where Self: Sized
    , Self: ops::AddAssign<usize> + ops::SubAssign<usize>
    , Self: ops::Add<usize, Output=Self> + ops::Sub<usize, Output=Self>
    , Self: cmp::PartialEq<Self> + cmp::PartialOrd<Self>
    , Self: Copy + Clone {

    /// The type of address used to address this `Page`.
    ///
    /// Typically, this is a `PAddr` or `VAddr` (but it could be a "MAddr")
    /// in schemes where we differentiate between physical and machine
    /// addresses. If we ever have those.
    type Address: Addr;

    /// Returns a new `Page` containing the given `Address`.
    ///
    /// N.B. that since trait functions cannot be `const`, implementors of
    /// this trait may wish to provide implementations of this function
    /// outside of the `impl` block and then wrap them here.
    fn containing(addr: Self::Address) -> Self;

    /// Returns the base `Address` where this page starts.
    fn base(&self) -> Self::Address;

    ///// Convert the frame into a raw pointer to the frame's base address
    //#[inline]
    //unsafe fn as_ptr<T>(&self) -> *const T {
    //    mem::transmute(self.base())
    //}
    //
    ///// Convert the frame into a raw mutable pointer to the frame's base address
    //#[inline]
    //unsafe fn as_mut_ptr<T>(&self) -> *mut T {
    //    mem::transmute(self.base())
    //}

    /// Returns a `PageRange` of this `Page` and the next `n` pages.
    #[inline]
    fn range_of(&self, n: usize) -> Range<Self> {
        self.range_until(*self + n)
    }

    /// Returns a `PageRange` on the frames from this frame until the end frame
    #[inline]
    fn range_until(&self, end: Self) -> Range<Self> {
        Range { start: *self, end: end }
    }

    fn number(&self) -> usize;

}
//
///// A range of `Page`s.
//#[derive(Copy, Clone, Debug, Eq, PartialEq)]
//pub struct Range

//where P: Page { start: P, end: P }
//
pub trait MemRange {
    /// Returns the number of `Page`s in this ranage
    #[inline]
    fn length(&self) -> usize;

    /// Remove `n` pages from the beginning of this `PageRange`
    fn drop_front(&mut self, n: usize) -> &mut Self;

    /// Remove `n` pages from the end of this `PageRange`
    fn drop_back(&mut self, n: usize) -> &mut Self;

    /// Add `n` pages at the front of this `PageRange`
    fn add_front(&mut self, n: usize) -> &mut Self;

    /// Add `n` pages at the back of this `PageRange`
    fn add_back(&mut self, n: usize) -> &mut Self;
}
    //pub const fn start(&self) -> P { self.start }
   //
   ///// Returns a `PageRange` between two pages
   //pub const fn between(start: P, end: P) -> Range
 {
   //    Range { start: start, end: end }
   //}
   //
   // /// Returns an iterator over this `PageRange`
   // pub fn iter<'a>(&'a self) -> RangeIter<'a, P> {
   //     RangeIter { range: self, current: self.start.clone() }
   // }

impl
 MemRange for Range

where P: Page {

    /// Returns the number of `Page`s in this ranage
    #[inline]
    fn length(&self) -> usize {
        self.end.number() - self.start.number()
    }

    /// Remove `n` pages from the beginning of this `PageRange`
    fn drop_front(&mut self, n: usize) -> &mut Self {
        assert!(n < self.length());
        self.start += n;
        self
    }

    /// Remove `n` pages from the end of this `PageRange`
    fn drop_back(&mut self, n: usize) -> &mut Self {
        assert!(n < self.length());
        self.end -= n;
        self
    }

    /// Add `n` pages at the front of this `PageRange`
    fn add_front(&mut self, n: usize) -> &mut Self {
        self.start -= n;
        self
    }

    /// Add `n` pages at the back of this `PageRange`
    fn add_back(&mut self, n: usize) -> &mut Self {
        self.end += n;
        self
    }
}

/// An iterator over a range of pages
pub struct RangeIter<'a, P>
where P: Page
    , P: 'a { range: &'a Range
, current: P }

impl<'a, P> Iterator for RangeIter<'a, P>
where P: Page
    , P: Clone {
    type Item = P;

    fn next(&mut self) -> Option
 {
        let end = self.range.end;
      assert!(self.range.start <= end);
      if self.current < end {
          let page = self.current.clone();
          self.current += 1;
          Some(page)
      } else {
          None
      }
  }

}

pub trait Mapper {
    type Flags;

    /// Translates a virtual address to the corresponding physical address.
    ///
    /// # Return
    /// + `Some(PAddr)` containing the physical address corresponding to
    ///                 `vaddr`, if it is mapped.
    /// + `None`: if the address is not mapped.
    fn translate(&self, vaddr: VAddr) -> Option<PAddr>;

    /// Translates a virtual page to a physical frame.
    fn translate_page(&self, page: VirtualPage) -> Option<PhysicalPage>;

    /// Modifies the page tables so that `page` maps to `frame`.
    ///
    /// # Arguments
    /// + `page`: the virtual `Page` to map
    /// + `frame`: the physical `Frame` that `Page` should map to.
    /// + `flags`: the page table entry flags.
    /// + `alloc`: a memory allocator
    fn map( &mut self, page: VirtualPage, frame: PhysicalPage
             , flags: Self::Flags, alloc: &mut A )
    where A: FrameAllocator;

    /// Identity map a given `frame`.
    ///
    /// # Arguments
    /// + `frame`: the physical `Frame` to identity map
    /// + `flags`: the page table entry flags.
    /// + `alloc`: a memory allocator
    fn identity_map( &mut self, frame: PhysicalPage
                      , flags: Self::Flags, alloc: &mut A )
    where A: FrameAllocator;

    /// Map the given `VirtualPage` to any free frame.
    ///
    /// This is like the fire and forget version of `map_to`: we just pick the
    /// first available free frame and map the page to it.
    ///
    /// # Arguments
    /// + `page`: the`VirtualPage` to map
    /// + `flags`: the page table entry flags.
    /// + `alloc`: a memory allocator
    fn map_to_any( &mut self, page: VirtualPage
                    , flags: Self::Flags
                    , alloc: &mut A)
    where A: FrameAllocator;

    /// Unmap the given `VirtualPage`.
    ///
    /// All freed frames are returned to the given `FrameAllocator`.
    fn unmap(&mut self, page: VirtualPage, alloc: &mut A)
    where A: FrameAllocator;

}

macro_rules! table_idx {
    ( $($name:ident >> $shift:expr)* ) => {$(
        pub fn $name(&self) -> usize {
            (self.number >> $shift) & 0o777
        }
    )*};
}

custom_derive!{
    /// A virtual page
    #[derive( Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Page(VAddr) )]
    pub struct VirtualPage { pub number: usize }
}
//
//impl ops::Add<usize> for VirtualPage {
//    type Output = Self;
//
//    #[inline]
//    fn add(self, amount: usize) -> Self {
//        VirtualPage { number: self.number + amount }
//    }
//}
//
//impl ops::Sub<usize> for VirtualPage {
//    type Output = Self;
//
//    #[inline]
//    fn sub(self, amount: usize) -> Self {
//        VirtualPage { number: self.number - amount}
//    }
//}
//
//
//impl ops::AddAssign for VirtualPage {
//    #[inline(always)]
//    fn add_assign(&mut self, rhs: Self) {
//        self.number += rhs.number
//    }
//}
//
//impl ops::AddAssign<usize> for VirtualPage {
//    #[inline(always)]
//    fn add_assign(&mut self, rhs: usize) {
//        self.number += rhs
//    }
//}
//
//impl ops::SubAssign for VirtualPage {
//    #[inline]
//    fn sub_assign(&mut self, rhs: Self) {
//        self.number -= rhs.number
//    }
//}
//
//impl ops::SubAssign<usize> for VirtualPage {
//    #[inline]
//    fn sub_assign(&mut self, rhs: usize) {
//        self.number -= rhs
//    }
//}

//impl Page for VirtualPage {
//    type Address = VAddr;
//
//    /// Create a new `Page` containing the given virtual address.
//    //  TODO: rewrite this as `up`/`down` using the page shift, instead.
//    fn containing(addr: VAddr) -> Self {
//        assert!( *addr < 0x0000_8000_0000_0000 ||
//                 *addr >= 0xffff_8000_0000_0000
//               , "invalid address: 0x{:x}", addr );
//        VirtualPage { number: *addr >> PAGE_SHIFT }
//    }
//
//    /// Return the start virtual address of this page
//    #[inline]
//    fn base(&self) -> VAddr {
//        VAddr::from(self.number << PAGE_SHIFT)
//    }
//
//    #[inline] fn number(&self) -> usize {
//        self.number
//    }
//}

impl VirtualPage {

    /// Flush the page from memory
    //  TODO: this is arch-specific, move it to arch
    pub unsafe fn flush(&self) {
        asm!( "invlpg [$0]"
            :
            : "{rax}"(self.base())
            : "memory"
            : "intel", "volatile")
    }

    // TODO: these are arch-specific, move them to `arch`
    table_idx!{
        pml4_index >> 27
        pdpt_index >> 18
        pd_index >> 9
        pt_index >> 0
    }

}
<commit_msg>[kernel] remove an unused import<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Non-arch-specific paging.
use memory::{Addr, VAddr, PAddr, PAGE_SHIFT};
use memory::alloc::FrameAllocator;
use core::{ops, cmp};
use core::ops::Range;

pub use arch::memory::PhysicalPage;
pub use arch::memory::paging::*;

pub type PageRange = Range<VirtualPage>;
pub type FrameRange = Range<PhysicalPage>;

/// Trait for a page. These can be virtual pages or physical frames.
pub trait Page
where Self: Sized
    , Self: ops::AddAssign<usize> + ops::SubAssign<usize>
    , Self: ops::Add<usize, Output=Self> + ops::Sub<usize, Output=Self>
    , Self: cmp::PartialEq<Self> + cmp::PartialOrd<Self>
    , Self: Copy + Clone {

    /// The type of address used to address this `Page`.
    ///
    /// Typically, this is a `PAddr` or `VAddr` (but it could be a "MAddr")
    /// in schemes where we differentiate between physical and machine
    /// addresses. If we ever have those.
    type Address: Addr;

    /// Returns a new `Page` containing the given `Address`.
    ///
    /// N.B. that since trait functions cannot be `const`, implementors of
    /// this trait may wish to provide implementations of this function
    /// outside of the `impl` block and then wrap them here.
    fn containing(addr: Self::Address) -> Self;

    /// Returns the base `Address` where this page starts.
    fn base(&self) -> Self::Address;

    ///// Convert the frame into a raw pointer to the frame's base address
    //#[inline]
    //unsafe fn as_ptr<T>(&self) -> *const T {
    //    mem::transmute(self.base())
    //}
    //
    ///// Convert the frame into a raw mutable pointer to the frame's base address
    //#[inline]
    //unsafe fn as_mut_ptr<T>(&self) -> *mut T {
    //    mem::transmute(self.base())
    //}

    /// Returns a `PageRange` of this `Page` and the next `n` pages.
    #[inline]
    fn range_of(&self, n: usize) -> Range<Self> {
        self.range_until(*self + n)
    }

    /// Returns a `PageRange` on the frames from this frame until the end frame
    #[inline]
    fn range_until(&self, end: Self) -> Range<Self> {
        Range { start: *self, end: end }
    }

    fn number(&self) -> usize;

}
//
///// A range of `Page`s.
//#[derive(Copy, Clone, Debug, Eq, PartialEq)]
//pub struct Range

//where P: Page { start: P, end: P }
//
pub trait MemRange {
    /// Returns the number of `Page`s in this ranage
    #[inline]
    fn length(&self) -> usize;

    /// Remove `n` pages from the beginning of this `PageRange`
    fn drop_front(&mut self, n: usize) -> &mut Self;

    /// Remove `n` pages from the end of this `PageRange`
    fn drop_back(&mut self, n: usize) -> &mut Self;

    /// Add `n` pages at the front of this `PageRange`
    fn add_front(&mut self, n: usize) -> &mut Self;

    /// Add `n` pages at the back of this `PageRange`
    fn add_back(&mut self, n: usize) -> &mut Self;
}
    //pub const fn start(&self) -> P { self.start }
   //
   ///// Returns a `PageRange` between two pages
   //pub const fn between(start: P, end: P) -> Range
 {
   //    Range { start: start, end: end }
   //}
   //
   // /// Returns an iterator over this `PageRange`
   // pub fn iter<'a>(&'a self) -> RangeIter<'a, P> {
   //     RangeIter { range: self, current: self.start.clone() }
   // }

impl
 MemRange for Range

where P: Page {

    /// Returns the number of `Page`s in this ranage
    #[inline]
    fn length(&self) -> usize {
        self.end.number() - self.start.number()
    }

    /// Remove `n` pages from the beginning of this `PageRange`
    fn drop_front(&mut self, n: usize) -> &mut Self {
        assert!(n < self.length());
        self.start += n;
        self
    }

    /// Remove `n` pages from the end of this `PageRange`
    fn drop_back(&mut self, n: usize) -> &mut Self {
        assert!(n < self.length());
        self.end -= n;
        self
    }

    /// Add `n` pages at the front of this `PageRange`
    fn add_front(&mut self, n: usize) -> &mut Self {
        self.start -= n;
        self
    }

    /// Add `n` pages at the back of this `PageRange`
    fn add_back(&mut self, n: usize) -> &mut Self {
        self.end += n;
        self
    }
}

/// An iterator over a range of pages
pub struct RangeIter<'a, P>
where P: Page
    , P: 'a { range: &'a Range
, current: P }

impl<'a, P> Iterator for RangeIter<'a, P>
where P: Page
    , P: Clone {
    type Item = P;

    fn next(&mut self) -> Option
 {
        let end = self.range.end;
      assert!(self.range.start <= end);
      if self.current < end {
          let page = self.current.clone();
          self.current += 1;
          Some(page)
      } else {
          None
      }
  }

}

pub trait Mapper {
    type Flags;

    /// Translates a virtual address to the corresponding physical address.
    ///
    /// # Return
    /// + `Some(PAddr)` containing the physical address corresponding to
    ///                 `vaddr`, if it is mapped.
    /// + `None`: if the address is not mapped.
    fn translate(&self, vaddr: VAddr) -> Option<PAddr>;

    /// Translates a virtual page to a physical frame.
    fn translate_page(&self, page: VirtualPage) -> Option<PhysicalPage>;

    /// Modifies the page tables so that `page` maps to `frame`.
    ///
    /// # Arguments
    /// + `page`: the virtual `Page` to map
    /// + `frame`: the physical `Frame` that `Page` should map to.
    /// + `flags`: the page table entry flags.
    /// + `alloc`: a memory allocator
    fn map( &mut self, page: VirtualPage, frame: PhysicalPage
             , flags: Self::Flags, alloc: &mut A )
    where A: FrameAllocator;

    /// Identity map a given `frame`.
    ///
    /// # Arguments
    /// + `frame`: the physical `Frame` to identity map
    /// + `flags`: the page table entry flags.
    /// + `alloc`: a memory allocator
    fn identity_map( &mut self, frame: PhysicalPage
                      , flags: Self::Flags, alloc: &mut A )
    where A: FrameAllocator;

    /// Map the given `VirtualPage` to any free frame.
    ///
    /// This is like the fire and forget version of `map_to`: we just pick the
    /// first available free frame and map the page to it.
    ///
    /// # Arguments
    /// + `page`: the`VirtualPage` to map
    /// + `flags`: the page table entry flags.
    /// + `alloc`: a memory allocator
    fn map_to_any( &mut self, page: VirtualPage
                    , flags: Self::Flags
                    , alloc: &mut A)
    where A: FrameAllocator;

    /// Unmap the given `VirtualPage`.
    ///
    /// All freed frames are returned to the given `FrameAllocator`.
    fn unmap(&mut self, page: VirtualPage, alloc: &mut A)
    where A: FrameAllocator;

}

macro_rules! table_idx {
    ( $($name:ident >> $shift:expr)* ) => {$(
        pub fn $name(&self) -> usize {
            (self.number >> $shift) & 0o777
        }
    )*};
}

custom_derive!{
    /// A virtual page
    #[derive( Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Page(VAddr) )]
    pub struct VirtualPage { pub number: usize }
}
//
//impl ops::Add<usize> for VirtualPage {
//    type Output = Self;
//
//    #[inline]
//    fn add(self, amount: usize) -> Self {
//        VirtualPage { number: self.number + amount }
//    }
//}
//
//impl ops::Sub<usize> for VirtualPage {
//    type Output = Self;
//
//    #[inline]
//    fn sub(self, amount: usize) -> Self {
//        VirtualPage { number: self.number - amount}
//    }
//}
//
//
//impl ops::AddAssign for VirtualPage {
//    #[inline(always)]
//    fn add_assign(&mut self, rhs: Self) {
//        self.number += rhs.number
//    }
//}
//
//impl ops::AddAssign<usize> for VirtualPage {
//    #[inline(always)]
//    fn add_assign(&mut self, rhs: usize) {
//        self.number += rhs
//    }
//}
//
//impl ops::SubAssign for VirtualPage {
//    #[inline]
//    fn sub_assign(&mut self, rhs: Self) {
//        self.number -= rhs.number
//    }
//}
//
//impl ops::SubAssign<usize> for VirtualPage {
//    #[inline]
//    fn sub_assign(&mut self, rhs: usize) {
//        self.number -= rhs
//    }
//}

//impl Page for VirtualPage {
//    type Address = VAddr;
//
//    /// Create a new `Page` containing the given virtual address.
//    //  TODO: rewrite this as `up`/`down` using the page shift, instead.
//    fn containing(addr: VAddr) -> Self {
//        assert!( *addr < 0x0000_8000_0000_0000 ||
//                 *addr >= 0xffff_8000_0000_0000
//               , "invalid address: 0x{:x}", addr );
//        VirtualPage { number: *addr >> PAGE_SHIFT }
//    }
//
//    /// Return the start virtual address of this page
//    #[inline]
//    fn base(&self) -> VAddr {
//        VAddr::from(self.number << PAGE_SHIFT)
//    }
//
//    #[inline] fn number(&self) -> usize {
//        self.number
//    }
//}

impl VirtualPage {

    /// Flush the page from memory
    //  TODO: this is arch-specific, move it to arch
    pub unsafe fn flush(&self) {
        asm!( "invlpg [$0]"
            :
            : "{rax}"(self.base())
            : "memory"
            : "intel", "volatile")
    }

    // TODO: these are arch-specific, move them to `arch`
    table_idx!{
        pml4_index >> 27
        pdpt_index >> 18
        pd_index >> 9
        pt_index >> 0
    }

}
<|endoftext|>


<commit_before>use itertools::Itertools;
use bio::stats::logprobs::LogProb;
use bio::stats::logprobs;

use model;

pub type DiffexpMeasure = f64;
pub type PMF = model::pmf::PMF<DiffexpMeasure>;

/// An estimate of differential expression
pub struct Estimate {
    pub differential_expression_pep: LogProb,
    pub differential_expression_bf: f64,
    pub expected_value: DiffexpMeasure,
    pub standard_deviation: DiffexpMeasure,
    pub credible_interval: (DiffexpMeasure, DiffexpMeasure)
}

impl PMF {
    /// Posterior error probability for differential expression.
    pub fn differential_expression_pep(&self, max_null_value: DiffexpMeasure) -> LogProb {
        let probs = self.iter().filter(|e| e.value.abs() > max_null_value).map(|e| e.prob).collect_vec();
        logprobs::ln_1m_exp(logprobs::sum(&probs))
    }

    /// Bayes factor for differential expression.
    pub fn differential_expression_bf(&self, max_null_value: DiffexpMeasure) -> model::BayesFactor {
        let m0 = self.iter().filter(|e| e.value.abs() <= max_null_value).map(|e| e.prob).collect_vec();
        let m1 = self.iter().filter(|e| e.value.abs() > max_null_value).map(|e| e.prob).collect_vec();

        (logprobs::sum(&m1) - logprobs::sum(&m0)).exp()
    }

    pub fn estimate(&self, max_fc: DiffexpMeasure) -> Estimate {
        Estimate {
            differential_expression_pep: self.differential_expression_pep(max_fc),
            differential_expression_bf: self.differential_expression_bf(max_fc),
            expected_value: self.expected_value(),
            standard_deviation: self.standard_deviation(),
            credible_interval: self.credible_interval()
        }
    }
}
<commit_msg>Make diffexp_pep robust to small numerical problems.<commit_after>use std::f64;

use itertools::Itertools;
use bio::stats::logprobs::LogProb;
use bio::stats::logprobs;

use model;

pub type DiffexpMeasure = f64;
pub type PMF = model::pmf::PMF<DiffexpMeasure>;

/// An estimate of differential expression
pub struct Estimate {
    pub differential_expression_pep: LogProb,
    pub differential_expression_bf: f64,
    pub expected_value: DiffexpMeasure,
    pub standard_deviation: DiffexpMeasure,
    pub credible_interval: (DiffexpMeasure, DiffexpMeasure)
}

impl PMF {
    /// Posterior error probability for differential expression.
    pub fn differential_expression_pep(&self, max_null_value: DiffexpMeasure) -> LogProb {
        let probs = self.iter().filter(|e| e.value.abs() > max_null_value).map(|e| e.prob).collect_vec();
        let s = logprobs::sum(&probs);
        if s > 0.0 {
            f64::NEG_INFINITY
        }
        else {
            logprobs::ln_1m_exp(s)
        }
    }

    /// Bayes factor for differential expression.
    pub fn differential_expression_bf(&self, max_null_value: DiffexpMeasure) -> model::BayesFactor {
        let m0 = self.iter().filter(|e| e.value.abs() <= max_null_value).map(|e| e.prob).collect_vec();
        let m1 = self.iter().filter(|e| e.value.abs() > max_null_value).map(|e| e.prob).collect_vec();

        (logprobs::sum(&m1) - logprobs::sum(&m0)).exp()
    }

    pub fn estimate(&self, max_fc: DiffexpMeasure) -> Estimate {
        Estimate {
            differential_expression_pep: self.differential_expression_pep(max_fc),
            differential_expression_bf: self.differential_expression_bf(max_fc),
            expected_value: self.expected_value(),
            standard_deviation: self.standard_deviation(),
            credible_interval: self.credible_interval()
        }
    }
}
<|endoftext|>


<commit_before>/*
    Copyright 2013 Jesse 'Jeaye' Wilkerson
    See licensing in LICENSE file, or at:
        http://www.opensource.org/licenses/BSD-3-Clause

    File: obj/md5/model.rs
    Author: Jesse 'Jeaye' Wilkerson
    Description:
      Loads, parses, and represents
      the model (as in MVC) side of
      MD5 animated models.
*/

use std::{ io, path, vec, i32 };
use super::{ Joint, Vertex, Triangle, Weight, Mesh };
use math;

struct Model
{
  version: i32,
  num_joints: i32,
  num_meshes: i32,
  is_animated: bool,

  joints: ~[Joint],
  meshes: ~[Mesh],

  //animation: Option<Animation>,

  local_to_world: math::Mat4x4,
}

impl Model
{
  pub fn new(mesh_file: ~str) -> Model
  {
    let mut model = Model
    {
      version: 0,
      num_joints: 0,
      num_meshes: 0,
      is_animated: false,

      joints: ~[],
      meshes: ~[],

      //animation: None,

      local_to_world: math::Mat4x4::new(),
    };

    model.load(mesh_file);

    model
  }

  priv fn load(&mut self, file: ~str) -> bool
  {
    let fior = io::file_reader(&path::Path(file));
    if fior.is_err()
    { error!("Failed to open model file %s", file); return false; }

    /* Clear existing data. */
    self.joints.clear();
    self.meshes.clear();

    let fio = fior.get();
    let mut param = ~"";
    let read_param = ||
    {
      param = ~""; /* TODO: clear? */
      let mut ch = fio.read_char();
      while ch.is_whitespace() && !fio.eof() /* Find the next word. */
      { ch = fio.read_char(); }

      if !fio.eof()
      {
        param.push_char(ch);
        ch = fio.read_char();
        while !ch.is_whitespace() && !fio.eof() /* Read the next word. */
        { param.push_char(ch); ch = fio.read_char(); }
      }
    };
    macro_rules! read_type
    (
      ($var:expr) =>
      ({
        let name = param.clone();
        read_param();
        let num = FromStr::from_str(param);
        if num.is_some()
        { $var = num.get(); }
        else
        { error!("Invalid %s in %s", name, file); }
      });
    )

    /* Read the first param and jump into the parsing. */
    read_param();
    while !fio.eof()
    {
      match param
      {
        ~"MD5Version" =>
        {
          /* Read version. */
          read_type!(self.version);
          debug!("Model version: %?", self.version);
        }
        ~"commandline" =>
        { fio.read_line(); /* Ignore this line. */ }
        ~"numJoints" =>
        {
          read_type!(self.num_joints);
          self.joints = vec::with_capacity(self.num_joints as uint);
          debug!("Model joints: %?", self.num_joints);
        }
        ~"numMeshes" =>
        {
          read_type!(self.num_meshes);
          self.meshes = vec::with_capacity(self.num_meshes as uint);
          debug!("Model meshes: %?", self.num_meshes);
        }
        ~"joints" =>
        {
          let mut joint = Joint::new();
          read_param(); /* read { junk */
          debug!("Reading model joints");

          for i32::range(0, self.num_joints) |_|
          {
            read_param();
            joint.name = param.clone();

            read_type!(joint.parent);

            read_param(); /* junk */
            read_type!(joint.position.x);
            read_type!(joint.position.y);
            read_type!(joint.position.z);
            read_param(); /* junk */
            read_param(); /* junk */
            read_type!(joint.orientation.x);
            read_type!(joint.orientation.y);
            read_type!(joint.orientation.z);
            read_param(); /* junk */

            joint.orientation.compute_w();
            self.joints.push(joint.clone());

            /* Ignore the rest of the line. */
            fio.read_line();
          }

          read_param(); /* read } junk */
        }
        ~"mesh" =>
        {
          let mut mesh = Mesh::new();
          let mut vert = Vertex::new();
          let mut tri = Triangle::new();
          let mut weight = Weight::new();
          let mut num_verts = 0;
          let mut num_tris = 0;
          let mut num_weights = 0;

          debug!("Parsing mesh");

          read_param(); /* Read } junk */
          read_param();
          while param != ~"}"
          {
            match param
            {
              ~"shader" => /* shader == texture path */
              {
                read_param();
                mesh.texture = param.clone();
                debug!("Mesh shader: %s", mesh.texture);

                /* TODO: Load texture. */

                fio.read_line();
              }
              ~"numverts" =>
              {
                read_type!(num_verts);
                fio.read_line();

                debug!("Mesh verts: %?", num_verts);

                for i32::range(0, num_verts) |_|
                {
                  read_param(); /* junk */
                  read_param(); /* junk */
                  read_param(); /* junk */
                  read_type!(vert.tex_coord.x);
                  read_type!(vert.tex_coord.y);
                  read_param(); /* junk */
                  read_type!(vert.start_weight);
                  read_type!(vert.weight_count);

                  fio.read_line();

                  mesh.verts.push(vert);
                  mesh.tex_coords.push(vert.tex_coord);
                }
              }
              ~"numtris" =>
              {
                read_type!(num_tris);
                fio.read_line();
                debug!("Mesh tris: %?", num_tris);

                for i32::range(0, num_tris) |_|
                {
                  read_param(); /* junk */
                  read_param(); /* junk */
                  read_type!(tri.indices[0]);
                  read_type!(tri.indices[1]);
                  read_type!(tri.indices[2]);

                  fio.read_line();

                  mesh.triangles.push(tri);
                  mesh.indices.push(tri.indices[0] as u32);
                  mesh.indices.push(tri.indices[1] as u32);
                  mesh.indices.push(tri.indices[2] as u32);
                }
              }
              ~"numweights" =>
              {
                read_type!(num_weights);
                fio.read_line();
                debug!("Mesh weights: %?", num_weights);

                for i32::range(0, num_weights) |_|
                {
                  read_param(); /* junk */
                  read_param(); /* junk */
                  read_type!(weight.joint_id);
                  read_type!(weight.bias);
                  read_param(); /* junk */
                  read_type!(weight.position.x);
                  read_type!(weight.position.y);
                  read_type!(weight.position.z);
                  read_param(); /* junk */

                  fio.read_line();
                  mesh.weights.push(weight);
                }
              }
              _ =>
              { fio.read_line(); }
            }

            read_param();
          }

          self.prepare_mesh(&mut mesh);
          self.meshes.push(mesh);
        }
        _ => { }
      }

      /* Move to the next param. */
      read_param();
    }

    true
  }

  priv fn prepare_mesh(&mut self, mesh: &mut Mesh)
  {
    mesh.positions.clear();
    mesh.tex_coords.clear();

    for i32::range(0, mesh.verts.len() as i32) |x|
    {
      let vert = &mut mesh.verts[x];
      vert.position = math::Vec3f::zero();
      vert.normal = math::Vec3f::zero();

      /* Sum the position of all the weights. */
      for i32::range(0, vert.weight_count) |w|
      {
        let weight = &mut mesh.weights[vert.start_weight + w];
        let joint = &mut self.joints[weight.joint_id];

        /* Convert the weight position from joint local to object space. */
        let rot_pos = joint.orientation.translate_vec(&weight.position);

        vert.position = vert.position + (joint.position + rot_pos) * weight.bias;
      }

      mesh.positions.push(vert.position);
      mesh.tex_coords.push(vert.tex_coord);
    }
  }
}

<commit_msg> #19 Bit of cleanup in md5 model parsing<commit_after>/*
    Copyright 2013 Jesse 'Jeaye' Wilkerson
    See licensing in LICENSE file, or at:
        http://www.opensource.org/licenses/BSD-3-Clause

    File: obj/md5/model.rs
    Author: Jesse 'Jeaye' Wilkerson
    Description:
      Loads, parses, and represents
      the model (as in MVC) side of
      MD5 animated models.
*/

use std::{ io, path, vec, i32 };
use super::{ Joint, Vertex, Triangle, Weight, Mesh };
use math;

struct Model
{
  version: i32,
  num_joints: i32,
  num_meshes: i32,
  is_animated: bool,

  joints: ~[Joint],
  meshes: ~[Mesh],

  //animation: Option<Animation>,

  local_to_world: math::Mat4x4,
}

impl Model
{
  pub fn new(mesh_file: ~str) -> Model
  {
    let mut model = Model
    {
      version: 0,
      num_joints: 0,
      num_meshes: 0,
      is_animated: false,

      joints: ~[],
      meshes: ~[],

      //animation: None,

      local_to_world: math::Mat4x4::new(),
    };

    model.load(mesh_file);

    model
  }

  priv fn load(&mut self, file: ~str) -> bool
  {
    let fior = io::file_reader(&path::Path(file));
    if fior.is_err()
    { error!("Failed to open model file %s", file); return false; }

    /* Clear existing data. */
    self.joints.clear();
    self.meshes.clear();

    let fio = fior.get();
    let mut param;
    macro_rules! read_param
    (
      () =>
      ({
        param = ~""; /* TODO: clear? */
        let mut ch = fio.read_char();
        while ch.is_whitespace() && !fio.eof() /* Find the next word. */
        { ch = fio.read_char(); }

        if !fio.eof()
        {
          param.push_char(ch);
          ch = fio.read_char();
          while !ch.is_whitespace() && !fio.eof() /* Read the next word. */
          { param.push_char(ch); ch = fio.read_char(); }
        }
      });
    )
    macro_rules! read_junk
    (() => ({ read_param!(); });)
    macro_rules! ignore_line
    (() => ({ fio.read_line(); });)
    macro_rules! read_type
    (
      ($var:expr) =>
      ({
        let name = param.clone();
        read_param!();
        let num = FromStr::from_str(param);
        if num.is_some()
        { $var = num.get(); }
        else
        { error!("Invalid %s in %s", name, file); }
      });
    )

    /* Read the first param and jump into the parsing. */
    read_param!();
    while !fio.eof()
    {
      match param
      {
        ~"MD5Version" =>
        {
          /* Read version. */
          read_type!(self.version);
          debug!("Model version: %?", self.version);
        }
        ~"commandline" =>
        { ignore_line!(); }
        ~"numJoints" =>
        {
          read_type!(self.num_joints);
          self.joints = vec::with_capacity(self.num_joints as uint);
          debug!("Model joints: %?", self.num_joints);
        }
        ~"numMeshes" =>
        {
          read_type!(self.num_meshes);
          self.meshes = vec::with_capacity(self.num_meshes as uint);
          debug!("Model meshes: %?", self.num_meshes);
        }
        ~"joints" =>
        {
          let mut joint = Joint::new();
          read_junk!();
          debug!("Reading model joints");

          for i32::range(0, self.num_joints) |_|
          {
            read_param!();
            joint.name = param.clone();

            read_type!(joint.parent);

            read_junk!();
            read_type!(joint.position.x);
            read_type!(joint.position.y);
            read_type!(joint.position.z);
            read_junk!();
            read_junk!();
            read_type!(joint.orientation.x);
            read_type!(joint.orientation.y);
            read_type!(joint.orientation.z);
            read_junk!();

            joint.orientation.compute_w();
            self.joints.push(joint.clone());

            /* Ignore the rest of the line. */
            ignore_line!();
          }

          read_junk!();
        }
        ~"mesh" =>
        {
          let mut mesh = Mesh::new();
          let mut vert = Vertex::new();
          let mut tri = Triangle::new();
          let mut weight = Weight::new();
          let mut num_verts = 0;
          let mut num_tris = 0;
          let mut num_weights = 0;

          debug!("Parsing mesh");

          read_junk!();
          read_param!();
          while param != ~"}"
          {
            match param
            {
              ~"shader" => /* shader == texture path */
              {
                read_param!();
                mesh.texture = param.clone();
                debug!("Mesh shader: %s", mesh.texture);

                /* TODO: Load texture. */

                ignore_line!();
              }
              ~"numverts" =>
              {
                read_type!(num_verts);
                ignore_line!();

                debug!("Mesh verts: %?", num_verts);

                for i32::range(0, num_verts) |_|
                {
                  read_junk!();
                  read_junk!();
                  read_junk!();
                  read_type!(vert.tex_coord.x);
                  read_type!(vert.tex_coord.y);
                  read_junk!();
                  read_type!(vert.start_weight);
                  read_type!(vert.weight_count);

                  ignore_line!();

                  mesh.verts.push(vert);
                  mesh.tex_coords.push(vert.tex_coord);
                }
              }
              ~"numtris" =>
              {
                read_type!(num_tris);
                ignore_line!();
                debug!("Mesh tris: %?", num_tris);

                for i32::range(0, num_tris) |_|
                {
                  read_junk!();
                  read_junk!();
                  read_type!(tri.indices[0]);
                  read_type!(tri.indices[1]);
                  read_type!(tri.indices[2]);

                  ignore_line!();

                  mesh.triangles.push(tri);
                  mesh.indices.push(tri.indices[0] as u32);
                  mesh.indices.push(tri.indices[1] as u32);
                  mesh.indices.push(tri.indices[2] as u32);
                }
              }
              ~"numweights" =>
              {
                read_type!(num_weights);
                ignore_line!();
                debug!("Mesh weights: %?", num_weights);

                for i32::range(0, num_weights) |_|
                {
                  read_junk!();
                  read_junk!();
                  read_type!(weight.joint_id);
                  read_type!(weight.bias);
                  read_junk!();
                  read_type!(weight.position.x);
                  read_type!(weight.position.y);
                  read_type!(weight.position.z);
                  read_junk!();

                  ignore_line!();
                  mesh.weights.push(weight);
                }
              }
              _ =>
              { ignore_line!(); }
            }

            read_param!();
          }

          self.prepare_mesh(&mut mesh);
          self.meshes.push(mesh);
        }
        _ => { }
      }

      /* Move to the next param. */
      read_param!();
    }

    true
  }

  priv fn prepare_mesh(&mut self, mesh: &mut Mesh)
  {
    mesh.positions.clear();
    mesh.tex_coords.clear();

    for i32::range(0, mesh.verts.len() as i32) |x|
    {
      let vert = &mut mesh.verts[x];
      vert.position = math::Vec3f::zero();
      vert.normal = math::Vec3f::zero();

      /* Sum the position of all the weights. */
      for i32::range(0, vert.weight_count) |w|
      {
        let weight = &mut mesh.weights[vert.start_weight + w];
        let joint = &mut self.joints[weight.joint_id];

        /* Convert the weight position from joint local to object space. */
        let rot_pos = joint.orientation.translate_vec(&weight.position);

        vert.position = vert.position + (joint.position + rot_pos) * weight.bias;
      }

      mesh.positions.push(vert.position);
      mesh.tex_coords.push(vert.tex_coord);
    }
  }
}

<|endoftext|>