<commit_before>// std imports

// srmat imports

use matrix::{MatrixF64, MatrixType, MinMaxAbs, ERO};
use linalg::error::*;

/// A Gauss elimination problem specification
pub struct GaussElimination<'a, 'b>{
    /// The matrix A of AX = B
    pub a : &'a MatrixF64,
    /// The matrix B of AX = B
    pub b : &'b MatrixF64
}

#[doc="Implements the Gauss elimination algorithm
for solving the linear system AX = B.
"]
impl<'a, 'b> GaussElimination<'a, 'b>{

    /// Setup of a new Gauss elimination problem.
    pub fn new(a : &'a MatrixF64, b : &'b MatrixF64) -> GaussElimination<'a, 'b>{
        assert!(a.is_square());
        assert_eq!(a.num_rows(), b.num_rows());
        GaussElimination{a : a , b : b}
    }

    /// Carries out the procedure of Gauss elimination.
    pub fn solve(&self) -> Result<MatrixF64,LinearSystemError> {
        let mut m = self.a.clone();
        m.append_columns(self.b);
        let rows = m.num_rows();
        let cols = m.num_cols();
        // a vector to hold the positions
        //let mut v  = from_range_uint(rows, 1, 0, rows);
        // Forward elimination process.
        for k in range(0, rows){
            // We are working on k-th column.
            let rr = {
                // Create a view of the remaining elements in column
                let col_k_remaining = m.view(k, k, rows - k, 1);
                //println!("k={}, col_k_remaining: {}", k, col_k_remaining);
                // find the maximum value in this view
                let (_, rr, _) = col_k_remaining.max_abs_scalar();
                // translate rr to the overall row number
                rr + k
            };
            if rr > k {
                // We need to exchange rows of the submatrix.
                m.ero_switch(k, rr);
                // Lets keep this position change information in record
                //v.ero_switch(k, rr);
            }
            // Pick up the pivot
            let pivot = m.get(k, k);
            let mut lower_right  = m.view(k + 1, k, rows - k - 1, cols -k);
            //println!("Pivot: {}", pivot);
            //println!("lower_right: {}", lower_right);
            for r in range(0, lower_right.num_rows()){
                let first = lower_right.get(r, 0);
                let factor = first  / pivot;
                lower_right.ero_scale_add(r, -1, -factor);
            }
            //println!("m: {}", m);
        }
        // Backward substitution starts now.
        let mut b = m.view(0, self.a.num_cols(),
            self.b.num_rows(),
            self.b.num_cols());
        let mut r = m.num_rows() - 1;
        loop {
            let pivot = m.get(r, r);
            if pivot == 0. {
                // We have a problem here. We cannot find a solution.
                // TODO: make it more robust for under-determined systems.
                return Err(NoSolution);
            }
            b.ero_scale(r, 1.0/pivot);
            for j in range(r+1, m.num_rows()){
                let factor = m.get(r, j) / pivot;
                b.ero_scale_add(r, j as int, -factor);
            }
            if r == 0 {
                break;
            }
            r -= 1;
        }
        //println!("m: {}", m);
        // We extract the result.
        Ok(b.to_matrix())
    }

}

#[doc="Implements the back substitution algorithm for
solving a upper triangular linear system. L X = B
"]pub fn ut_back_substitute(l : &MatrixF64, b : &MatrixF64) ->
    Result<MatrixF64, LinearSystemError>{
    assert_eq!(l.num_rows(), b.num_rows());
    assert!(l.is_square());
    debug_assert!(l.is_ut());
    // Create a copy for the result
    let mut b = b.clone();
    let mut r = l.num_rows() - 1;
    loop {
        let pivot = l.get(r, r);
        if pivot == 0. {
            // We have a problem here. We cannot find a solution.
            // TODO: make it more robust for under-determined systems.
            return Err(NoSolution);
        }
        b.ero_scale(r, 1.0/pivot);
        for j in range(r+1, l.num_rows()){
            let factor = l.get(r, j) / pivot;
            b.ero_scale_add(r, j as int, -factor);
        }
        if r == 0 {
            break;
        }
        r -= 1;
    }
    Ok(b)
}

/// Validates the solution of linear system
pub struct LinearSystemValidator<'a, 'b, 'c>{
    /// The matrix A of AX = B
    pub a : &'a MatrixF64,
    /// The matrix X of AX = B
    pub x : &'b MatrixF64,
    /// The matrix B of AX = B
    pub b : &'c MatrixF64,
    /// The difference matrix
    pub d : MatrixF64
}

impl<'a, 'b, 'c> LinearSystemValidator<'a, 'b, 'c>{

    /// Setup of a new Gauss elimination problem.
    pub fn new(a : &'a MatrixF64,
        x : &'b MatrixF64,
        b : &'c MatrixF64,
        ) -> LinearSystemValidator<'a, 'b, 'c>{
        assert_eq!(a.num_rows(), b.num_rows());
        LinearSystemValidator{a : a ,
            x : x,
            b : b,
            d : *a * *x - *b}
    }

    pub fn max_abs_scalar_value(&self)-> f64{
        self.d.max_abs_scalar_value()
    }

    /// Validates the equality Ax = b subject to maximum
    /// absolute error being less than a specified threshold.
    pub fn is_max_abs_val_below_threshold(&self, threshold: f64)-> bool{
        self.max_abs_scalar_value() < threshold
    }

    /// Printing for debugging
    pub fn print(&self){
        println!("a: {}", self.a);
        println!("x: {}", self.x);
        println!("ax: {}", self.a * *(self.x));
        println!("b: {}", self.b);
        println!("diff: {}", self.d);
        println!("max abs diff: {}", self.max_abs_scalar_value());
    }
}

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

    #[test]
    fn test_ge_0(){
        let a = matrix_cw_f64(2,2, [1., 4., 2., 5.]);
        println!("{}", a);
        let b = vector_f64([3.0, 6.0]);
        let x = GaussElimination::new(&a, &b).solve().unwrap();
        println!("{}", x);
        assert_eq!(x, vector_f64([-1., 2.]));
        let lsv = LinearSystemValidator::new(&a, &x, &b);
        assert!(lsv.is_max_abs_val_below_threshold(1e-6));
    }

    #[test]
    fn test_ge_1(){
        let mut a = from_range_cw(3, 3, 1.0, 100.0);
        let x = from_range_cw(3, 1, 1.0, 100.0);
        // a above is rank-2.
        a.set(2,2, 11.0);
        let b  = a * x;
        println!("A: {}", a);
        println!("x: {}", x);
        println!("b: {}", b);
        let ge = GaussElimination::new(&a, &b);
        let z = ge.solve().unwrap();
        println!("z: {}", z);
        /*
        TODO: have better understanding of
        the roundoff error.
        In this case, it is greater than
        1e-15.
        */
        let lsv = LinearSystemValidator::new(&a, &x, &b);
        assert!(lsv.is_max_abs_val_below_threshold(1e-6));
    }

    #[test]
    fn test_ge_2(){
        let a = matrix_cw_f64(3,3, [1., 0., 0.,
            -1., 1., 0.,
            1., 1., 1.]);
        let b = vector_f64([1., 1., 1.]);
        let ge = GaussElimination::new(&a, &b);
        let x  = ge.solve().unwrap();
        println!("a: {}, x: {}, b: {}", a, x, b);
        // answer is [0, 0, 1]
        let lsv = LinearSystemValidator::new(&a, &x, &b);
        assert!(lsv.is_max_abs_val_below_threshold(1e-6));
    }

    #[test]
    fn test_ge_3(){
        let a = matrix_cw_f64(3,3, [2., 4., -2.,
            1., -6., 7.,
            1., 0., 2.]);
        let b = vector_f64([5., -2., 9.]);
        let ge = GaussElimination::new(&a, &b);
        let x  = ge.solve().unwrap();
        println!("a: {}, x: {}, b: {}", a, x, b);
        // answer is [1, 1, 2]
        //assert!(false);
        let lsv = LinearSystemValidator::new(&a, &x, &b);
        assert!(lsv.is_max_abs_val_below_threshold(1e-6));
    }

    #[test]
    fn test_ge_no_solution(){
        let a = matrix_cw_f64(2,2, [1., 4., 2., 8.]);
        println!("{}", a);
        let b = vector_f64([3.0, 6.0]);
        let result = GaussElimination::new(&a, &b).solve();
        match result {
            Ok(x) => {
                println!("{}", x);
                assert!(false);
            },
            Err(e) => println!("{}", e),
        }

    }

    #[test]
    fn test_lt_0(){
        let l = matrix_rw_f64(2, 2, [
            1., 1.,
            0., 1.]);
        let x = vector_f64([1., 2.]);
        let b = l * x;
        let x = ut_back_substitute(&l, &b).unwrap();
        let lsv = LinearSystemValidator::new(&l, &x, &b);
        lsv.print();
        assert!(lsv.is_max_abs_val_below_threshold(1e-6));
    }

}
<commit_msg>support for solving lower triangular system by forward substitution.<commit_after>// std imports

// srmat imports

use matrix::{MatrixF64, MatrixType, MinMaxAbs, ERO};
use linalg::error::*;

/// A Gauss elimination problem specification
pub struct GaussElimination<'a, 'b>{
    /// The matrix A of AX = B
    pub a : &'a MatrixF64,
    /// The matrix B of AX = B
    pub b : &'b MatrixF64
}

#[doc="Implements the Gauss elimination algorithm
for solving the linear system AX = B.
"]
impl<'a, 'b> GaussElimination<'a, 'b>{

    /// Setup of a new Gauss elimination problem.
    pub fn new(a : &'a MatrixF64, b : &'b MatrixF64) -> GaussElimination<'a, 'b>{
        assert!(a.is_square());
        assert_eq!(a.num_rows(), b.num_rows());
        GaussElimination{a : a , b : b}
    }

    /// Carries out the procedure of Gauss elimination.
    pub fn solve(&self) -> Result<MatrixF64,LinearSystemError> {
        let mut m = self.a.clone();
        m.append_columns(self.b);
        let rows = m.num_rows();
        let cols = m.num_cols();
        // a vector to hold the positions
        //let mut v  = from_range_uint(rows, 1, 0, rows);
        // Forward elimination process.
        for k in range(0, rows){
            // We are working on k-th column.
            let rr = {
                // Create a view of the remaining elements in column
                let col_k_remaining = m.view(k, k, rows - k, 1);
                //println!("k={}, col_k_remaining: {}", k, col_k_remaining);
                // find the maximum value in this view
                let (_, rr, _) = col_k_remaining.max_abs_scalar();
                // translate rr to the overall row number
                rr + k
            };
            if rr > k {
                // We need to exchange rows of the submatrix.
                m.ero_switch(k, rr);
                // Lets keep this position change information in record
                //v.ero_switch(k, rr);
            }
            // Pick up the pivot
            let pivot = m.get(k, k);
            let mut lower_right  = m.view(k + 1, k, rows - k - 1, cols -k);
            //println!("Pivot: {}", pivot);
            //println!("lower_right: {}", lower_right);
            for r in range(0, lower_right.num_rows()){
                let first = lower_right.get(r, 0);
                let factor = first  / pivot;
                lower_right.ero_scale_add(r, -1, -factor);
            }
            //println!("m: {}", m);
        }
        // Backward substitution starts now.
        let mut b = m.view(0, self.a.num_cols(),
            self.b.num_rows(),
            self.b.num_cols());
        let mut r = m.num_rows() - 1;
        loop {
            let pivot = m.get(r, r);
            if pivot == 0. {
                // We have a problem here. We cannot find a solution.
                // TODO: make it more robust for under-determined systems.
                return Err(NoSolution);
            }
            b.ero_scale(r, 1.0/pivot);
            for j in range(r+1, m.num_rows()){
                let factor = m.get(r, j) / pivot;
                b.ero_scale_add(r, j as int, -factor);
            }
            if r == 0 {
                break;
            }
            r -= 1;
        }
        //println!("m: {}", m);
        // We extract the result.
        Ok(b.to_matrix())
    }

}

#[doc="Implements the forward substitution algorithm for
solving a lower triangular linear system. L X = B
"]pub fn lt_solve(l : &MatrixF64, b : &MatrixF64) ->
    Result<MatrixF64, LinearSystemError>{
    assert!(l.is_square());
    let n = l.num_rows();
    assert_eq!(n, b.num_rows());
    debug_assert!(l.is_lt());
    // Create a copy for the result
    let mut b = b.clone();
    for r in range(0, n) {
        let pivot = l.get(r, r);
        if pivot == 0. {
            // We have a problem here. We cannot find a solution.
            // TODO: make it more robust for under-determined systems.
            return Err(NoSolution);
        }
        for k in range(0,  r){
            b.ero_scale_add(r, k as int, -l.get(r, k));
        }
        b.ero_scale(r, 1.0/pivot);
    }
    Ok(b)
}

#[doc="Implements the back substitution algorithm for
solving a upper triangular linear system. L X = B
"]pub fn ut_solve(u : &MatrixF64, b : &MatrixF64) ->
    Result<MatrixF64, LinearSystemError>{
    assert_eq!(u.num_rows(), b.num_rows());
    assert!(u.is_square());
    debug_assert!(u.is_ut());
    // Create a copy for the result
    let mut b = b.clone();
    let mut r = u.num_rows() - 1;
    loop {
        let pivot = u.get(r, r);
        if pivot == 0. {
            // We have a problem here. We cannot find a solution.
            // TODO: make it more robust for under-determined systems.
            return Err(NoSolution);
        }
        b.ero_scale(r, 1.0/pivot);
        for j in range(r+1, u.num_rows()){
            let factor = u.get(r, j) / pivot;
            b.ero_scale_add(r, j as int, -factor);
        }
        if r == 0 {
            break;
        }
        r -= 1;
    }
    Ok(b)
}

/// Validates the solution of linear system
pub struct LinearSystemValidator<'a, 'b, 'c>{
    /// The matrix A of AX = B
    pub a : &'a MatrixF64,
    /// The matrix X of AX = B
    pub x : &'b MatrixF64,
    /// The matrix B of AX = B
    pub b : &'c MatrixF64,
    /// The difference matrix
    pub d : MatrixF64
}

impl<'a, 'b, 'c> LinearSystemValidator<'a, 'b, 'c>{

    /// Setup of a new Gauss elimination problem.
    pub fn new(a : &'a MatrixF64,
        x : &'b MatrixF64,
        b : &'c MatrixF64,
        ) -> LinearSystemValidator<'a, 'b, 'c>{
        assert_eq!(a.num_rows(), b.num_rows());
        LinearSystemValidator{a : a ,
            x : x,
            b : b,
            d : *a * *x - *b}
    }

    pub fn max_abs_scalar_value(&self)-> f64{
        self.d.max_abs_scalar_value()
    }

    /// Validates the equality Ax = b subject to maximum
    /// absolute error being less than a specified threshold.
    pub fn is_max_abs_val_below_threshold(&self, threshold: f64)-> bool{
        self.max_abs_scalar_value() < threshold
    }

    /// Printing for debugging
    pub fn print(&self){
        println!("a: {}", self.a);
        println!("x: {}", self.x);
        println!("ax: {}", self.a * *(self.x));
        println!("b: {}", self.b);
        println!("diff: {}", self.d);
        println!("max abs diff: {}", self.max_abs_scalar_value());
    }
}

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

    #[test]
    fn test_ge_0(){
        let a = matrix_cw_f64(2,2, [1., 4., 2., 5.]);
        println!("{}", a);
        let b = vector_f64([3.0, 6.0]);
        let x = GaussElimination::new(&a, &b).solve().unwrap();
        println!("{}", x);
        assert_eq!(x, vector_f64([-1., 2.]));
        let lsv = LinearSystemValidator::new(&a, &x, &b);
        assert!(lsv.is_max_abs_val_below_threshold(1e-6));
    }

    #[test]
    fn test_ge_1(){
        let mut a = from_range_cw(3, 3, 1.0, 100.0);
        let x = from_range_cw(3, 1, 1.0, 100.0);
        // a above is rank-2.
        a.set(2,2, 11.0);
        let b  = a * x;
        println!("A: {}", a);
        println!("x: {}", x);
        println!("b: {}", b);
        let ge = GaussElimination::new(&a, &b);
        let z = ge.solve().unwrap();
        println!("z: {}", z);
        /*
        TODO: have better understanding of
        the roundoff error.
        In this case, it is greater than
        1e-15.
        */
        let lsv = LinearSystemValidator::new(&a, &x, &b);
        assert!(lsv.is_max_abs_val_below_threshold(1e-6));
    }

    #[test]
    fn test_ge_2(){
        let a = matrix_cw_f64(3,3, [1., 0., 0.,
            -1., 1., 0.,
            1., 1., 1.]);
        let b = vector_f64([1., 1., 1.]);
        let ge = GaussElimination::new(&a, &b);
        let x  = ge.solve().unwrap();
        println!("a: {}, x: {}, b: {}", a, x, b);
        // answer is [0, 0, 1]
        let lsv = LinearSystemValidator::new(&a, &x, &b);
        assert!(lsv.is_max_abs_val_below_threshold(1e-6));
    }

    #[test]
    fn test_ge_3(){
        let a = matrix_cw_f64(3,3, [2., 4., -2.,
            1., -6., 7.,
            1., 0., 2.]);
        let b = vector_f64([5., -2., 9.]);
        let ge = GaussElimination::new(&a, &b);
        let x  = ge.solve().unwrap();
        println!("a: {}, x: {}, b: {}", a, x, b);
        // answer is [1, 1, 2]
        //assert!(false);
        let lsv = LinearSystemValidator::new(&a, &x, &b);
        assert!(lsv.is_max_abs_val_below_threshold(1e-6));
    }

    #[test]
    fn test_ge_no_solution(){
        let a = matrix_cw_f64(2,2, [1., 4., 2., 8.]);
        println!("{}", a);
        let b = vector_f64([3.0, 6.0]);
        let result = GaussElimination::new(&a, &b).solve();
        match result {
            Ok(x) => {
                println!("{}", x);
                assert!(false);
            },
            Err(e) => println!("{}", e),
        }

    }

    #[test]
    fn test_ut_0(){
        let l = matrix_rw_f64(2, 2, [
            1., 1.,
            0., 1.]);
        let x = vector_f64([1., 2.]);
        let b = l * x;
        let x = ut_solve(&l, &b).unwrap();
        let lsv = LinearSystemValidator::new(&l, &x, &b);
        lsv.print();
        assert!(lsv.is_max_abs_val_below_threshold(1e-6));
    }

    #[test]
    fn test_lt_0(){
        let l = matrix_rw_f64(2, 2, [
            1., 0.,
            1., 1.]);
        let x = vector_f64([1., 2.]);
        let b = l * x;
        let x = lt_solve(&l, &b).unwrap();
        let lsv = LinearSystemValidator::new(&l, &x, &b);
        lsv.print();
        assert!(lsv.is_max_abs_val_below_threshold(1e-6));
    }

}
<|endoftext|>


<commit_before>use crate::Error;
use serde_derive::{Deserialize, Serialize};
use std::marker::PhantomData;
use std::ops::{Deref, Index, IndexMut};
use std::slice::SliceIndex;
use typenum::Unsigned;

pub use typenum;

/// Emulates a SSZ `List`.
///
/// An ordered, heap-allocated, variable-length, homogeneous collection of `T`, with no more than
/// `N` values.
///
/// This struct is backed by a Rust `Vec` but constrained such that it must be instantiated with a
/// fixed number of elements and you may not add or remove elements, only modify.
///
/// The length of this struct is fixed at the type-level using
/// [typenum](https://crates.io/crates/typenum).
///
/// ## Example
///
/// ```
/// use ssz_types::{VariableList, typenum};
///
/// let base: Vec<u64> = vec![1, 2, 3, 4];
///
/// // Create a `VariableList` from a `Vec` that has the expected length.
/// let exact: VariableList<_, typenum::U4> = VariableList::from(base.clone());
/// assert_eq!(&exact[..], &[1, 2, 3, 4]);
///
/// // Create a `VariableList` from a `Vec` that is too long and the `Vec` is truncated.
/// let short: VariableList<_, typenum::U3> = VariableList::from(base.clone());
/// assert_eq!(&short[..], &[1, 2, 3]);
///
/// // Create a `VariableList` from a `Vec` that is shorter than the maximum.
/// let mut long: VariableList<_, typenum::U5> = VariableList::from(base);
/// assert_eq!(&long[..], &[1, 2, 3, 4]);
///
/// // Push a value to if it does not exceed the maximum
/// long.push(5).unwrap();
/// assert_eq!(&long[..], &[1, 2, 3, 4, 5]);
///
/// // Push a value to if it _does_ exceed the maximum.
/// assert!(long.push(6).is_err());
/// ```
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(transparent)]
pub struct VariableList<T, N> {
    vec: Vec<T>,
    _phantom: PhantomData<N>,
}

impl<T, N: Unsigned> VariableList<T, N> {
    /// Returns `Some` if the given `vec` equals the fixed length of `Self`. Otherwise returns
    /// `None`.
    pub fn new(vec: Vec<T>) -> Result<Self, Error> {
        if vec.len() <= N::to_usize() {
            Ok(Self {
                vec,
                _phantom: PhantomData,
            })
        } else {
            Err(Error::InvalidLength {
                i: vec.len(),
                len: Self::max_len(),
            })
        }
    }

    /// Returns the number of values presently in `self`.
    pub fn len(&self) -> usize {
        self.vec.len()
    }

    /// True if `self` does not contain any values.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns the type-level maximum length.
    pub fn max_len() -> usize {
        N::to_usize()
    }

    /// Appends `value` to the back of `self`.
    ///
    /// Returns `Err(())` when appending `value` would exceed the maximum length.
    pub fn push(&mut self, value: T) -> Result<(), Error> {
        if self.vec.len() < Self::max_len() {
            self.vec.push(value);
            Ok(())
        } else {
            Err(Error::InvalidLength {
                i: self.vec.len() + 1,
                len: Self::max_len(),
            })
        }
    }
}

impl<T: Default, N: Unsigned> From<Vec<T>> for VariableList<T, N> {
    fn from(mut vec: Vec<T>) -> Self {
        vec.truncate(N::to_usize());

        Self {
            vec,
            _phantom: PhantomData,
        }
    }
}

impl<T, N: Unsigned> Into<Vec<T>> for VariableList<T, N> {
    fn into(self) -> Vec<T> {
        self.vec
    }
}

impl<T, N: Unsigned> Default for VariableList<T, N> {
    fn default() -> Self {
        Self {
            vec: Vec::default(),
            _phantom: PhantomData,
        }
    }
}

impl<T, N: Unsigned, I: SliceIndex<[T]>> Index<I> for VariableList<T, N> {
    type Output = I::Output;

    #[inline]
    fn index(&self, index: I) -> &Self::Output {
        Index::index(&self.vec, index)
    }
}

impl<T, N: Unsigned, I: SliceIndex<[T]>> IndexMut<I> for VariableList<T, N> {
    #[inline]
    fn index_mut(&mut self, index: I) -> &mut Self::Output {
        IndexMut::index_mut(&mut self.vec, index)
    }
}

impl<T, N: Unsigned> Deref for VariableList<T, N> {
    type Target = [T];

    fn deref(&self) -> &[T] {
        &self.vec[..]
    }
}

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

    #[test]
    fn new() {
        let vec = vec![42; 5];
        let fixed: Result<VariableList<u64, U4>, _> = VariableList::new(vec.clone());
        assert!(fixed.is_err());

        let vec = vec![42; 3];
        let fixed: Result<VariableList<u64, U4>, _> = VariableList::new(vec.clone());
        assert!(fixed.is_ok());

        let vec = vec![42; 4];
        let fixed: Result<VariableList<u64, U4>, _> = VariableList::new(vec.clone());
        assert!(fixed.is_ok());
    }

    #[test]
    fn indexing() {
        let vec = vec![1, 2];

        let mut fixed: VariableList<u64, U8192> = vec.clone().into();

        assert_eq!(fixed[0], 1);
        assert_eq!(&fixed[0..1], &vec[0..1]);
        assert_eq!((&fixed[..]).len(), 2);

        fixed[1] = 3;
        assert_eq!(fixed[1], 3);
    }

    #[test]
    fn length() {
        let vec = vec![42; 5];
        let fixed: VariableList<u64, U4> = VariableList::from(vec.clone());
        assert_eq!(&fixed[..], &vec[0..4]);

        let vec = vec![42; 3];
        let fixed: VariableList<u64, U4> = VariableList::from(vec.clone());
        assert_eq!(&fixed[0..3], &vec[..]);
        assert_eq!(&fixed[..], &vec![42, 42, 42][..]);

        let vec = vec![];
        let fixed: VariableList<u64, U4> = VariableList::from(vec.clone());
        assert_eq!(&fixed[..], &vec![][..]);
    }

    #[test]
    fn deref() {
        let vec = vec![0, 2, 4, 6];
        let fixed: VariableList<u64, U4> = VariableList::from(vec);

        assert_eq!(fixed.get(0), Some(&0));
        assert_eq!(fixed.get(3), Some(&6));
        assert_eq!(fixed.get(4), None);
    }
}

/*
impl<T, N: Unsigned> tree_hash::TreeHash for VariableList<T, N>
where
    T: tree_hash::TreeHash,
{
    fn tree_hash_type() -> tree_hash::TreeHashType {
        tree_hash::TreeHashType::Vector
    }

    fn tree_hash_packed_encoding(&self) -> Vec<u8> {
        unreachable!("Vector should never be packed.")
    }

    fn tree_hash_packing_factor() -> usize {
        unreachable!("Vector should never be packed.")
    }

    fn tree_hash_root(&self) -> Vec<u8> {
        tree_hash::impls::vec_tree_hash_root(&self.vec)
    }
}

impl<T, N: Unsigned> cached_tree_hash::CachedTreeHash for VariableList<T, N>
where
    T: cached_tree_hash::CachedTreeHash + tree_hash::TreeHash,
{
    fn new_tree_hash_cache(
        &self,
        depth: usize,
    ) -> Result<cached_tree_hash::TreeHashCache, cached_tree_hash::Error> {
        let (cache, _overlay) = cached_tree_hash::vec::new_tree_hash_cache(&self.vec, depth)?;

        Ok(cache)
    }

    fn tree_hash_cache_schema(&self, depth: usize) -> cached_tree_hash::BTreeSchema {
        cached_tree_hash::vec::produce_schema(&self.vec, depth)
    }

    fn update_tree_hash_cache(
        &self,
        cache: &mut cached_tree_hash::TreeHashCache,
    ) -> Result<(), cached_tree_hash::Error> {
        cached_tree_hash::vec::update_tree_hash_cache(&self.vec, cache)?;

        Ok(())
    }
}
*/

impl<T, N: Unsigned> ssz::Encode for VariableList<T, N>
where
    T: ssz::Encode,
{
    fn is_ssz_fixed_len() -> bool {
        <Vec<T>>::is_ssz_fixed_len()
    }

    fn ssz_fixed_len() -> usize {
        <Vec<T>>::ssz_fixed_len()
    }

    fn ssz_append(&self, buf: &mut Vec<u8>) {
        self.vec.ssz_append(buf)
    }
}

impl<T, N: Unsigned> ssz::Decode for VariableList<T, N>
where
    T: ssz::Decode + Default,
{
    fn is_ssz_fixed_len() -> bool {
        <Vec<T>>::is_ssz_fixed_len()
    }

    fn ssz_fixed_len() -> usize {
        <Vec<T>>::ssz_fixed_len()
    }

    fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> {
        let vec = <Vec<T>>::from_ssz_bytes(bytes)?;

        Self::new(vec).map_err(|e| ssz::DecodeError::BytesInvalid(format!("VariableList {:?}", e)))
    }
}

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

    #[test]
    fn encode() {
        let vec: VariableList<u16, U2> = vec![0; 2].into();
        assert_eq!(vec.as_ssz_bytes(), vec![0, 0, 0, 0]);
        assert_eq!(<VariableList<u16, U2> as Encode>::ssz_fixed_len(), 4);
    }

    fn round_trip<T: Encode + Decode + std::fmt::Debug + PartialEq>(item: T) {
        let encoded = &item.as_ssz_bytes();
        assert_eq!(T::from_ssz_bytes(&encoded), Ok(item));
    }

    #[test]
    fn u16_len_8() {
        round_trip::<VariableList<u16, U8>>(vec![42; 8].into());
        round_trip::<VariableList<u16, U8>>(vec![0; 8].into());
    }
}
<commit_msg>Uncomment broken tree hash impl for variable list<commit_after>use crate::Error;
use serde_derive::{Deserialize, Serialize};
use std::marker::PhantomData;
use std::ops::{Deref, Index, IndexMut};
use std::slice::SliceIndex;
use typenum::Unsigned;

pub use typenum;

/// Emulates a SSZ `List`.
///
/// An ordered, heap-allocated, variable-length, homogeneous collection of `T`, with no more than
/// `N` values.
///
/// This struct is backed by a Rust `Vec` but constrained such that it must be instantiated with a
/// fixed number of elements and you may not add or remove elements, only modify.
///
/// The length of this struct is fixed at the type-level using
/// [typenum](https://crates.io/crates/typenum).
///
/// ## Example
///
/// ```
/// use ssz_types::{VariableList, typenum};
///
/// let base: Vec<u64> = vec![1, 2, 3, 4];
///
/// // Create a `VariableList` from a `Vec` that has the expected length.
/// let exact: VariableList<_, typenum::U4> = VariableList::from(base.clone());
/// assert_eq!(&exact[..], &[1, 2, 3, 4]);
///
/// // Create a `VariableList` from a `Vec` that is too long and the `Vec` is truncated.
/// let short: VariableList<_, typenum::U3> = VariableList::from(base.clone());
/// assert_eq!(&short[..], &[1, 2, 3]);
///
/// // Create a `VariableList` from a `Vec` that is shorter than the maximum.
/// let mut long: VariableList<_, typenum::U5> = VariableList::from(base);
/// assert_eq!(&long[..], &[1, 2, 3, 4]);
///
/// // Push a value to if it does not exceed the maximum
/// long.push(5).unwrap();
/// assert_eq!(&long[..], &[1, 2, 3, 4, 5]);
///
/// // Push a value to if it _does_ exceed the maximum.
/// assert!(long.push(6).is_err());
/// ```
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(transparent)]
pub struct VariableList<T, N> {
    vec: Vec<T>,
    _phantom: PhantomData<N>,
}

impl<T, N: Unsigned> VariableList<T, N> {
    /// Returns `Some` if the given `vec` equals the fixed length of `Self`. Otherwise returns
    /// `None`.
    pub fn new(vec: Vec<T>) -> Result<Self, Error> {
        if vec.len() <= N::to_usize() {
            Ok(Self {
                vec,
                _phantom: PhantomData,
            })
        } else {
            Err(Error::InvalidLength {
                i: vec.len(),
                len: Self::max_len(),
            })
        }
    }

    /// Returns the number of values presently in `self`.
    pub fn len(&self) -> usize {
        self.vec.len()
    }

    /// True if `self` does not contain any values.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns the type-level maximum length.
    pub fn max_len() -> usize {
        N::to_usize()
    }

    /// Appends `value` to the back of `self`.
    ///
    /// Returns `Err(())` when appending `value` would exceed the maximum length.
    pub fn push(&mut self, value: T) -> Result<(), Error> {
        if self.vec.len() < Self::max_len() {
            self.vec.push(value);
            Ok(())
        } else {
            Err(Error::InvalidLength {
                i: self.vec.len() + 1,
                len: Self::max_len(),
            })
        }
    }
}

impl<T: Default, N: Unsigned> From<Vec<T>> for VariableList<T, N> {
    fn from(mut vec: Vec<T>) -> Self {
        vec.truncate(N::to_usize());

        Self {
            vec,
            _phantom: PhantomData,
        }
    }
}

impl<T, N: Unsigned> Into<Vec<T>> for VariableList<T, N> {
    fn into(self) -> Vec<T> {
        self.vec
    }
}

impl<T, N: Unsigned> Default for VariableList<T, N> {
    fn default() -> Self {
        Self {
            vec: Vec::default(),
            _phantom: PhantomData,
        }
    }
}

impl<T, N: Unsigned, I: SliceIndex<[T]>> Index<I> for VariableList<T, N> {
    type Output = I::Output;

    #[inline]
    fn index(&self, index: I) -> &Self::Output {
        Index::index(&self.vec, index)
    }
}

impl<T, N: Unsigned, I: SliceIndex<[T]>> IndexMut<I> for VariableList<T, N> {
    #[inline]
    fn index_mut(&mut self, index: I) -> &mut Self::Output {
        IndexMut::index_mut(&mut self.vec, index)
    }
}

impl<T, N: Unsigned> Deref for VariableList<T, N> {
    type Target = [T];

    fn deref(&self) -> &[T] {
        &self.vec[..]
    }
}

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

    #[test]
    fn new() {
        let vec = vec![42; 5];
        let fixed: Result<VariableList<u64, U4>, _> = VariableList::new(vec.clone());
        assert!(fixed.is_err());

        let vec = vec![42; 3];
        let fixed: Result<VariableList<u64, U4>, _> = VariableList::new(vec.clone());
        assert!(fixed.is_ok());

        let vec = vec![42; 4];
        let fixed: Result<VariableList<u64, U4>, _> = VariableList::new(vec.clone());
        assert!(fixed.is_ok());
    }

    #[test]
    fn indexing() {
        let vec = vec![1, 2];

        let mut fixed: VariableList<u64, U8192> = vec.clone().into();

        assert_eq!(fixed[0], 1);
        assert_eq!(&fixed[0..1], &vec[0..1]);
        assert_eq!((&fixed[..]).len(), 2);

        fixed[1] = 3;
        assert_eq!(fixed[1], 3);
    }

    #[test]
    fn length() {
        let vec = vec![42; 5];
        let fixed: VariableList<u64, U4> = VariableList::from(vec.clone());
        assert_eq!(&fixed[..], &vec[0..4]);

        let vec = vec![42; 3];
        let fixed: VariableList<u64, U4> = VariableList::from(vec.clone());
        assert_eq!(&fixed[0..3], &vec[..]);
        assert_eq!(&fixed[..], &vec![42, 42, 42][..]);

        let vec = vec![];
        let fixed: VariableList<u64, U4> = VariableList::from(vec.clone());
        assert_eq!(&fixed[..], &vec![][..]);
    }

    #[test]
    fn deref() {
        let vec = vec![0, 2, 4, 6];
        let fixed: VariableList<u64, U4> = VariableList::from(vec);

        assert_eq!(fixed.get(0), Some(&0));
        assert_eq!(fixed.get(3), Some(&6));
        assert_eq!(fixed.get(4), None);
    }
}

impl<T, N: Unsigned> tree_hash::TreeHash for VariableList<T, N>
where
    T: tree_hash::TreeHash,
{
    fn tree_hash_type() -> tree_hash::TreeHashType {
        tree_hash::TreeHashType::Vector
    }

    fn tree_hash_packed_encoding(&self) -> Vec<u8> {
        unreachable!("Vector should never be packed.")
    }

    fn tree_hash_packing_factor() -> usize {
        unreachable!("Vector should never be packed.")
    }

    fn tree_hash_root(&self) -> Vec<u8> {
        tree_hash::impls::vec_tree_hash_root(&self.vec)
    }
}

impl<T, N: Unsigned> cached_tree_hash::CachedTreeHash for VariableList<T, N>
where
    T: cached_tree_hash::CachedTreeHash + tree_hash::TreeHash,
{
    fn new_tree_hash_cache(
        &self,
        depth: usize,
    ) -> Result<cached_tree_hash::TreeHashCache, cached_tree_hash::Error> {
        let (cache, _overlay) = cached_tree_hash::vec::new_tree_hash_cache(&self.vec, depth)?;

        Ok(cache)
    }

    fn tree_hash_cache_schema(&self, depth: usize) -> cached_tree_hash::BTreeSchema {
        cached_tree_hash::vec::produce_schema(&self.vec, depth)
    }

    fn update_tree_hash_cache(
        &self,
        cache: &mut cached_tree_hash::TreeHashCache,
    ) -> Result<(), cached_tree_hash::Error> {
        cached_tree_hash::vec::update_tree_hash_cache(&self.vec, cache)?;

        Ok(())
    }
}

impl<T, N: Unsigned> ssz::Encode for VariableList<T, N>
where
    T: ssz::Encode,
{
    fn is_ssz_fixed_len() -> bool {
        <Vec<T>>::is_ssz_fixed_len()
    }

    fn ssz_fixed_len() -> usize {
        <Vec<T>>::ssz_fixed_len()
    }

    fn ssz_append(&self, buf: &mut Vec<u8>) {
        self.vec.ssz_append(buf)
    }
}

impl<T, N: Unsigned> ssz::Decode for VariableList<T, N>
where
    T: ssz::Decode + Default,
{
    fn is_ssz_fixed_len() -> bool {
        <Vec<T>>::is_ssz_fixed_len()
    }

    fn ssz_fixed_len() -> usize {
        <Vec<T>>::ssz_fixed_len()
    }

    fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> {
        let vec = <Vec<T>>::from_ssz_bytes(bytes)?;

        Self::new(vec).map_err(|e| ssz::DecodeError::BytesInvalid(format!("VariableList {:?}", e)))
    }
}

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

    #[test]
    fn encode() {
        let vec: VariableList<u16, U2> = vec![0; 2].into();
        assert_eq!(vec.as_ssz_bytes(), vec![0, 0, 0, 0]);
        assert_eq!(<VariableList<u16, U2> as Encode>::ssz_fixed_len(), 4);
    }

    fn round_trip<T: Encode + Decode + std::fmt::Debug + PartialEq>(item: T) {
        let encoded = &item.as_ssz_bytes();
        assert_eq!(T::from_ssz_bytes(&encoded), Ok(item));
    }

    #[test]
    fn u16_len_8() {
        round_trip::<VariableList<u16, U8>>(vec![42; 8].into());
        round_trip::<VariableList<u16, U8>>(vec![0; 8].into());
    }
}
<|endoftext|>


<commit_before>use super::{FFTW_MUTEX, FLAG, R2R_KIND, SIGN, c32, c64};
use super::aligned_vec::AlignedVec;
use ffi;

use std::os::raw::c_void;
use std::ptr::null;

pub enum RawPlan {
    _64(ffi::fftw_plan),
    _32(ffi::fftwf_plan),
}

impl RawPlan {
    pub unsafe fn execute(&self) {
        if self.is_null() {
            panic!("Plan is NULL");
        }
        match *self {
            RawPlan::_64(p) => ffi::fftw_execute(p),
            RawPlan::_32(p) => ffi::fftwf_execute(p),
        }
    }

    pub fn is_null(&self) -> bool {
        let p = match *self {
            RawPlan::_64(p) => p as *const c_void,
            RawPlan::_32(p) => p as *const c_void,
        };
        p == null()
    }
}

impl Drop for RawPlan {
    fn drop(&mut self) {
        if self.is_null() {
            // TODO warning
            return;
        }
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe {
            match *self {
                RawPlan::_64(p) => ffi::fftw_destroy_plan(p),
                RawPlan::_32(p) => ffi::fftwf_destroy_plan(p),
            }
        }
    }
}

pub trait R2R: Sized {
    unsafe fn r2r_1d(n: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, R2R_KIND, FLAG) -> RawPlan;
    unsafe fn r2r_2d(
        n0: usize,
        n1: usize,
        in_: &mut AlignedVec<Self>,
        out: &mut AlignedVec<Self>,
        R2R_KIND,
        R2R_KIND,
        FLAG,
    ) -> RawPlan;
    unsafe fn r2r_3d(
        n0: usize,
        n1: usize,
        n2: usize,
        in_: &mut AlignedVec<Self>,
        out: &mut AlignedVec<Self>,
        R2R_KIND,
        R2R_KIND,
        R2R_KIND,
        FLAG,
    ) -> RawPlan;
}
pub trait C2C: Sized {
    unsafe fn c2c_1d(n: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, SIGN, FLAG) -> RawPlan;
    unsafe fn c2c_2d(
        n0: usize,
        n1: usize,
        in_: &mut AlignedVec<Self>,
        out: &mut AlignedVec<Self>,
        SIGN,
        FLAG,
    ) -> RawPlan;
    unsafe fn c2c_3d(
        n0: usize,
        n1: usize,
        n2: usize,
        in_: &mut AlignedVec<Self>,
        out: &mut AlignedVec<Self>,
        SIGN,
        FLAG,
    ) -> RawPlan;
}

pub trait R2C {
    type Real: Sized;
    type Complex: Sized;
    unsafe fn r2c_1d(n: usize, in_: &mut AlignedVec<Self::Real>, out: &mut AlignedVec<Self::Complex>, FLAG) -> RawPlan;
    unsafe fn c2r_1d(n: usize, in_: &mut AlignedVec<Self::Complex>, out: &mut AlignedVec<Self::Real>, FLAG) -> RawPlan;
    unsafe fn r2c_2d(
        n0: usize,
        n1: usize,
        in_: &mut AlignedVec<Self::Real>,
        out: &mut AlignedVec<Self::Complex>,
        FLAG,
    ) -> RawPlan;
    unsafe fn c2r_2d(
        n0: usize,
        n1: usize,
        in_: &mut AlignedVec<Self::Complex>,
        out: &mut AlignedVec<Self::Real>,
        FLAG,
    ) -> RawPlan;
    unsafe fn r2c_3d(
        n0: usize,
        n1: usize,
        n2: usize,
        in_: &mut AlignedVec<Self::Real>,
        out: &mut AlignedVec<Self::Complex>,
        FLAG,
    ) -> RawPlan;
    unsafe fn c2r_3d(
        n0: usize,
        n1: usize,
        n2: usize,
        in_: &mut AlignedVec<Self::Complex>,
        out: &mut AlignedVec<Self::Real>,
        FLAG,
    ) -> RawPlan;
}

macro_rules! impl_plan_create {
    ($bit:ident, $float:ty, $complex:ty,
     $r2r_1d:ident, $r2c_1d:ident, $c2r_1d:ident, $c2c_1d:ident,
     $r2r_2d:ident, $r2c_2d:ident, $c2r_2d:ident, $c2c_2d:ident,
     $r2r_3d:ident, $r2c_3d:ident, $c2r_3d:ident, $c2c_3d:ident) => {

impl R2R for $float {
    unsafe fn r2r_1d(n: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, kind: R2R_KIND, flag: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2r_1d(n as i32, in_.as_mut_ptr(), out.as_mut_ptr(), kind, flag as u32))
    }
    unsafe fn r2r_2d(n0: usize, n1: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, k0: R2R_KIND, k1: R2R_KIND, flag: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2r_2d(n0 as i32, n1 as i32, in_.as_mut_ptr(), out.as_mut_ptr(), k0, k1, flag as u32))
    }
    unsafe fn r2r_3d(n0: usize, n1: usize, n2: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, k0: R2R_KIND, k1: R2R_KIND, k2: R2R_KIND, flag: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2r_3d(n0 as i32, n1 as i32, n2 as i32, in_.as_mut_ptr(), out.as_mut_ptr(), k0, k1, k2, flag as u32))
    }
}

impl C2C for $complex {
    unsafe fn c2c_1d(n: usize, i: &mut AlignedVec<Self>, o: &mut AlignedVec<Self>, s: SIGN, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2c_1d(n as i32, i.as_mut_ptr(), o.as_mut_ptr(), s as i32, f as u32))
    }
    unsafe fn c2c_2d(n0: usize, n1: usize, i: &mut AlignedVec<Self>, o: &mut AlignedVec<Self>, s: SIGN, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2c_2d(n0 as i32, n1 as i32, i.as_mut_ptr(), o.as_mut_ptr(), s as i32, f as u32))
    }
    unsafe fn c2c_3d(n0: usize, n1: usize, n2: usize, i: &mut AlignedVec<Self>, o: &mut AlignedVec<Self>, s: SIGN, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2c_3d(n0 as i32, n1 as i32, n2 as i32, i.as_mut_ptr(), o.as_mut_ptr(), s as i32, f as u32))
    }
}

impl R2C for ($float, $complex) {
    type Real = $float;
    type Complex = $complex;
    unsafe fn r2c_1d(n: usize, i: &mut AlignedVec<Self::Real>, o: &mut AlignedVec<Self::Complex>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2c_1d(n as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn c2r_1d(n: usize, i: &mut AlignedVec<Self::Complex>, o: &mut AlignedVec<Self::Real>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2r_1d(n as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn r2c_2d(n0: usize, n1: usize, i: &mut AlignedVec<Self::Real>, o: &mut AlignedVec<Self::Complex>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2c_2d(n0 as i32, n1 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn c2r_2d(n0: usize, n1: usize, i: &mut AlignedVec<Self::Complex>, o: &mut AlignedVec<Self::Real>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2r_2d(n0 as i32, n1 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn r2c_3d(n0: usize, n1: usize, n2: usize, i: &mut AlignedVec<Self::Real>, o: &mut AlignedVec<Self::Complex>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2c_3d(n0 as i32, n1 as i32, n2 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn c2r_3d(n0: usize, n1: usize, n2: usize, i: &mut AlignedVec<Self::Complex>, o: &mut AlignedVec<Self::Real>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2r_3d(n0 as i32, n1 as i32, n2 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
}

}} // impl_plan_create

impl_plan_create!(
    _64,
    f64,
    c64,
    fftw_plan_r2r_1d,
    fftw_plan_dft_r2c_1d,
    fftw_plan_dft_c2r_1d,
    fftw_plan_dft_1d,
    fftw_plan_r2r_2d,
    fftw_plan_dft_r2c_2d,
    fftw_plan_dft_c2r_2d,
    fftw_plan_dft_2d,
    fftw_plan_r2r_3d,
    fftw_plan_dft_r2c_3d,
    fftw_plan_dft_c2r_3d,
    fftw_plan_dft_3d
);
impl_plan_create!(
    _32,
    f32,
    c32,
    fftwf_plan_r2r_1d,
    fftwf_plan_dft_r2c_1d,
    fftwf_plan_dft_c2r_1d,
    fftwf_plan_dft_1d,
    fftwf_plan_r2r_2d,
    fftwf_plan_dft_r2c_2d,
    fftwf_plan_dft_c2r_2d,
    fftwf_plan_dft_2d,
    fftwf_plan_r2r_3d,
    fftwf_plan_dft_r2c_3d,
    fftwf_plan_dft_c2r_3d,
    fftwf_plan_dft_3d
);
<commit_msg>Add comment<commit_after>use super::{FFTW_MUTEX, FLAG, R2R_KIND, SIGN, c32, c64};
use super::aligned_vec::AlignedVec;
use ffi;

use std::os::raw::c_void;
use std::ptr::null;

pub enum RawPlan {
    _64(ffi::fftw_plan),
    _32(ffi::fftwf_plan),
}

impl RawPlan {
    /// Execute FFT saved in the plan
    ///
    /// This is unsafe because rewrite the array saved in the plan.
    pub unsafe fn execute(&self) {
        if self.is_null() {
            panic!("Plan is NULL");
        }
        match *self {
            RawPlan::_64(p) => ffi::fftw_execute(p),
            RawPlan::_32(p) => ffi::fftwf_execute(p),
        }
    }

    /// Check if the plan is NULL
    pub fn is_null(&self) -> bool {
        let p = match *self {
            RawPlan::_64(p) => p as *const c_void,
            RawPlan::_32(p) => p as *const c_void,
        };
        p == null()
    }
}

impl Drop for RawPlan {
    fn drop(&mut self) {
        if self.is_null() {
            // TODO warning
            return;
        }
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe {
            match *self {
                RawPlan::_64(p) => ffi::fftw_destroy_plan(p),
                RawPlan::_32(p) => ffi::fftwf_destroy_plan(p),
            }
        }
    }
}

pub trait R2R: Sized {
    unsafe fn r2r_1d(n: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, R2R_KIND, FLAG) -> RawPlan;
    unsafe fn r2r_2d(
        n0: usize,
        n1: usize,
        in_: &mut AlignedVec<Self>,
        out: &mut AlignedVec<Self>,
        R2R_KIND,
        R2R_KIND,
        FLAG,
    ) -> RawPlan;
    unsafe fn r2r_3d(
        n0: usize,
        n1: usize,
        n2: usize,
        in_: &mut AlignedVec<Self>,
        out: &mut AlignedVec<Self>,
        R2R_KIND,
        R2R_KIND,
        R2R_KIND,
        FLAG,
    ) -> RawPlan;
}
pub trait C2C: Sized {
    unsafe fn c2c_1d(n: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, SIGN, FLAG) -> RawPlan;
    unsafe fn c2c_2d(
        n0: usize,
        n1: usize,
        in_: &mut AlignedVec<Self>,
        out: &mut AlignedVec<Self>,
        SIGN,
        FLAG,
    ) -> RawPlan;
    unsafe fn c2c_3d(
        n0: usize,
        n1: usize,
        n2: usize,
        in_: &mut AlignedVec<Self>,
        out: &mut AlignedVec<Self>,
        SIGN,
        FLAG,
    ) -> RawPlan;
}

pub trait R2C {
    type Real: Sized;
    type Complex: Sized;
    unsafe fn r2c_1d(n: usize, in_: &mut AlignedVec<Self::Real>, out: &mut AlignedVec<Self::Complex>, FLAG) -> RawPlan;
    unsafe fn c2r_1d(n: usize, in_: &mut AlignedVec<Self::Complex>, out: &mut AlignedVec<Self::Real>, FLAG) -> RawPlan;
    unsafe fn r2c_2d(
        n0: usize,
        n1: usize,
        in_: &mut AlignedVec<Self::Real>,
        out: &mut AlignedVec<Self::Complex>,
        FLAG,
    ) -> RawPlan;
    unsafe fn c2r_2d(
        n0: usize,
        n1: usize,
        in_: &mut AlignedVec<Self::Complex>,
        out: &mut AlignedVec<Self::Real>,
        FLAG,
    ) -> RawPlan;
    unsafe fn r2c_3d(
        n0: usize,
        n1: usize,
        n2: usize,
        in_: &mut AlignedVec<Self::Real>,
        out: &mut AlignedVec<Self::Complex>,
        FLAG,
    ) -> RawPlan;
    unsafe fn c2r_3d(
        n0: usize,
        n1: usize,
        n2: usize,
        in_: &mut AlignedVec<Self::Complex>,
        out: &mut AlignedVec<Self::Real>,
        FLAG,
    ) -> RawPlan;
}

macro_rules! impl_plan_create {
    ($bit:ident, $float:ty, $complex:ty,
     $r2r_1d:ident, $r2c_1d:ident, $c2r_1d:ident, $c2c_1d:ident,
     $r2r_2d:ident, $r2c_2d:ident, $c2r_2d:ident, $c2c_2d:ident,
     $r2r_3d:ident, $r2c_3d:ident, $c2r_3d:ident, $c2c_3d:ident) => {

impl R2R for $float {
    unsafe fn r2r_1d(n: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, kind: R2R_KIND, flag: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2r_1d(n as i32, in_.as_mut_ptr(), out.as_mut_ptr(), kind, flag as u32))
    }
    unsafe fn r2r_2d(n0: usize, n1: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, k0: R2R_KIND, k1: R2R_KIND, flag: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2r_2d(n0 as i32, n1 as i32, in_.as_mut_ptr(), out.as_mut_ptr(), k0, k1, flag as u32))
    }
    unsafe fn r2r_3d(n0: usize, n1: usize, n2: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, k0: R2R_KIND, k1: R2R_KIND, k2: R2R_KIND, flag: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2r_3d(n0 as i32, n1 as i32, n2 as i32, in_.as_mut_ptr(), out.as_mut_ptr(), k0, k1, k2, flag as u32))
    }
}

impl C2C for $complex {
    unsafe fn c2c_1d(n: usize, i: &mut AlignedVec<Self>, o: &mut AlignedVec<Self>, s: SIGN, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2c_1d(n as i32, i.as_mut_ptr(), o.as_mut_ptr(), s as i32, f as u32))
    }
    unsafe fn c2c_2d(n0: usize, n1: usize, i: &mut AlignedVec<Self>, o: &mut AlignedVec<Self>, s: SIGN, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2c_2d(n0 as i32, n1 as i32, i.as_mut_ptr(), o.as_mut_ptr(), s as i32, f as u32))
    }
    unsafe fn c2c_3d(n0: usize, n1: usize, n2: usize, i: &mut AlignedVec<Self>, o: &mut AlignedVec<Self>, s: SIGN, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2c_3d(n0 as i32, n1 as i32, n2 as i32, i.as_mut_ptr(), o.as_mut_ptr(), s as i32, f as u32))
    }
}

impl R2C for ($float, $complex) {
    type Real = $float;
    type Complex = $complex;
    unsafe fn r2c_1d(n: usize, i: &mut AlignedVec<Self::Real>, o: &mut AlignedVec<Self::Complex>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2c_1d(n as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn c2r_1d(n: usize, i: &mut AlignedVec<Self::Complex>, o: &mut AlignedVec<Self::Real>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2r_1d(n as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn r2c_2d(n0: usize, n1: usize, i: &mut AlignedVec<Self::Real>, o: &mut AlignedVec<Self::Complex>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2c_2d(n0 as i32, n1 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn c2r_2d(n0: usize, n1: usize, i: &mut AlignedVec<Self::Complex>, o: &mut AlignedVec<Self::Real>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2r_2d(n0 as i32, n1 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn r2c_3d(n0: usize, n1: usize, n2: usize, i: &mut AlignedVec<Self::Real>, o: &mut AlignedVec<Self::Complex>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2c_3d(n0 as i32, n1 as i32, n2 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn c2r_3d(n0: usize, n1: usize, n2: usize, i: &mut AlignedVec<Self::Complex>, o: &mut AlignedVec<Self::Real>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2r_3d(n0 as i32, n1 as i32, n2 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
}

}} // impl_plan_create

impl_plan_create!(
    _64,
    f64,
    c64,
    fftw_plan_r2r_1d,
    fftw_plan_dft_r2c_1d,
    fftw_plan_dft_c2r_1d,
    fftw_plan_dft_1d,
    fftw_plan_r2r_2d,
    fftw_plan_dft_r2c_2d,
    fftw_plan_dft_c2r_2d,
    fftw_plan_dft_2d,
    fftw_plan_r2r_3d,
    fftw_plan_dft_r2c_3d,
    fftw_plan_dft_c2r_3d,
    fftw_plan_dft_3d
);
impl_plan_create!(
    _32,
    f32,
    c32,
    fftwf_plan_r2r_1d,
    fftwf_plan_dft_r2c_1d,
    fftwf_plan_dft_c2r_1d,
    fftwf_plan_dft_1d,
    fftwf_plan_r2r_2d,
    fftwf_plan_dft_r2c_2d,
    fftwf_plan_dft_c2r_2d,
    fftwf_plan_dft_2d,
    fftwf_plan_r2r_3d,
    fftwf_plan_dft_r2c_3d,
    fftwf_plan_dft_c2r_3d,
    fftwf_plan_dft_3d
);
<|endoftext|>


<commit_before>//! Unwinding for *emscripten* target.
//!
//! Whereas Rust's usual unwinding implementation for Unix platforms
//! calls into the libunwind APIs directly, on Emscripten we instead
//! call into the C++ unwinding APIs. This is just an expedience since
//! Emscripten's runtime always implements those APIs and does not
//! implement libunwind.

#![allow(private_no_mangle_fns)]

use alloc::boxed::Box;
use core::any::Any;
use core::mem;
use core::ptr;
use libc::{self, c_int};
use unwind as uw;

// This matches the layout of std::type_info in C++
#[repr(C)]
struct TypeInfo {
    vtable: *const usize,
    name: *const u8,
}
unsafe impl Sync for TypeInfo {}

extern "C" {
    // The leading `\x01` byte here is actually a magical signal to LLVM to
    // *not* apply any other mangling like prefixing with a `_` character.
    //
    // This symbol is the vtable used by C++'s `std::type_info`. Objects of type
    // `std::type_info`, type descriptors, have a pointer to this table. Type
    // descriptors are referenced by the C++ EH structures defined above and
    // that we construct below.
    //
    // Note that the real size is larger than 3 usize, but we only need our
    // vtable to point to the third element.
    #[link_name = "\x01_ZTVN10__cxxabiv117__class_type_infoE"]
    static CLASS_TYPE_INFO_VTABLE: [usize; 3];
}

// std::type_info for a rust_panic class
#[lang = "eh_catch_typeinfo"]
static EXCEPTION_TYPE_INFO: TypeInfo = TypeInfo {
    // Normally we would use .as_ptr().add(2) but this doesn't work in a const context.
    vtable: unsafe { &CLASS_TYPE_INFO_VTABLE[2] },
    // This intentionally doesn't use the normal name mangling scheme because
    // we don't want C++ to be able to produce or catch Rust panics.
    name: b"rust_panic\0".as_ptr(),
};

pub fn payload() -> *mut u8 {
    ptr::null_mut()
}

pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
    assert!(!ptr.is_null());
    let adjusted_ptr = __cxa_begin_catch(ptr as *mut libc::c_void);
    let ex = ptr::read(adjusted_ptr as *mut _);
    __cxa_end_catch();
    ex
}

pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
    let sz = mem::size_of_val(&data);
    let exception = __cxa_allocate_exception(sz);
    if exception.is_null() {
        return uw::_URC_FATAL_PHASE1_ERROR as u32;
    }
    ptr::write(exception as *mut _, data);
    __cxa_throw(exception as *mut _, &EXCEPTION_TYPE_INFO, ptr::null_mut());
}

#[lang = "eh_personality"]
#[no_mangle]
unsafe extern "C" fn rust_eh_personality(
    version: c_int,
    actions: uw::_Unwind_Action,
    exception_class: uw::_Unwind_Exception_Class,
    exception_object: *mut uw::_Unwind_Exception,
    context: *mut uw::_Unwind_Context,
) -> uw::_Unwind_Reason_Code {
    __gxx_personality_v0(version, actions, exception_class, exception_object, context)
}

extern "C" {
    fn __cxa_allocate_exception(thrown_size: libc::size_t) -> *mut libc::c_void;
    fn __cxa_begin_catch(thrown_exception: *mut libc::c_void) -> *mut libc::c_void;
    fn __cxa_end_catch();
    fn __cxa_throw(
        thrown_exception: *mut libc::c_void,
        tinfo: *const TypeInfo,
        dest: *mut libc::c_void,
    ) -> !;
    fn __gxx_personality_v0(
        version: c_int,
        actions: uw::_Unwind_Action,
        exception_class: uw::_Unwind_Exception_Class,
        exception_object: *mut uw::_Unwind_Exception,
        context: *mut uw::_Unwind_Context,
    ) -> uw::_Unwind_Reason_Code;
}
<commit_msg>Fix a memory leak in emcc if a Rust panic is caught by C++ and discarded<commit_after>//! Unwinding for *emscripten* target.
//!
//! Whereas Rust's usual unwinding implementation for Unix platforms
//! calls into the libunwind APIs directly, on Emscripten we instead
//! call into the C++ unwinding APIs. This is just an expedience since
//! Emscripten's runtime always implements those APIs and does not
//! implement libunwind.

#![allow(private_no_mangle_fns)]

use alloc::boxed::Box;
use core::any::Any;
use core::mem;
use core::ptr;
use libc::{self, c_int};
use unwind as uw;

// This matches the layout of std::type_info in C++
#[repr(C)]
struct TypeInfo {
    vtable: *const usize,
    name: *const u8,
}
unsafe impl Sync for TypeInfo {}

extern "C" {
    // The leading `\x01` byte here is actually a magical signal to LLVM to
    // *not* apply any other mangling like prefixing with a `_` character.
    //
    // This symbol is the vtable used by C++'s `std::type_info`. Objects of type
    // `std::type_info`, type descriptors, have a pointer to this table. Type
    // descriptors are referenced by the C++ EH structures defined above and
    // that we construct below.
    //
    // Note that the real size is larger than 3 usize, but we only need our
    // vtable to point to the third element.
    #[link_name = "\x01_ZTVN10__cxxabiv117__class_type_infoE"]
    static CLASS_TYPE_INFO_VTABLE: [usize; 3];
}

// std::type_info for a rust_panic class
#[lang = "eh_catch_typeinfo"]
static EXCEPTION_TYPE_INFO: TypeInfo = TypeInfo {
    // Normally we would use .as_ptr().add(2) but this doesn't work in a const context.
    vtable: unsafe { &CLASS_TYPE_INFO_VTABLE[2] },
    // This intentionally doesn't use the normal name mangling scheme because
    // we don't want C++ to be able to produce or catch Rust panics.
    name: b"rust_panic\0".as_ptr(),
};

pub fn payload() -> *mut u8 {
    ptr::null_mut()
}

struct Exception {
    data: Option<Box<dyn Any + Send>>,
}

pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
    assert!(!ptr.is_null());
    let adjusted_ptr = __cxa_begin_catch(ptr as *mut libc::c_void) as *mut Exception;
    let ex = (*adjusted_ptr).data.take();
    __cxa_end_catch();
    ex.unwrap()
}

pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
    let sz = mem::size_of_val(&data);
    let exception = __cxa_allocate_exception(sz) as *mut Exception;
    if exception.is_null() {
        return uw::_URC_FATAL_PHASE1_ERROR as u32;
    }
    ptr::write(exception, Exception { data: Some(data) });
    __cxa_throw(exception as *mut _, &EXCEPTION_TYPE_INFO, exception_cleanup);

    extern "C" fn exception_cleanup(ptr: *mut libc::c_void) {
        unsafe {
            ptr::drop_in_place(ptr as *mut Exception);
        }
    }
}

#[lang = "eh_personality"]
#[no_mangle]
unsafe extern "C" fn rust_eh_personality(
    version: c_int,
    actions: uw::_Unwind_Action,
    exception_class: uw::_Unwind_Exception_Class,
    exception_object: *mut uw::_Unwind_Exception,
    context: *mut uw::_Unwind_Context,
) -> uw::_Unwind_Reason_Code {
    __gxx_personality_v0(version, actions, exception_class, exception_object, context)
}

extern "C" {
    fn __cxa_allocate_exception(thrown_size: libc::size_t) -> *mut libc::c_void;
    fn __cxa_begin_catch(thrown_exception: *mut libc::c_void) -> *mut libc::c_void;
    fn __cxa_end_catch();
    fn __cxa_throw(
        thrown_exception: *mut libc::c_void,
        tinfo: *const TypeInfo,
        dest: extern "C" fn(*mut libc::c_void),
    ) -> !;
    fn __gxx_personality_v0(
        version: c_int,
        actions: uw::_Unwind_Action,
        exception_class: uw::_Unwind_Exception_Class,
        exception_object: *mut uw::_Unwind_Exception,
        context: *mut uw::_Unwind_Context,
    ) -> uw::_Unwind_Reason_Code;
}
<|endoftext|>


<commit_before>//! Functions for loading TIS-100 assembly code from save files.

use std::collections::VecMap;
use std::io::Read;
use std::fs::File;
use core::Program;
use parse::{parse_program, ProgramErrors};

/// Programs that are assigned to specific nodes in a TIS-100.
pub type Save = VecMap<Program>;

/// A list of errors returned when parsing programs for each node.
pub type SaveErrors = VecMap<ProgramErrors>;

/// An error returned when loading a safe from a file.
pub enum LoadSaveError {
    ParseFailed(SaveErrors),
    LoadFailed,
}

use self::LoadSaveError::*;

/// Load a `Save` from a file.
pub fn load_save(filename: &str) -> Result<Save, LoadSaveError> {
    match File::open(filename) {
        Ok(mut file) => {
            let mut src = String::new();
            match file.read_to_string(&mut src) {
                Ok(_) => match parse_save(&src) {
                    Ok(prog) => Ok(prog),
                    Err(errs) => Err(ParseFailed(errs)),
                },
                Err(_) => Err(LoadFailed),
            }
        },
        Err(_) => Err(LoadFailed),
    }
}

/// Parse the text of a TIS-100 save file into a map from node numbers to programs.
pub fn parse_save(src: &str) -> Result<Save, SaveErrors> {
    let mut save = VecMap::new();
    let mut errors = VecMap::new();

    // Skip the first result since it will be empty.
    for src in src.split("@").skip(1) {
        let maybe_num = src.chars()
            .take_while(|c| c.is_numeric())
            .collect::<String>()
            .parse::<usize>()
            .ok();

        if let Some(num) = maybe_num {
            // Skip the first line since it has the node number.
            let prog_src = src.lines()
                .skip(1)
                .collect::<String>();

            match parse_program(&prog_src) {
                Ok(prog) => {
                    save.insert(num, prog);
                },
                Err(errs) => {
                    errors.insert(num, errs);
                }
            }
        }
    }

    if errors.len() > 0 {
        Err(errors)
    } else {
        Ok(save)
    }
}

/// Pretty print errors from parsing a save file.
pub fn pretty_print_errors(save_errors: SaveErrors) {
    for (node_num, ref errors) in save_errors.iter() {
        for &(line_num, ref error) in errors.iter() {
            println!("Node {}: Line {}: {}\n", node_num, line_num, error);
        }
    }
}

#[test]
fn test_parse_save() {
    let save = parse_save("@1\nADD 1\n@2\nADD 1\n").unwrap();
    assert_eq!(save.len(), 2);
}
<commit_msg>Fix a bug when parsing newlines in saves.<commit_after>//! Functions for loading TIS-100 assembly code from save files.

use std::collections::VecMap;
use std::io::Read;
use std::fs::File;
use core::Program;
use parse::{parse_program, ProgramErrors};

/// Programs that are assigned to specific nodes in a TIS-100.
pub type Save = VecMap<Program>;

/// A list of errors returned when parsing programs for each node.
pub type SaveErrors = VecMap<ProgramErrors>;

/// An error returned when loading a safe from a file.
pub enum LoadSaveError {
    ParseFailed(SaveErrors),
    LoadFailed,
}

use self::LoadSaveError::*;

/// Load a `Save` from a file.
pub fn load_save(filename: &str) -> Result<Save, LoadSaveError> {
    match File::open(filename) {
        Ok(mut file) => {
            let mut src = String::new();
            match file.read_to_string(&mut src) {
                Ok(_) => match parse_save(&src) {
                    Ok(prog) => Ok(prog),
                    Err(errs) => Err(ParseFailed(errs)),
                },
                Err(_) => Err(LoadFailed),
            }
        },
        Err(_) => Err(LoadFailed),
    }
}

/// Parse the text of a TIS-100 save file into a map from node numbers to programs.
pub fn parse_save(src: &str) -> Result<Save, SaveErrors> {
    let mut save = VecMap::new();
    let mut errors = VecMap::new();

    // Skip the first result since it will be empty.
    for src in src.split("@").skip(1) {
        let maybe_num = src.chars()
            .take_while(|c| c.is_numeric())
            .collect::<String>()
            .parse::<usize>()
            .ok();

        if let Some(num) = maybe_num {
            // Skip the first line since it has the node number.
            let prog_src = src.chars()
                .skip_while(|&c| c != '\n')
                .skip(1)
                .collect::<String>();

            match parse_program(&prog_src) {
                Ok(prog) => {
                    save.insert(num, prog);
                },
                Err(errs) => {
                    errors.insert(num, errs);
                }
            }
        }
    }

    if errors.len() > 0 {
        Err(errors)
    } else {
        Ok(save)
    }
}

/// Pretty print errors from parsing a save file.
pub fn pretty_print_errors(save_errors: SaveErrors) {
    for (node_num, ref errors) in save_errors.iter() {
        for &(line_num, ref error) in errors.iter() {
            println!("Node {}: Line {}: {}\n", node_num, line_num, error);
        }
    }
}

#[test]
fn test_parse_save() {
    let save = parse_save("@1\nADD 1\n@2\nADD 1\n").unwrap();
    assert_eq!(save.len(), 2);
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, The Radare Project. All rights reserved.
// See the COPYING file at the top-level directory of this distribution.
// Licensed under the BSD 3-Clause License:
// <http://opensource.org/licenses/BSD-3-Clause>
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Defines the traits to be implemented by SSA data structures.
//!
//! These traits extend upon the ones provided in `cfg_traits`
//!
//! # Design
//!  * `SSA` - Analogous to `CFG` this trait provides __accessors__ to
//!  the data: Methods to enumerate operations, discovered connected operations,
//!  determine which operation a basic block is in. etc.
//!
//!  * `SSAMod` - This trait provides methods to __manipulate__ operation nodes.
//!
//!  * `SSAExtras` - Provides additional methods that allow associated information to be stored
//!
//! The associated type `SSA::ValueRef` is used by the methods to refer to
//! nodes.

use std::hash::Hash;
use std::fmt::{self, Debug};

use middle::ir;
use super::cfg_traits::{CFG, CFGMod};

#[macro_export]
macro_rules! entry_node_err {
    ($ssa:expr) => {
        $ssa.entry_node().unwrap_or_else(|| {
            radeco_err!("Incomplete CFG graph");
            $ssa.invalid_action().unwrap()
        })
    }
}

#[macro_export]
macro_rules! exit_node_err {
    ($ssa:expr) => {
        $ssa.exit_node().unwrap_or_else(|| {
            radeco_err!("Incomplete CFG graph");
            $ssa.invalid_action().unwrap()
        })
    }
}

#[macro_export]
macro_rules! registers_in_err {
    ($ssa:expr, $node:expr) => {
            registers_in_err!($ssa, $node, $ssa.invalid_value().unwrap())
    };
    ($ssa:expr, $node:expr, $default:expr) => {
        $ssa.registers_in($node).unwrap_or_else(|| {
            radeco_err!("No register state node found");
            $default
        })
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
/// Defines the high level `type` of value for a node. It is only used to differentiate between
/// references and non-reference (scalar) types.
pub enum ValueType {
    /// Pointer or reference to code or memory
    Reference,
    /// Not a pointer type
    Scalar,
    /// Not (yet) resolved to be a reference or a constant
    Unresolved,
    /// Invalid/Unconsistent
    Invalid,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
/// Information for a `ValueRef`
pub struct ValueInfo {
    /// `Type` of value
    pub vty: ValueType,
    /// `width` of the operation, should be in 1, 2, 4, 8, 16, 32, 64, 128
    width: ir::WidthSpec,
}

macro_rules! scalar {
    ($w:expr) => {
        ValueInfo::new($crate::middle::ssa::ssa_traits::ValueType::Scalar, ir::WidthSpec::new_known($w))
    }
}

macro_rules! reference {
    () => {
        ValueInfo::new($crate::middle::ssa::ssa_traits::ValueType::Reference, ir::WidthSpec::Unknown)
    };
    ($w:expr) => {
        ValueInfo::new($crate::middle::ssa::ssa_traits::ValueType::Reference, ir::WidthSpec::new_known($w))
    }
}

impl ValueInfo {
    pub fn new(vty: ValueType, width: ir::WidthSpec) -> ValueInfo {
        ValueInfo {
            vty: vty,
            width: width,
        }
    }

    pub fn width(&self) -> &ir::WidthSpec {
        &self.width
    }

    pub fn new_unresolved(width: ir::WidthSpec) -> ValueInfo {
        ValueInfo::new(ValueType::Unresolved, width)
    }

    pub fn new_scalar(width: ir::WidthSpec) -> ValueInfo {
        ValueInfo::new(ValueType::Scalar, width)
    }

    pub fn new_reference(width: ir::WidthSpec) -> ValueInfo {
        ValueInfo::new(ValueType::Reference, width)
    }

    pub fn set_value_type(&mut self, vt: ValueType) {
        self.vty = vt;
    }

    pub fn mark_as_scalar(&mut self) {
        self.vty = ValueType::Scalar;
    }

    pub fn mark_as_reference(&mut self) {
        self.vty = ValueType::Reference;
    }

    pub fn mark_as_invalid(&mut self) {
        self.vty = ValueType::Invalid;
    }

    pub fn value_type(&self) -> &ValueType {
        &self.vty
    }

    pub fn is_scalar(&self) -> bool {
        self.vty == ValueType::Scalar
    }

    pub fn is_reference(&self) -> bool {
        self.vty == ValueType::Reference
    }
}

pub struct BBInfo;

/// Value node without operands
#[derive(Clone, Debug)]
pub enum NodeType {
    /// An operation node with the specified opcode.
    Op(ir::MOpcode),
    /// A phi node.
    Phi,
    /// A node with unknown value.
    Undefined,
    /// Generic comment, used to represent other data
    Comment(String),
}

// Implement display helper for NodeData to make it a little nicer to read prefix notation.
impl fmt::Display for NodeType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match self {
            &NodeType::Op(ref op) => format!("{}", op),
            &NodeType::Phi => "Phi".to_owned(),
            &NodeType::Comment(ref s) => s.clone(),
            // Don't care about these
            _ => String::new(),
        };
        write!(f, "{}", s)
    }
}

#[derive(Clone, Debug)]
/// Value node without operands with `ValueInfo`
pub struct NodeData {
    pub vt: ValueInfo,
    pub nt: NodeType,
}

/// Trait for the SSA Form implementation.
// This trait ensures that any other ssa form will be compatible with our
// implementations provided
// the SSA form implements the following traits.
pub trait SSA: CFG {
    type ValueRef: Eq + Hash + Clone + Copy + Debug; // We could drop the Copy trait later and insert .clone()

    ///////////////////////////////////////////////////////////////////////////
    //// Node accessors and helpers
    ///////////////////////////////////////////////////////////////////////////

    /// Check if the node at the given index is a expression or not.
    fn is_expr(&self, i: Self::ValueRef) -> bool;

    /// Check if the node at the given index is a phi node or not.
    fn is_phi(&self, i: Self::ValueRef) -> bool;

    /// Returns true if the expression acts as a `Selector` for control flow.
    fn is_selector(&self, i: Self::ValueRef) -> bool;

    /// Returns true if the node is a comment node
    fn is_comment(&self, i: Self::ValueRef) -> bool;

    fn is_constant(&self, exi: Self::ValueRef) -> bool;
    fn constant_value(&self, exi: Self::ValueRef) -> Option<u64>;

    /// Get all value nodes in the whole graph.
    fn values(&self) -> Vec<Self::ValueRef>;

    /// Get expr/phi node address
    fn address(&self, ni: Self::ValueRef) -> Option<ir::MAddress>;

    /// Get all the NodeIndex of all operations/expressions in the BasicBlock with index 'i'.
    fn exprs_in(&self, i: Self::ActionRef) -> Vec<Self::ValueRef>;

    /// Get all phis in the BasicBlock with index 'i'.
    fn phis_in(&self, i: Self::ActionRef) -> Vec<Self::ValueRef>;

    /// Get a node that has all register values at the beginning of the specified basic block as args
    fn registers_in(&self, i: Self::ActionRef) -> Option<Self::ValueRef>;

    /// Returns the selector for the Block.
    fn selector_in(&self, i: Self::ActionRef) -> Option<Self::ValueRef>;

    /// Get the Block for which i acts as a selector.
    fn selector_for(&self, i: Self::ValueRef) -> Option<Self::ActionRef>;

    /// Get all the uses of the node with index 'i'.
    fn uses_of(&self, i: Self::ValueRef) -> Vec<Self::ValueRef>;

    /// Get the operands for the operation with NodeIndex 'i'.
    fn operands_of(&self, i: Self::ValueRef) -> Vec<Self::ValueRef>;

    /// Get the operands for the operation with NodeIndex 'i' as tuples.
    fn sparse_operands_of(&self, i: Self::ValueRef) -> Vec<(u8, Self::ValueRef)>;

    /// Get the NodeIndex of the BasicBlock to which node with index 'i' belongs to.
    fn block_for(&self, i: Self::ValueRef) -> Option<Self::ActionRef>;

    /// Get the actual NodeData.
    fn node_data(&self, i: Self::ValueRef) -> Result<NodeData, Box<Debug>>;

    /// Get const information, as a pack of get_node_data on a OpConst node.
    fn constant(&self, i: Self::ValueRef) -> Option<u64>;

    /// Get comment information, as a pack of get_node_data on a Comment data.
    fn comment(&self, i: Self::ValueRef) -> Option<String>;

    /// Get OpCode information, as a pack of get_node_data on a Comment data.
    fn opcode(&self, i: Self::ValueRef) -> Option<ir::MOpcode>;

    /// Get information of the register which belongs to the node.
    fn registers(&self, _: Self::ValueRef) -> Vec<String>;

    /// Return invalid value
    fn invalid_value(&self) -> Option<Self::ValueRef>;
}

/// Trait for modifying SSA data
pub trait SSAMod: SSA + CFGMod {

    /// Set the address of a value
    fn set_address(&mut self, i: Self::ValueRef, addr: ir::MAddress);

    /// Set the register information for a value
    fn set_register(&mut self, i: Self::ValueRef, regname: String);

    /// Set the node as selector for the control edges away from the specified basic block
    fn set_selector(&mut self, node: Self::ValueRef, block: Self::ActionRef);

    /// Insert a new operation node.
    fn insert_op(&mut self, opc: ir::MOpcode, vt: ValueInfo, addr: Option<u64>) -> Option<Self::ValueRef>;

    /// Add a new constant node.
    fn insert_const(&mut self, value: u64) -> Option<Self::ValueRef>;

    /// Add a new phi node.
    fn insert_phi(&mut self, vt: ValueInfo) -> Option<Self::ValueRef>;

    /// Add a new undefined node
    fn insert_undefined(&mut self, vt: ValueInfo) -> Option<Self::ValueRef>;

    /// Add a new comment node
    fn insert_comment(&mut self, vt: ValueInfo, msg: String) -> Option<Self::ValueRef>;

    /// Associate a node with index n with a block
    fn insert_into_block(&mut self, node: Self::ValueRef, block: Self::ActionRef, ir::MAddress);

    /// Add a data source to a phi node.
    fn phi_use(&mut self, phi: Self::ValueRef, node: Self::ValueRef);

    /// Remove a data source from a phi node.
    fn phi_unuse(&mut self, phi: Self::ValueRef, node: Self::ValueRef);

    /// Set the index-th argument of the node.
    fn op_use(&mut self, node: Self::ValueRef, index: u8, argument: Self::ValueRef);

    /// Remove a data source from a expr node.
    fn op_unuse(&mut self, op: Self::ValueRef, operand: Self::ValueRef);

    /// Replace one node by another within one basic block.
    fn replace_value(&mut self, node: Self::ValueRef, replacement: Self::ValueRef);

    /// Remove a node without replacement
    fn remove_value(&mut self, node: Self::ValueRef);

    /// Remove control flow edge. This is a part of SSAMod as this potentially modifies the ssa.
    fn remove_data_edge(&mut self, i: Self::CFEdgeRef);
}

/// Extras. TODO
///
/// Design requirement - For a method to be a part of `SSAExtras`, it __has__ to have a default
/// implementation that would work out of the box. Since these methods are only extras and do not
/// add any major functionality, but rather just convinence or display glitter, the user must not
/// be burdened with implementing this. All methods must return `Option<T>` to ensure this.

pub trait SSAExtra: SSA {
    fn mark(&mut self, _: &Self::ValueRef) { }
    fn clear_mark(&mut self, &Self::ValueRef) { }
    fn set_color(&mut self, _: &Self::ValueRef, _: u8) { }
    fn set_comment(&mut self, _: &Self::ValueRef, _: String) { }
    fn add_flag(&mut self, _: &Self::ValueRef, _: String) { }
    fn is_marked(&self, _: &Self::ValueRef) -> bool {
        false
    }

    fn color(&self, _: &Self::ValueRef) -> Option<u8> {
        None
    }

    fn comments(&self, _: &Self::ValueRef) -> Option<String> {
        None
    }

    fn addr(&self, _: &Self::ValueRef) -> Option<String> {
        None
    }

    fn flags(&self, _: &Self::ValueRef) -> Option<String> {
        None
    }
}

pub trait SSAWalk<I: Iterator<Item=<Self as SSA>::ValueRef>>: SSA {
    fn bfs_walk(&self) -> I;
    fn inorder_walk(&self) -> I;
    fn dfs_walk(&self) -> I;
}
<commit_msg>Formatting<commit_after>// Copyright (c) 2015, The Radare Project. All rights reserved.
// See the COPYING file at the top-level directory of this distribution.
// Licensed under the BSD 3-Clause License:
// <http://opensource.org/licenses/BSD-3-Clause>
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Defines the traits to be implemented by SSA data structures.
//!
//! These traits extend upon the ones provided in `cfg_traits`
//!
//! # Design
//!  * `SSA` - Analogous to `CFG` this trait provides __accessors__ to
//!  the data: Methods to enumerate operations, discovered connected operations,
//!  determine which operation a basic block is in. etc.
//!
//!  * `SSAMod` - This trait provides methods to __manipulate__ operation nodes.
//!
//!  * `SSAExtras` - Provides additional methods that allow associated information to be stored
//!
//! The associated type `SSA::ValueRef` is used by the methods to refer to
//! nodes.

use std::fmt::{self, Debug};
use std::hash::Hash;

use super::cfg_traits::{CFGMod, CFG};
use middle::ir;

#[macro_export]
macro_rules! entry_node_err {
    ($ssa:expr) => {
        $ssa.entry_node().unwrap_or_else(|| {
            radeco_err!("Incomplete CFG graph");
            $ssa.invalid_action().unwrap()
        })
    };
}

#[macro_export]
macro_rules! exit_node_err {
    ($ssa:expr) => {
        $ssa.exit_node().unwrap_or_else(|| {
            radeco_err!("Incomplete CFG graph");
            $ssa.invalid_action().unwrap()
        })
    };
}

#[macro_export]
macro_rules! registers_in_err {
    ($ssa:expr, $node:expr) => {
        registers_in_err!($ssa, $node, $ssa.invalid_value().unwrap())
    };
    ($ssa:expr, $node:expr, $default:expr) => {
        $ssa.registers_in($node).unwrap_or_else(|| {
            radeco_err!("No register state node found");
            $default
        })
    };
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
/// Defines the high level `type` of value for a node. It is only used to differentiate between
/// references and non-reference (scalar) types.
pub enum ValueType {
    /// Pointer or reference to code or memory
    Reference,
    /// Not a pointer type
    Scalar,
    /// Not (yet) resolved to be a reference or a constant
    Unresolved,
    /// Invalid/Unconsistent
    Invalid,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
/// Information for a `ValueRef`
pub struct ValueInfo {
    /// `Type` of value
    pub vty: ValueType,
    /// `width` of the operation, should be in 1, 2, 4, 8, 16, 32, 64, 128
    width: ir::WidthSpec,
}

macro_rules! scalar {
    ($w:expr) => {
        ValueInfo::new(
            $crate::middle::ssa::ssa_traits::ValueType::Scalar,
            ir::WidthSpec::new_known($w),
        )
    };
}

macro_rules! reference {
    () => {
        ValueInfo::new(
            $crate::middle::ssa::ssa_traits::ValueType::Reference,
            ir::WidthSpec::Unknown,
        )
    };
    ($w:expr) => {
        ValueInfo::new(
            $crate::middle::ssa::ssa_traits::ValueType::Reference,
            ir::WidthSpec::new_known($w),
        )
    };
}

impl ValueInfo {
    pub fn new(vty: ValueType, width: ir::WidthSpec) -> ValueInfo {
        ValueInfo {
            vty: vty,
            width: width,
        }
    }

    pub fn width(&self) -> &ir::WidthSpec {
        &self.width
    }

    pub fn new_unresolved(width: ir::WidthSpec) -> ValueInfo {
        ValueInfo::new(ValueType::Unresolved, width)
    }

    pub fn new_scalar(width: ir::WidthSpec) -> ValueInfo {
        ValueInfo::new(ValueType::Scalar, width)
    }

    pub fn new_reference(width: ir::WidthSpec) -> ValueInfo {
        ValueInfo::new(ValueType::Reference, width)
    }

    pub fn set_value_type(&mut self, vt: ValueType) {
        self.vty = vt;
    }

    pub fn mark_as_scalar(&mut self) {
        self.vty = ValueType::Scalar;
    }

    pub fn mark_as_reference(&mut self) {
        self.vty = ValueType::Reference;
    }

    pub fn mark_as_invalid(&mut self) {
        self.vty = ValueType::Invalid;
    }

    pub fn value_type(&self) -> &ValueType {
        &self.vty
    }

    pub fn is_scalar(&self) -> bool {
        self.vty == ValueType::Scalar
    }

    pub fn is_reference(&self) -> bool {
        self.vty == ValueType::Reference
    }
}

pub struct BBInfo;

/// Value node without operands
#[derive(Clone, Debug)]
pub enum NodeType {
    /// An operation node with the specified opcode.
    Op(ir::MOpcode),
    /// A phi node.
    Phi,
    /// A node with unknown value.
    Undefined,
    /// Generic comment, used to represent other data
    Comment(String),
}

// Implement display helper for NodeData to make it a little nicer to read prefix notation.
impl fmt::Display for NodeType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match self {
            &NodeType::Op(ref op) => format!("{}", op),
            &NodeType::Phi => "Phi".to_owned(),
            &NodeType::Comment(ref s) => s.clone(),
            // Don't care about these
            _ => String::new(),
        };
        write!(f, "{}", s)
    }
}

#[derive(Clone, Debug)]
/// Value node without operands with `ValueInfo`
pub struct NodeData {
    pub vt: ValueInfo,
    pub nt: NodeType,
}

/// Trait for the SSA Form implementation.
// This trait ensures that any other ssa form will be compatible with our
// implementations provided
// the SSA form implements the following traits.
pub trait SSA: CFG {
    type ValueRef: Eq + Hash + Clone + Copy + Debug; // We could drop the Copy trait later and insert .clone()

    ///////////////////////////////////////////////////////////////////////////
    //// Node accessors and helpers
    ///////////////////////////////////////////////////////////////////////////

    /// Check if the node at the given index is a expression or not.
    fn is_expr(&self, i: Self::ValueRef) -> bool;

    /// Check if the node at the given index is a phi node or not.
    fn is_phi(&self, i: Self::ValueRef) -> bool;

    /// Returns true if the expression acts as a `Selector` for control flow.
    fn is_selector(&self, i: Self::ValueRef) -> bool;

    /// Returns true if the node is a comment node
    fn is_comment(&self, i: Self::ValueRef) -> bool;

    fn is_constant(&self, exi: Self::ValueRef) -> bool;
    fn constant_value(&self, exi: Self::ValueRef) -> Option<u64>;

    /// Get all value nodes in the whole graph.
    fn values(&self) -> Vec<Self::ValueRef>;

    /// Get expr/phi node address
    fn address(&self, ni: Self::ValueRef) -> Option<ir::MAddress>;

    /// Get all the NodeIndex of all operations/expressions in the BasicBlock with index 'i'.
    fn exprs_in(&self, i: Self::ActionRef) -> Vec<Self::ValueRef>;

    /// Get all phis in the BasicBlock with index 'i'.
    fn phis_in(&self, i: Self::ActionRef) -> Vec<Self::ValueRef>;

    /// Get a node that has all register values at the beginning of the specified basic block as args
    fn registers_in(&self, i: Self::ActionRef) -> Option<Self::ValueRef>;

    /// Returns the selector for the Block.
    fn selector_in(&self, i: Self::ActionRef) -> Option<Self::ValueRef>;

    /// Get the Block for which i acts as a selector.
    fn selector_for(&self, i: Self::ValueRef) -> Option<Self::ActionRef>;

    /// Get all the uses of the node with index 'i'.
    fn uses_of(&self, i: Self::ValueRef) -> Vec<Self::ValueRef>;

    /// Get the operands for the operation with NodeIndex 'i'.
    fn operands_of(&self, i: Self::ValueRef) -> Vec<Self::ValueRef>;

    /// Get the operands for the operation with NodeIndex 'i' as tuples.
    fn sparse_operands_of(&self, i: Self::ValueRef) -> Vec<(u8, Self::ValueRef)>;

    /// Get the NodeIndex of the BasicBlock to which node with index 'i' belongs to.
    fn block_for(&self, i: Self::ValueRef) -> Option<Self::ActionRef>;

    /// Get the actual NodeData.
    fn node_data(&self, i: Self::ValueRef) -> Result<NodeData, Box<Debug>>;

    /// Get const information, as a pack of get_node_data on a OpConst node.
    fn constant(&self, i: Self::ValueRef) -> Option<u64>;

    /// Get comment information, as a pack of get_node_data on a Comment data.
    fn comment(&self, i: Self::ValueRef) -> Option<String>;

    /// Get OpCode information, as a pack of get_node_data on a Comment data.
    fn opcode(&self, i: Self::ValueRef) -> Option<ir::MOpcode>;

    /// Get information of the register which belongs to the node.
    fn registers(&self, _: Self::ValueRef) -> Vec<String>;

    /// Return invalid value
    fn invalid_value(&self) -> Option<Self::ValueRef>;
}

/// Trait for modifying SSA data
pub trait SSAMod: SSA + CFGMod {
    /// Set the address of a value
    fn set_address(&mut self, i: Self::ValueRef, addr: ir::MAddress);

    /// Set the register information for a value
    fn set_register(&mut self, i: Self::ValueRef, regname: String);

    /// Set the node as selector for the control edges away from the specified basic block
    fn set_selector(&mut self, node: Self::ValueRef, block: Self::ActionRef);

    /// Insert a new operation node.
    fn insert_op(
        &mut self,
        opc: ir::MOpcode,
        vt: ValueInfo,
        addr: Option<u64>,
    ) -> Option<Self::ValueRef>;

    /// Add a new constant node.
    fn insert_const(&mut self, value: u64) -> Option<Self::ValueRef>;

    /// Add a new phi node.
    fn insert_phi(&mut self, vt: ValueInfo) -> Option<Self::ValueRef>;

    /// Add a new undefined node
    fn insert_undefined(&mut self, vt: ValueInfo) -> Option<Self::ValueRef>;

    /// Add a new comment node
    fn insert_comment(&mut self, vt: ValueInfo, msg: String) -> Option<Self::ValueRef>;

    /// Associate a node with index n with a block
    fn insert_into_block(&mut self, node: Self::ValueRef, block: Self::ActionRef, ir::MAddress);

    /// Add a data source to a phi node.
    fn phi_use(&mut self, phi: Self::ValueRef, node: Self::ValueRef);

    /// Remove a data source from a phi node.
    fn phi_unuse(&mut self, phi: Self::ValueRef, node: Self::ValueRef);

    /// Set the index-th argument of the node.
    fn op_use(&mut self, node: Self::ValueRef, index: u8, argument: Self::ValueRef);

    /// Remove a data source from a expr node.
    fn op_unuse(&mut self, op: Self::ValueRef, operand: Self::ValueRef);

    /// Replace one node by another within one basic block.
    fn replace_value(&mut self, node: Self::ValueRef, replacement: Self::ValueRef);

    /// Remove a node without replacement
    fn remove_value(&mut self, node: Self::ValueRef);

    /// Remove control flow edge. This is a part of SSAMod as this potentially modifies the ssa.
    fn remove_data_edge(&mut self, i: Self::CFEdgeRef);
}

/// Extras. TODO
///
/// Design requirement - For a method to be a part of `SSAExtras`, it __has__ to have a default
/// implementation that would work out of the box. Since these methods are only extras and do not
/// add any major functionality, but rather just convinence or display glitter, the user must not
/// be burdened with implementing this. All methods must return `Option<T>` to ensure this.

pub trait SSAExtra: SSA {
    fn mark(&mut self, _: &Self::ValueRef) {}
    fn clear_mark(&mut self, &Self::ValueRef) {}
    fn set_color(&mut self, _: &Self::ValueRef, _: u8) {}
    fn set_comment(&mut self, _: &Self::ValueRef, _: String) {}
    fn add_flag(&mut self, _: &Self::ValueRef, _: String) {}
    fn is_marked(&self, _: &Self::ValueRef) -> bool {
        false
    }

    fn color(&self, _: &Self::ValueRef) -> Option<u8> {
        None
    }

    fn comments(&self, _: &Self::ValueRef) -> Option<String> {
        None
    }

    fn addr(&self, _: &Self::ValueRef) -> Option<String> {
        None
    }

    fn flags(&self, _: &Self::ValueRef) -> Option<String> {
        None
    }
}

pub trait SSAWalk<I: Iterator<Item = <Self as SSA>::ValueRef>>: SSA {
    fn bfs_walk(&self) -> I;
    fn inorder_walk(&self) -> I;
    fn dfs_walk(&self) -> I;
}
<|endoftext|>