<commit_before>extern crate walkdir;

use self::walkdir::{DirEntry as WalkDirEntry, WalkDir, WalkDirIterator};

use std::collections::BTreeSet;
use std::ffi::OsString;
use std::fs;
use std::io::Error as IoError;
use std::path::{Path, PathBuf};
use std::result::Result;

macro_rules! path_buf {
    ($($x: expr),+) => {
        PathBuf::new()
            $(.join($x))+
    };
}

pub fn ls<P: AsRef<Path>>(path: P) -> Result<Vec<String>, IoError> {
    let dirs = try!(fs::read_dir(path));
    let dirs = dirs
        .filter_map(Result::ok)
        .map(|d| d.file_name())
        .map(OsString::into_string)
        .filter_map(Result::ok)
        .collect::<Vec<String>>();
    Ok(dirs)
}

pub fn is_empty_dir<P: AsRef<Path>>(path: P) -> bool {
    match fs::read_dir(path) {
        Ok(rd) => rd.count() == 0,
        Err(_) => false,
    }
}

fn is_hidden_name(file_name: &str) -> bool {
    file_name.starts_with(".") && file_name.len() > 1 && file_name != ".."
}
#[test]
fn is_hidden_name_should_return_true() {
    let file_names = [
        ".a",
        ".ab",
        ".abc",
        "..a",
        "...",
    ];
    for file_name in &file_names {
        assert!(is_hidden_name(file_name));
    }
}
#[test]
fn is_hidden_name_should_return_false() {
    let file_names = [
        "",

        ".",
        "..",
        "a",
        "ab",
        "abc",
    ];
    for file_name in &file_names {
        assert!(!is_hidden_name(file_name));
    }
}

fn is_hidden(entry: &WalkDirEntry) -> bool {
    entry
        .file_name()
        .to_str()
        .map_or(false, is_hidden_name)
}

pub fn walk_dir<P: AsRef<Path>>(root: P) -> BTreeSet<String> {
    let walker = WalkDir::new(root)
        .into_iter()
        .filter_entry(|e| !is_hidden(e))
        .filter_map(Result::ok)
        .filter(|e| !e.file_type().is_dir())
        .collect::<Vec<WalkDirEntry>>();

    walker
        .into_iter()
        .filter_map(|e| e.path().to_str().map(|s| s.to_string()))
        .collect::<BTreeSet<String>>()
}

pub fn dirs_ordered_by_descending_depth<P: AsRef<Path>>(root: P) -> Vec<PathBuf> {
    let mut walker = WalkDir::new(root)
        .into_iter()
        .filter_entry(|e| !is_hidden(e))
        .filter_entry(|e| e.file_type().is_dir())
        .filter_map(Result::ok)
        .collect::<Vec<WalkDirEntry>>();

    walker.sort_by(|l, r| {
        let l_depth = &l.depth();
        let r_depth = &r.depth();
        r_depth.cmp(l_depth)
    });

    walker
        .into_iter()
        .map(|e| e.path().to_path_buf())
        .collect::<Vec<PathBuf>>()
}

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

    use std::collections::BTreeSet;
    use std::fs::{self, File};
    use std::io::Write;
    use std::path::{Path, PathBuf};

    struct Helper;
    impl Helper {
        fn d1() -> String { "directory1".to_string() }
        fn d2() -> String { "directory2".to_string() }
        fn d3() -> String { "directory3".to_string() }

        fn f1() -> String { "file1".to_string() }
        fn f2() -> String { "file2".to_string() }

        fn path_to_d1() -> PathBuf {
            PathBuf::new().join(Self::d1())
        }
        fn path_to_d2() -> PathBuf {
            Self::path_to_d1().join(Self::d2())
        }
        fn path_to_d3() -> PathBuf {
            Self::path_to_d2().join(Self::d3())
        }

        fn path_to_f1() -> PathBuf {
            Self::path_to_d1().join(Self::f1())
        }
        fn path_to_f2() -> PathBuf {
            Self::path_to_d2().join(Self::f2())
        }

        fn remove_dirs_and_files() {
            fs::remove_dir_all(Self::path_to_d1()).ok();
        }

        fn create_dirs_and_files() {
            Self::remove_dirs_and_files();

            fs::create_dir_all(Self::path_to_d3()).ok();

            let mut f = File::create(Self::path_to_f1()).unwrap();
            f.write("\n".as_ref()).ok();
            fs::copy(Self::path_to_f1(), Self::path_to_f2()).ok();
        }

        fn to_string_forcely(path: PathBuf) -> String {
            path.to_str().unwrap().to_string()
        }
    }

    #[test]
    fn path_buf_macro_should_create_path_buf() {
        let paths = [
            (Path::new("path").to_path_buf()          , path_buf!["path"              ]),
            (Path::new("path").join("to")             , path_buf!["path", "to"        ]),
            (Path::new("path").join("to").join("file"), path_buf!["path", "to", "file"]),
        ];
        for &(ref correct, ref calculated) in &paths {
            assert_eq!(correct, calculated);
        }
    }

    #[test]
    fn ls_should_return_ok() {
        Helper::create_dirs_and_files();

        let empty_vec: Vec<String> = Vec::new();

        assert_eq!(vec![Helper::d2(), Helper::f1()], ls(Helper::path_to_d1()).unwrap());
        assert_eq!(vec![Helper::d3(), Helper::f2()], ls(Helper::path_to_d2()).unwrap());
        assert_eq!(empty_vec                       , ls(Helper::path_to_d3()).unwrap());

        Helper::remove_dirs_and_files();
    }

    #[test]
    fn is_empty_dir_should_return_true() {
        Helper::create_dirs_and_files();

        assert!(is_empty_dir(Helper::path_to_d3()));

        Helper::remove_dirs_and_files();
    }
    #[test]
    fn is_empty_dir_should_return_false() {
        Helper::create_dirs_and_files();

        assert!(!is_empty_dir(Helper::path_to_d1()));
        assert!(!is_empty_dir(Helper::path_to_d2()));

        Helper::remove_dirs_and_files();
    }

    #[test]
    fn walk_dir_should_return_b_tree_set() {
        Helper::create_dirs_and_files();

        let mut correct = BTreeSet::new();
        correct.insert(Helper::to_string_forcely(Helper::path_to_f1()));
        correct.insert(Helper::to_string_forcely(Helper::path_to_f2()));

        assert_eq!(correct, walk_dir(Helper::path_to_d1()));

        Helper::remove_dirs_and_files();
    }

    #[test]
    fn dirs_ordered_by_descending_depth_should_return_vec() {
        Helper::create_dirs_and_files();

        let correct = vec![Helper::path_to_d3(), Helper::path_to_d2(), Helper::path_to_d1()];

        assert_eq!(correct, dirs_ordered_by_descending_depth(Helper::path_to_d1()));

        Helper::remove_dirs_and_files();
    }
}
<commit_msg>[Test] Success to run test on async<commit_after>extern crate walkdir;

use self::walkdir::{DirEntry as WalkDirEntry, WalkDir, WalkDirIterator};

use std::collections::BTreeSet;
use std::ffi::OsString;
use std::fs;
use std::io::Error as IoError;
use std::path::{Path, PathBuf};
use std::result::Result;

macro_rules! path_buf {
    ($($x: expr),+) => {
        PathBuf::new()
            $(.join($x))+
    };
}

pub fn ls<P: AsRef<Path>>(path: P) -> Result<Vec<String>, IoError> {
    let dirs = try!(fs::read_dir(path));
    let dirs = dirs
        .filter_map(Result::ok)
        .map(|d| d.file_name())
        .map(OsString::into_string)
        .filter_map(Result::ok)
        .collect::<Vec<String>>();
    Ok(dirs)
}

pub fn is_empty_dir<P: AsRef<Path>>(path: P) -> bool {
    match fs::read_dir(path) {
        Ok(rd) => rd.count() == 0,
        Err(_) => false,
    }
}

fn is_hidden_name(file_name: &str) -> bool {
    file_name.starts_with(".") && file_name.len() > 1 && file_name != ".."
}
#[test]
fn is_hidden_name_should_return_true() {
    let file_names = [
        ".a",
        ".ab",
        ".abc",
        "..a",
        "...",
    ];
    for file_name in &file_names {
        assert!(is_hidden_name(file_name));
    }
}
#[test]
fn is_hidden_name_should_return_false() {
    let file_names = [
        "",

        ".",
        "..",
        "a",
        "ab",
        "abc",
    ];
    for file_name in &file_names {
        assert!(!is_hidden_name(file_name));
    }
}

fn is_hidden(entry: &WalkDirEntry) -> bool {
    entry
        .file_name()
        .to_str()
        .map_or(false, is_hidden_name)
}

pub fn walk_dir<P: AsRef<Path>>(root: P) -> BTreeSet<String> {
    let walker = WalkDir::new(root)
        .into_iter()
        .filter_entry(|e| !is_hidden(e))
        .filter_map(Result::ok)
        .filter(|e| !e.file_type().is_dir())
        .collect::<Vec<WalkDirEntry>>();

    walker
        .into_iter()
        .filter_map(|e| e.path().to_str().map(|s| s.to_string()))
        .collect::<BTreeSet<String>>()
}

pub fn dirs_ordered_by_descending_depth<P: AsRef<Path>>(root: P) -> Vec<PathBuf> {
    let mut walker = WalkDir::new(root)
        .into_iter()
        .filter_entry(|e| !is_hidden(e))
        .filter_entry(|e| e.file_type().is_dir())
        .filter_map(Result::ok)
        .collect::<Vec<WalkDirEntry>>();

    walker.sort_by(|l, r| {
        let l_depth = &l.depth();
        let r_depth = &r.depth();
        r_depth.cmp(l_depth)
    });

    walker
        .into_iter()
        .map(|e| e.path().to_path_buf())
        .collect::<Vec<PathBuf>>()
}

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

    use std::collections::BTreeSet;
    use std::fs::{self, File};
    use std::io::Write;
    use std::path::{Path, PathBuf};

    struct Helper {
        d1: String,
        d2: String,
        d3: String,
        f1: String,
        f2: String,
    }
    impl Helper {
        fn new(suffix: &str) -> Self {
            Helper {
                d1: format!("directory1_{}", suffix),
                d2: format!("directory2_{}", suffix),
                d3: format!("directory3_{}", suffix),
                f1: format!("file1_{}"     , suffix),
                f2: format!("file2_{}"     , suffix),
            }
        }

        fn path_to_d1(&self) -> PathBuf {
            PathBuf::new().join(&self.d1)
        }
        fn path_to_d2(&self) -> PathBuf {
            self.path_to_d1().join(&self.d2)
        }
        fn path_to_d3(&self) -> PathBuf {
            self.path_to_d2().join(&self.d3)
        }

        fn path_to_f1(&self) -> PathBuf {
            self.path_to_d1().join(&self.f1)
        }
        fn path_to_f2(&self) -> PathBuf {
            self.path_to_d2().join(&self.f2)
        }

        fn remove_dirs_and_files(&self) {
            fs::remove_dir_all(self.path_to_d1()).ok();
        }

        fn create_dirs_and_files(&self) {
            self.remove_dirs_and_files();

            fs::create_dir_all(self.path_to_d3()).ok();

            let mut f = File::create(self.path_to_f1()).unwrap();
            f.write("\n".as_ref()).ok();
            fs::copy(self.path_to_f1(), self.path_to_f2()).ok();
        }

        fn to_string_forcely(path: PathBuf) -> String {
            path.to_str().unwrap().to_string()
        }
    }

    #[test]
    fn path_buf_macro_should_create_path_buf() {
        let paths = [
            (Path::new("path").to_path_buf()          , path_buf!["path"              ]),
            (Path::new("path").join("to")             , path_buf!["path", "to"        ]),
            (Path::new("path").join("to").join("file"), path_buf!["path", "to", "file"]),
        ];
        for &(ref correct, ref calculated) in &paths {
            assert_eq!(correct, calculated);
        }
    }

    #[test]
    fn ls_should_return_ok() {
        let helper = Helper::new("ls_Ok");
        helper.create_dirs_and_files();

        let empty_vec: Vec<String> = Vec::new();

        assert_eq!(vec![helper.d2.clone(), helper.f1.clone()], ls(helper.path_to_d1()).unwrap());
        assert_eq!(vec![helper.d3.clone(), helper.f2.clone()], ls(helper.path_to_d2()).unwrap());
        assert_eq!(empty_vec                                 , ls(helper.path_to_d3()).unwrap());

        helper.remove_dirs_and_files();
    }

    #[test]
    fn is_empty_dir_should_return_true() {
        let helper = Helper::new("is_empty_dir_true");
        helper.create_dirs_and_files();

        assert!(is_empty_dir(helper.path_to_d3()));

        helper.remove_dirs_and_files();
    }
    #[test]
    fn is_empty_dir_should_return_false() {
        let helper = Helper::new("is_empty_dir_false");
        helper.create_dirs_and_files();

        assert!(!is_empty_dir(helper.path_to_d1()));
        assert!(!is_empty_dir(helper.path_to_d2()));

        helper.remove_dirs_and_files();
    }

    #[test]
    fn walk_dir_should_return_b_tree_set() {
        let helper = Helper::new("walk_dir_BTreeSet");
        helper.create_dirs_and_files();

        let mut correct = BTreeSet::new();
        correct.insert(Helper::to_string_forcely(helper.path_to_f1()));
        correct.insert(Helper::to_string_forcely(helper.path_to_f2()));

        assert_eq!(correct, walk_dir(helper.path_to_d1()));

        helper.remove_dirs_and_files();
    }

    #[test]
    fn dirs_ordered_by_descending_depth_should_return_vec() {
        let helper = Helper::new("dirs_ordered_by_descending_depth_Vec");
        helper.create_dirs_and_files();

        let correct = vec![helper.path_to_d3(), helper.path_to_d2(), helper.path_to_d1()];

        assert_eq!(correct, dirs_ordered_by_descending_depth(helper.path_to_d1()));

        helper.remove_dirs_and_files();
    }
}
<|endoftext|>


<commit_before>#![allow(uppercase_variables)]

//! A few linear algebra operations on two-dimensional arrays.

use std::num::{zero, one, Zero, One};

use super::{Array, Ix};

/// Column vector.
pub type Col = Array;
/// Rectangular matrix.
pub type Mat = Array;

/// Return the identity matrix of dimension *n*.
pub fn eye(n: Ix) -> Mat
{
    let mut eye = Array::zeros((n, n));
    for a_ii in eye.diag_iter_mut() {
        *a_ii = one::();
    }
    eye
}

/*
/// Return the inverse matrix of square matrix `a`.
pub fn inverse(a: &Mat) -> Mat
{
    fail!()
}
*/

/// Solve *a x = b* with linear least squares approximation.
///
/// It is used to find the best fit for an overdetermined system,
/// i.e. the number of rows in *a* is larger than the number of
/// unknowns *x*.
///
/// Return best fit for *x*.
pub fn least_squares(a: &Mat, b: &Col) -> Col
{
    // Using transpose: a.T a x = a.T b;
    // a.T a being square gives naive solution
    // x_lstsq = inv(a.T a) a.T b
    //
    // Solve using cholesky decomposition
    // aT a x = aT b
    //
    // Factor aT a into L L.T
    //
    // L L.T x = aT b
    //
    // => L z = aT b
    //  fw subst for z
    // => L.T x = z
    //  bw subst for x estimate
    //
    let mut aT = a.clone();
    aT.swap_axes(0, 1);

    let aT_a = aT.mat_mul(a);
    let mut L = cholesky(aT_a);
    let rhs = aT.mat_mul_col(b);

    // Solve L z = aT b
    let z = subst_fw(&L, &rhs);

    // Solve L.T x = z
    L.swap_axes(0, 1);
    let x_lstsq = subst_bw(&L, &z);
    x_lstsq
}

/// Factor *a = L LT*.
///
/// *a* should be a square matrix, hermitian and positive definite.
///
/// https://en.wikipedia.org/wiki/Cholesky_decomposition
///
/// “The Cholesky decomposition is mainly used for the numerical solution of
/// linear equations Ax = b.
///
/// If A is symmetric and positive definite, then we can solve Ax = b by first
/// computing the Cholesky decomposition A = LL*, then solving Ly = b for y by
/// forward substitution, and finally solving L*x = y for x by back
/// substitution.”
///
/// Return L.
pub fn cholesky(a: Mat) -> Mat
{
    let z = zero::();
    let (m, n) = a.dim();
    assert!(m == n);
    // Perform the operation in-place on `a`
    let mut L = a;
    for i in range(0, m) {
        // Entries 0 .. i before the diagonal
        for j in range(0, i) {
            // A = (
            // L²_1,1
            // L_2,1 L_1,1  L²_2,1 + L²_2,2
            // L_3,1 L_1,1  L_3,1 L_2,1 + L_3,2 L_2,2  L²_3,1 + L²_3,2 + L²_3,3
            // .. )
            let mut lik_ljk_sum = z.clone();
            {
                // L_ik for k = 0 .. j
                // L_jk for k = 0 .. j
                let Lik = L.row_iter(i);
                let Ljk = L.row_iter(j);
                for (&lik, &ljk) in Lik.zip(Ljk).take(j) {
                    lik_ljk_sum = lik_ljk_sum + lik * ljk;
                }
            }

            // L_ij = A_ij - Sum(k = 1 .. j) L_ik L_jk
            L[(i, j)] = (L[(i, j)] - lik_ljk_sum) / L[(j, j)];
        }

        // Diagonal where i == j
        // L_jj = Sqrt[ A_jj - Sum(k = 1 .. j) L_jk L_jk ]
        let j = i;
        let mut ljk_sum = z.clone();
        // L_jk for k = 0 .. j
        for &ljk in L.row_iter(j).take(j) {
            ljk_sum = ljk_sum + ljk * ljk;
        }
        L[(j, j)] = (L[(j, j)] - ljk_sum).sqrt();

        // After the diagonal
        // L_ij = 0 for j > i
        for j in range(i + 1, n) {
            L[(i, j)] = z.clone();
        }
    }
    L
}

/// Solve *L x = b* where *L* is a lower triangular matrix.
pub fn subst_fw(l: &Mat, b: &Col) -> Col
{
    let (m, n) = l.dim();
    assert!(m == n);
    assert!(m == b.dim());
    let mut x = Vec::from_elem(m, zero::());
    for (i, bi) in b.indexed_iter() {
        // b_lx_sum = b[i] - Sum(for j = 0 .. i) L_ij x_j
        let mut b_lx_sum = bi.clone();
        for (lij, xj) in l.row_iter(i).zip(x.iter()).take(i) {
            b_lx_sum = b_lx_sum - (*lij) * (*xj)
        }
        x.as_mut_slice()[i] = b_lx_sum / l[(i, i)];
    }
    Array::from_vec(x)
}

/// Solve *U x = b* where *U* is an upper triangular matrix.
pub fn subst_bw(u: &Mat, b: &Col) -> Col
{
    let (m, n) = u.dim();
    assert!(m == n);
    assert!(m == b.dim());
    let mut x = Vec::from_elem(m, zero::());
    for i in range(0, m).rev() {
        // b_ux_sum = b[i] - Sum(for j = i .. m) U_ij x_j
        let mut b_ux_sum = b[i].clone();
        for (uij, xj) in u.row_iter(i).rev().zip(x.iter().rev()).take(m - i - 1) {
            b_ux_sum = b_ux_sum - (*uij) * (*xj);
        }
        x.as_mut_slice()[i] = b_ux_sum / u[(i, i)];
    }
    Array::from_vec(x)
}
<commit_msg>linalg: Fix omission in comment<commit_after>#![allow(uppercase_variables)]

//! A few linear algebra operations on two-dimensional arrays.

use std::num::{zero, one, Zero, One};

use super::{Array, Ix};

/// Column vector.
pub type Col = Array;
/// Rectangular matrix.
pub type Mat = Array;

/// Return the identity matrix of dimension *n*.
pub fn eye(n: Ix) -> Mat
{
    let mut eye = Array::zeros((n, n));
    for a_ii in eye.diag_iter_mut() {
        *a_ii = one::();
    }
    eye
}

/*
/// Return the inverse matrix of square matrix `a`.
pub fn inverse(a: &Mat) -> Mat
{
    fail!()
}
*/

/// Solve *a x = b* with linear least squares approximation.
///
/// It is used to find the best fit for an overdetermined system,
/// i.e. the number of rows in *a* is larger than the number of
/// unknowns *x*.
///
/// Return best fit for *x*.
pub fn least_squares(a: &Mat, b: &Col) -> Col
{
    // Using transpose: a.T a x = a.T b;
    // a.T a being square gives naive solution
    // x_lstsq = inv(a.T a) a.T b
    //
    // Solve using cholesky decomposition
    // aT a x = aT b
    //
    // Factor aT a into L L.T
    //
    // L L.T x = aT b
    //
    // => L z = aT b
    //  fw subst for z
    // => L.T x = z
    //  bw subst for x estimate
    //
    let mut aT = a.clone();
    aT.swap_axes(0, 1);

    let aT_a = aT.mat_mul(a);
    let mut L = cholesky(aT_a);
    let rhs = aT.mat_mul_col(b);

    // Solve L z = aT b
    let z = subst_fw(&L, &rhs);

    // Solve L.T x = z
    L.swap_axes(0, 1);
    let x_lstsq = subst_bw(&L, &z);
    x_lstsq
}

/// Factor *a = L LT*.
///
/// *a* should be a square matrix, hermitian and positive definite.
///
/// https://en.wikipedia.org/wiki/Cholesky_decomposition
///
/// “The Cholesky decomposition is mainly used for the numerical solution of
/// linear equations Ax = b.
///
/// If A is symmetric and positive definite, then we can solve Ax = b by first
/// computing the Cholesky decomposition A = LL*, then solving Ly = b for y by
/// forward substitution, and finally solving L*x = y for x by back
/// substitution.”
///
/// Return L.
pub fn cholesky(a: Mat) -> Mat
{
    let z = zero::();
    let (m, n) = a.dim();
    assert!(m == n);
    // Perform the operation in-place on `a`
    let mut L = a;
    for i in range(0, m) {
        // Entries 0 .. i before the diagonal
        for j in range(0, i) {
            // A = (
            // L²_1,1
            // L_2,1 L_1,1  L²_2,1 + L²_2,2
            // L_3,1 L_1,1  L_3,1 L_2,1 + L_3,2 L_2,2  L²_3,1 + L²_3,2 + L²_3,3
            // .. )
            let mut lik_ljk_sum = z.clone();
            {
                // L_ik for k = 0 .. j
                // L_jk for k = 0 .. j
                let Lik = L.row_iter(i);
                let Ljk = L.row_iter(j);
                for (&lik, &ljk) in Lik.zip(Ljk).take(j) {
                    lik_ljk_sum = lik_ljk_sum + lik * ljk;
                }
            }

            // L_ij = [ A_ij - Sum(k = 1 .. j) L_ik L_jk ] / L_jj
            L[(i, j)] = (L[(i, j)] - lik_ljk_sum) / L[(j, j)];
        }

        // Diagonal where i == j
        // L_jj = Sqrt[ A_jj - Sum(k = 1 .. j) L_jk L_jk ]
        let j = i;
        let mut ljk_sum = z.clone();
        // L_jk for k = 0 .. j
        for &ljk in L.row_iter(j).take(j) {
            ljk_sum = ljk_sum + ljk * ljk;
        }
        L[(j, j)] = (L[(j, j)] - ljk_sum).sqrt();

        // After the diagonal
        // L_ij = 0 for j > i
        for j in range(i + 1, n) {
            L[(i, j)] = z.clone();
        }
    }
    L
}

/// Solve *L x = b* where *L* is a lower triangular matrix.
pub fn subst_fw(l: &Mat, b: &Col) -> Col
{
    let (m, n) = l.dim();
    assert!(m == n);
    assert!(m == b.dim());
    let mut x = Vec::from_elem(m, zero::());
    for (i, bi) in b.indexed_iter() {
        // b_lx_sum = b[i] - Sum(for j = 0 .. i) L_ij x_j
        let mut b_lx_sum = bi.clone();
        for (lij, xj) in l.row_iter(i).zip(x.iter()).take(i) {
            b_lx_sum = b_lx_sum - (*lij) * (*xj)
        }
        x.as_mut_slice()[i] = b_lx_sum / l[(i, i)];
    }
    Array::from_vec(x)
}

/// Solve *U x = b* where *U* is an upper triangular matrix.
pub fn subst_bw(u: &Mat, b: &Col) -> Col
{
    let (m, n) = u.dim();
    assert!(m == n);
    assert!(m == b.dim());
    let mut x = Vec::from_elem(m, zero::());
    for i in range(0, m).rev() {
        // b_ux_sum = b[i] - Sum(for j = i .. m) U_ij x_j
        let mut b_ux_sum = b[i].clone();
        for (uij, xj) in u.row_iter(i).rev().zip(x.iter().rev()).take(m - i - 1) {
            b_ux_sum = b_ux_sum - (*uij) * (*xj);
        }
        x.as_mut_slice()[i] = b_ux_sum / u[(i, i)];
    }
    Array::from_vec(x)
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;

use ll;
use ll::limb::Limb;

pub unsafe fn gcd(gp: *mut Limb, mut ap: *mut Limb, mut an: i32, mut bp: *mut Limb, mut bn: i32) -> i32 {
    assert!(an >= bn);

    let mut gc = 0;
    while *ap == 0 && !ll::is_zero(ap, an) && *bp == 0 && !ll::is_zero(bp, bn){
        ap = ap.offset(1);
        bp = bp.offset(1);
        an -= 1;
        bn -= 1;
        gc += 1;
    }

    let a_trailing = (*ap).trailing_zeros() as u32;
    let b_trailing = (*bp).trailing_zeros() as u32;

    let trailing = if a_trailing < b_trailing {
        a_trailing
    } else {
        b_trailing
    };

    if trailing > 0 {
        ll::shr(ap, ap, an, trailing);
        ll::shr(bp, bp, bn, trailing);
    }

    ll::copy_incr(bp, gp, bn);
    bp = gp;

    while !ll::is_zero(ap, an) {

        while *ap == 0 && !ll::is_zero(ap, an) {
            ap = ap.offset(1);
            an -= 1;
        }

        let at = (*ap).trailing_zeros() as u32;
        if at > 0 {
            ll::shr(ap, ap, an, at);
        }

        while *bp == 0 && !ll::is_zero(bp, bn) {
            bp = bp.offset(1);
            bn -= 1;
        }

        let bt = (*bp).trailing_zeros() as u32;
        if bt > 0 {
            ll::shr(bp, bp, bn, bt);
        }

        let c = ll::cmp(ap, bp, an);

        // FIXME find better way to compute |ap - bp| / 2
        if c == Ordering::Equal || c == Ordering::Greater {
            ll::sub(ap, ap, an, bp, bn);
            ll::shr(ap, ap, an, 1);
        } else {
            ll::sub(gp, bp, an, ap, an);
            ll::shr(gp, gp, an, 1);
            bp = gp;
        }
    }

    // FIXME what's the best way for the left shift, using offset
    let gn = (gc + 1) as i32;
    for _ in 0..gc {
        ll::shl(gp, gp, gn, (Limb::BITS - 1) as u32);
        ll::shl(gp, gp, gn, 1);
    }
    if trailing > 0 {
        ll::shl(gp, gp, gn, trailing);
    }

    gn
}
<commit_msg>Fix length of g<commit_after>use std::cmp::Ordering;

use ll;
use ll::limb::Limb;

pub unsafe fn gcd(gp: *mut Limb, mut ap: *mut Limb, mut an: i32, mut bp: *mut Limb, mut bn: i32) -> i32 {
    assert!(an >= bn);

    let mut gc = 0;
    while *ap == 0 && !ll::is_zero(ap, an) && *bp == 0 && !ll::is_zero(bp, bn){
        ap = ap.offset(1);
        bp = bp.offset(1);
        an -= 1;
        bn -= 1;
        gc += 1;
    }

    let a_trailing = (*ap).trailing_zeros() as u32;
    let b_trailing = (*bp).trailing_zeros() as u32;

    let trailing = if a_trailing < b_trailing {
        a_trailing
    } else {
        b_trailing
    };

    if trailing > 0 {
        ll::shr(ap, ap, an, trailing);
        ll::shr(bp, bp, bn, trailing);
    }

    ll::copy_incr(bp, gp, bn);
    bp = gp;

    while !ll::is_zero(ap, an) {

        while *ap == 0 && !ll::is_zero(ap, an) {
            ap = ap.offset(1);
            an -= 1;
        }

        let at = (*ap).trailing_zeros() as u32;
        if at > 0 {
            ll::shr(ap, ap, an, at);
        }

        while *bp == 0 && !ll::is_zero(bp, bn) {
            bp = bp.offset(1);
            bn -= 1;
        }

        let bt = (*bp).trailing_zeros() as u32;
        if bt > 0 {
            ll::shr(bp, bp, bn, bt);
        }

        let c = ll::cmp(ap, bp, an);

        // FIXME find better way to compute |ap - bp| / 2
        if c == Ordering::Equal || c == Ordering::Greater {
            ll::sub(ap, ap, an, bp, bn);
            ll::shr(ap, ap, an, 1);
        } else {
            ll::sub(gp, bp, an, ap, an);
            ll::shr(gp, gp, an, 1);
            bp = gp;
        }
    }

    // FIXME what's the best way for the left shift, using offset
    let gn = bn + gc;
    for _ in 0..gc {
        ll::shl(gp, gp, gn, (Limb::BITS - 1) as u32);
        ll::shl(gp, gp, gn, 1);
    }
    if trailing > 0 {
        ll::shl(gp, gp, gn, trailing);
    }

    gn
}
<|endoftext|>


<commit_before>/// Compose multiple state machines into single type
///
/// Composition requires two types: the state machine itself and Seed which
/// is used to create children state machines.
///
/// Mostly because of limitations of Rust macro system composition only works
/// on concrete context type.
///
/// # Example
/// ```ignore
/// rotor_compose!{
///     pub enum Fsm/Seed<Context> {
///         Http(HttpMachine)
///         Dns(DnsMachine)
///     }
/// }
/// ```
///
/// This creates a an `Fsm` state machine type which is enum with two options.
/// And `Seed` state machine type, which is also enum with same option names
/// but uses `<HttpMachine as rotor::Machine>::Seed` for the wrapped type.
#[macro_export]
macro_rules! rotor_compose {
    /* TODO(tailhook) make and check generic combinators
    (pub enum $name:ident { $($x:ident ($y:ty),)* }) => {
        pub enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name C [] $($x($y),)*);
    };
    (enum $name:ident { $($x:ident ($y:ty),)* }) => {
        enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name $($x($y),)*);
    };
    */
    (pub enum $name:ident/$cname:ident <$context_type:ident>
        { $($x:ident ($y:ty),)* })
    => {
        pub enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name/$cname
            $context_type [] $($x($y),)*);
    };
    (enum $name:ident/$cname:ident <$context_type:ident>
        { $($x:ident ($y:ty),)* })
    => {
        enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name/$cname
            $context_type [] $($x($y),)*);
    };
    (@machine $name:ident/$cname:ident $ctx_typ:ident
        [ $(<$ctx_name:ident $(: $ctx_bound:ident)*>)* ]
        $($iname:ident ($itype:ty),)*)
    => {
        enum $cname {
            $( $iname (<$itype as $crate::Machine>::Seed), )*
        }
        impl $( <$ctx_name:$ctx_bound> )* $crate::Machine for $name {
            type Context = $ctx_typ;
            type Seed = $cname;
            fn create(seed: $cname, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, $crate::Void>
            {
                match seed {
                    $( $cname::$iname (x)
                        => $crate::Machine::create(x, scope)
                            .map($name::$iname,
                                 |x| $crate::void::unreachable(x)),
                    )*
                }
            }
            fn ready(self, events: $crate::EventSet,
                scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.ready(events, scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
            fn spawned(self, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.spawned(scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
            fn timeout(self, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.timeout(scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
            fn wakeup(self, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.wakeup(scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
        }

    }
}
<commit_msg>Fix `rotor_compose` for public enums for rust 1.7<commit_after>/// Compose multiple state machines into single type
///
/// Composition requires two types: the state machine itself and Seed which
/// is used to create children state machines.
///
/// Mostly because of limitations of Rust macro system composition only works
/// on concrete context type.
///
/// # Example
/// ```ignore
/// rotor_compose!{
///     pub enum Fsm/Seed<Context> {
///         Http(HttpMachine)
///         Dns(DnsMachine)
///     }
/// }
/// ```
///
/// This creates a an `Fsm` state machine type which is enum with two options.
/// And `Seed` state machine type, which is also enum with same option names
/// but uses `<HttpMachine as rotor::Machine>::Seed` for the wrapped type.
#[macro_export]
macro_rules! rotor_compose {
    /* TODO(tailhook) make and check generic combinators
    (pub enum $name:ident { $($x:ident ($y:ty),)* }) => {
        pub enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name C [] $($x($y),)*);
    };
    (enum $name:ident { $($x:ident ($y:ty),)* }) => {
        enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name $($x($y),)*);
    };
    */
    (pub enum $name:ident/$cname:ident <$context_type:ident>
        { $($x:ident ($y:ty),)* })
    => {
        pub enum $name { $($x ($y),)* }
        pub enum $cname {
            $( $x (<$y as $crate::Machine>::Seed), )*
        }
        rotor_compose!(@machine $name/$cname
            $context_type [] $($x($y),)*);
    };
    (enum $name:ident/$cname:ident <$context_type:ident>
        { $($x:ident ($y:ty),)* })
    => {
        enum $name { $($x ($y),)* }
        enum $cname {
            $( $x (<$y as $crate::Machine>::Seed), )*
        }
        rotor_compose!(@machine $name/$cname
            $context_type [] $($x($y),)*);
    };
    (@machine $name:ident/$cname:ident $ctx_typ:ident
        [ $(<$ctx_name:ident $(: $ctx_bound:ident)*>)* ]
        $($iname:ident ($itype:ty),)*)
    => {
        impl $( <$ctx_name:$ctx_bound> )* $crate::Machine for $name {
            type Context = $ctx_typ;
            type Seed = $cname;
            fn create(seed: $cname, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, $crate::Void>
            {
                match seed {
                    $( $cname::$iname (x)
                        => $crate::Machine::create(x, scope)
                            .map($name::$iname,
                                 |x| $crate::void::unreachable(x)),
                    )*
                }
            }
            fn ready(self, events: $crate::EventSet,
                scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.ready(events, scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
            fn spawned(self, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.spawned(scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
            fn timeout(self, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.timeout(scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
            fn wakeup(self, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.wakeup(scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
        }

    }
}
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Mattis Marjak (mattis.marjak@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#[macro_export]
macro_rules! hsm_define_objects {
    ($st_str:ident, $st_en:ident, $st_evt:ty, $shr_dat:ident, ( $($s:ident),* ) ) => {
        use $crate::Parent;
        _hsm_create_states!($($s),*);
        _hsm_create_state_enum!($st_en, ($($s),*));
        _hsm_create_state_struct!($st_str, $st_en, $st_evt, $shr_dat, ($($s),*) );
    };
    ($st_str:ident, $st_en:ident, $st_evt:ty, $shr_dat:ident, ( $($s:ident $x:tt),*)) => {
        use $crate::Parent;
        _hsm_create_states!( $($s $x),* );
        _hsm_create_state_enum!($st_en, ($($s),*));
        _hsm_create_state_struct!($st_str, $st_en, $st_evt, $shr_dat, ($($s),*) );
    }
}

#[macro_export]
macro_rules! hsm_delayed_transition {
    ($probe:ident, $x:block) => {
        match $probe {
            true  => $crate::Action::DelayedTransition,
            false => $crate::Action::Transition($x)
        }
    }
}

#[macro_export]
macro_rules! hsm_impl_state {
    ($state:ident, $events:ident, $states:ident, $shr_data:ident, $($pat:pat => $result:expr),*) => {
        impl $crate::State<$events, $states, $shr_data> for $state {
            #[allow(unused_variables)]
            fn handle_event(&mut self, shr_data: &mut $shr_data, evt: $crate::Event<$events>, probe: bool) -> $crate::Action<$states> {
                match evt {
                    $( $pat => $result),*
                }
            }
        }
    }
}

#[macro_export]
macro_rules! hsm_state_parents {
    ($st_en:ident ; $($nam:ident -> $parent:ident),*) => {
        $(_hsm_impl_state_parent!($st_en ; $nam -> $parent);)*
    }
}

#[macro_export]
macro_rules! _hsm_impl_state_parent {
    ($st_en:ident ; $nam:ident -> None) => {
        impl $crate::Parent<$st_en> for $nam {
            fn get_parent() -> Option<$st_en> { None }
        }
    };
    ($st_en:ident ; $nam:ident -> $parent:ident) => {
        impl $crate::Parent<$st_en> for $nam {
            fn get_parent() -> Option<$st_en> { Some($st_en::$parent) }
        }
    }
}

#[macro_export]
macro_rules! _hsm_create_states {
    ( $($s:ident),* ) => {
        $(_hsm_create_state!($s);)*
    };
    ($($s:ident $x:tt),*) => {
        $(_hsm_create_state!($s $x);)*
    }
}

#[macro_export]
macro_rules! _hsm_create_state_common {
    ($nam:ident) => {
        impl $crate::Name for $nam {
            fn name(&self) -> &'static str {
                stringify!($nam)
            }
        }
    }
}

#[macro_export]
macro_rules! _hsm_create_state {
    ($nam:ident) => {
        #[derive(Debug)]
        struct $nam;
        impl $crate::Initializer for $nam {
            fn new() -> Self {
                $nam;
            }
        }
        _hsm_create_state_common!($nam);
    };
    ($nam:ident { $($field_name:ident : $field_type:ty = $field_default:expr),* }) => {
        #[derive(Debug)]
        struct $nam {
            _phantom        : ::std::marker::PhantomData<u8>,
            $( $field_name  : $field_type ),*
        }
        impl $crate::Initializer for $nam {
            fn new() -> Self {
                $nam {
                    _phantom        : ::std::marker::PhantomData,
                    $( $field_name  : $field_default ),*
                }
            }
        }
        _hsm_create_state_common!($nam);
    }
}

#[macro_export]
macro_rules! _hsm_create_state_enum {
    ($st_en:ident, ($($s:ident),*) ) => {
        #[derive(Debug, Clone, Eq, PartialEq)]
        enum $st_en {
            $( $s ),*
        }
        impl ::std::fmt::Display for $st_en {
            fn fmt(&self, f:&mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
                match *self {
                    $( $st_en::$s => try!(::std::fmt::Display::fmt(stringify!($s), f)) ),*
                };
                Ok(())
            }
        }
        impl $crate::InstanceParent<$st_en> for $st_en {
            fn get_parent(&self) -> Option<$st_en> {
                match *self {
                    $( $st_en::$s => $s::get_parent() ),*
                }
            }
        }
    }
}

#[macro_export]
macro_rules! _hsm_create_state_struct {
    ($st_str:ident, $st_en:ident, $st_evt:ty, $shr_dat:ident, ($($s:ident),*) ) => {
        #[derive(Debug)]
        #[allow(non_snake_case)]
        struct $st_str {
            $( $s : $s ),*
        }
        impl $crate::Initializer for $st_str {
            fn new() -> Self {
                $st_str {
                    $( $s : $s::new() ),*
                }
            }
        }
        impl $crate::StateLookup<$st_en, $st_evt, $shr_dat> for $st_str {
            fn lookup(&mut self, typ: &$st_en) -> &mut $crate::State<$st_evt, $st_en, $shr_dat> {
                match *typ {
                    $($st_en::$s => &mut self.$s ),*
                }
            }
        }
    }
}
<commit_msg>fix state initializer creation macro<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Mattis Marjak (mattis.marjak@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#[macro_export]
macro_rules! hsm_define_objects {
    ($st_str:ident, $st_en:ident, $st_evt:ty, $shr_dat:ident, ( $($s:ident),* ) ) => {
        use $crate::Parent;
        _hsm_create_states!($($s),*);
        _hsm_create_state_enum!($st_en, ($($s),*));
        _hsm_create_state_struct!($st_str, $st_en, $st_evt, $shr_dat, ($($s),*) );
    };
    ($st_str:ident, $st_en:ident, $st_evt:ty, $shr_dat:ident, ( $($s:ident $x:tt),*)) => {
        use $crate::Parent;
        _hsm_create_states!( $($s $x),* );
        _hsm_create_state_enum!($st_en, ($($s),*));
        _hsm_create_state_struct!($st_str, $st_en, $st_evt, $shr_dat, ($($s),*) );
    }
}

#[macro_export]
macro_rules! hsm_delayed_transition {
    ($probe:ident, $x:block) => {
        match $probe {
            true  => $crate::Action::DelayedTransition,
            false => $crate::Action::Transition($x)
        }
    }
}

#[macro_export]
macro_rules! hsm_impl_state {
    ($state:ident, $events:ident, $states:ident, $shr_data:ident, $($pat:pat => $result:expr),*) => {
        impl $crate::State<$events, $states, $shr_data> for $state {
            #[allow(unused_variables)]
            fn handle_event(&mut self, shr_data: &mut $shr_data, evt: $crate::Event<$events>, probe: bool) -> $crate::Action<$states> {
                match evt {
                    $( $pat => $result),*
                }
            }
        }
    }
}

#[macro_export]
macro_rules! hsm_state_parents {
    ($st_en:ident ; $($nam:ident -> $parent:ident),*) => {
        $(_hsm_impl_state_parent!($st_en ; $nam -> $parent);)*
    }
}

#[macro_export]
macro_rules! _hsm_impl_state_parent {
    ($st_en:ident ; $nam:ident -> None) => {
        impl $crate::Parent<$st_en> for $nam {
            fn get_parent() -> Option<$st_en> { None }
        }
    };
    ($st_en:ident ; $nam:ident -> $parent:ident) => {
        impl $crate::Parent<$st_en> for $nam {
            fn get_parent() -> Option<$st_en> { Some($st_en::$parent) }
        }
    }
}

#[macro_export]
macro_rules! _hsm_create_states {
    ( $($s:ident),* ) => {
        $(_hsm_create_state!($s);)*
    };
    ($($s:ident $x:tt),*) => {
        $(_hsm_create_state!($s $x);)*
    }
}

#[macro_export]
macro_rules! _hsm_create_state_common {
    ($nam:ident) => {
        impl $crate::Name for $nam {
            fn name(&self) -> &'static str {
                stringify!($nam)
            }
        }
    }
}

#[macro_export]
macro_rules! _hsm_create_state {
    ($nam:ident) => {
        #[derive(Debug)]
        struct $nam;
        impl $crate::Initializer for $nam {
            fn new() -> Self {
                $nam
            }
        }
        _hsm_create_state_common!($nam);
    };
    ($nam:ident { $($field_name:ident : $field_type:ty = $field_default:expr),* }) => {
        #[derive(Debug)]
        struct $nam {
            _phantom        : ::std::marker::PhantomData<u8>,
            $( $field_name  : $field_type ),*
        }
        impl $crate::Initializer for $nam {
            fn new() -> Self {
                $nam {
                    _phantom        : ::std::marker::PhantomData,
                    $( $field_name  : $field_default ),*
                }
            }
        }
        _hsm_create_state_common!($nam);
    }
}

#[macro_export]
macro_rules! _hsm_create_state_enum {
    ($st_en:ident, ($($s:ident),*) ) => {
        #[derive(Debug, Clone, Eq, PartialEq)]
        enum $st_en {
            $( $s ),*
        }
        impl ::std::fmt::Display for $st_en {
            fn fmt(&self, f:&mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
                match *self {
                    $( $st_en::$s => try!(::std::fmt::Display::fmt(stringify!($s), f)) ),*
                };
                Ok(())
            }
        }
        impl $crate::InstanceParent<$st_en> for $st_en {
            fn get_parent(&self) -> Option<$st_en> {
                match *self {
                    $( $st_en::$s => $s::get_parent() ),*
                }
            }
        }
    }
}

#[macro_export]
macro_rules! _hsm_create_state_struct {
    ($st_str:ident, $st_en:ident, $st_evt:ty, $shr_dat:ident, ($($s:ident),*) ) => {
        #[derive(Debug)]
        #[allow(non_snake_case)]
        struct $st_str {
            $( $s : $s ),*
        }
        impl $crate::Initializer for $st_str {
            fn new() -> Self {
                $st_str {
                    $( $s : $s::new() ),*
                }
            }
        }
        impl $crate::StateLookup<$st_en, $st_evt, $shr_dat> for $st_str {
            fn lookup(&mut self, typ: &$st_en) -> &mut $crate::State<$st_evt, $st_en, $shr_dat> {
                match *typ {
                    $($st_en::$s => &mut self.$s ),*
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 int08h LLC
//
// 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.

extern crate ring;

use super::{TREE_LEAF_TWEAK, TREE_NODE_TWEAK, HASH_LENGTH};
use self::ring::digest;

type Data = Vec<u8>;
type Hash = Data;

pub struct MerkleTree {
    levels: Vec<Vec<Data>>,
}

impl MerkleTree {
    pub fn new() -> MerkleTree {
        MerkleTree {
            levels: vec![vec![]]
        }
    }

    pub fn push_leaf(&mut self, data: &[u8]) {
        let hash = self.hash_leaf(data);
        self.levels[0].push(hash);
    }

    pub fn get_paths(&self, mut index: usize) -> Vec<u8> {
        let mut paths = Vec::with_capacity(self.levels.len() * 64);
        let mut level = 0;

        while !self.levels[level].is_empty() {
            let sibling = if index % 2 == 0 {
                index + 1
            } else {
                index - 1
            };

            paths.extend(self.levels[level][sibling].clone());
            level += 1;
            index /= 2;
        }
        paths
    }

    pub fn compute_root(&mut self) -> Hash {
        assert!(self.levels[0].len() > 0, "Must have at least one leaf to hash!");

        let mut level = 0;
        let mut node_count = self.levels[0].len();
        while node_count > 1 {
            level += 1;

            if self.levels.len() < level + 1 {
                self.levels.push(vec![]);
            }

            if node_count % 2 != 0 {
                self.levels[level - 1].push(vec![0; HASH_LENGTH as usize]);
                node_count += 1;
            }

            node_count /= 2;

            for i in 0..node_count {
                let hash = self.hash_nodes(&self.levels[level - 1][i*2], &self.levels[level - 1][(i*2)+1]);
                self.levels[level].push(hash);
            }
        }
        assert_eq!(self.levels[level].len(), 1);
        self.levels[level].pop().unwrap()
    }

    pub fn reset(&mut self) {
        for mut level in &mut self.levels {
            level.clear();
        }
    }

    fn hash_leaf(&self, leaf: &[u8]) -> Data {
        self.hash(&[TREE_LEAF_TWEAK, leaf])
    }

    fn hash_nodes(&self, first: &[u8], second: &[u8]) -> Data {
        self.hash(&[TREE_NODE_TWEAK, first, second])
    }

    fn hash(&self, to_hash: &[&[u8]]) -> Data {
        let mut ctx = digest::Context::new(&digest::SHA512);
        for data in to_hash {
            ctx.update(data);
        }
        Data::from(ctx.finish().as_ref())
    }
}

pub fn root_from_paths(mut index: usize, data: &[u8], paths: &[u8]) -> Hash {
    let mut hash = {
        let mut ctx = digest::Context::new(&digest::SHA512);
        ctx.update(TREE_LEAF_TWEAK);
        ctx.update(data);
        Hash::from(ctx.finish().as_ref())
    };

    assert_eq!(paths.len() % 64, 0);

    for path in paths.chunks(64) {
        let mut ctx = digest::Context::new(&digest::SHA512);
        ctx.update(TREE_NODE_TWEAK);

        if index & 1 == 0 {
            // Left
            ctx.update(&hash);
            ctx.update(path);
        } else {
            // Right
            ctx.update(path);
            ctx.update(&hash);
        }
        hash = Hash::from(ctx.finish().as_ref());

        index >>= 1;
    }
    hash
}

#[cfg(test)]
mod test {

    use merkle::*;

    fn test_paths_with_num(num: usize) {
        let mut merkle = MerkleTree::new();

        for i in 0..num {
            merkle.push_leaf(&[i as u8]);
        }

        let root = merkle.compute_root();

        for i in 0..num {
            println!("Testing {:?} {:?}", num, i);
            let paths: Vec<u8> = merkle.get_paths(i).into_iter().flat_map(|x| x).collect();
            let computed_root = root_from_paths(i, &[i as u8], &paths);

            assert_eq!(root, computed_root);
        }
    }

    #[test]
    fn power_of_two() {
        test_paths_with_num(2);
        test_paths_with_num(4);
        test_paths_with_num(8);
        test_paths_with_num(16);
    }

    #[test]
    fn not_power_of_two() {
        test_paths_with_num(1);
        test_paths_with_num(20);
    }
}
<commit_msg>Fix merkle tests<commit_after>// Copyright 2018 int08h LLC
//
// 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.

extern crate ring;

use super::{TREE_LEAF_TWEAK, TREE_NODE_TWEAK, HASH_LENGTH};
use self::ring::digest;

type Data = Vec<u8>;
type Hash = Data;

pub struct MerkleTree {
    levels: Vec<Vec<Data>>,
}

impl MerkleTree {
    pub fn new() -> MerkleTree {
        MerkleTree {
            levels: vec![vec![]]
        }
    }

    pub fn push_leaf(&mut self, data: &[u8]) {
        let hash = self.hash_leaf(data);
        self.levels[0].push(hash);
    }

    pub fn get_paths(&self, mut index: usize) -> Vec<u8> {
        let mut paths = Vec::with_capacity(self.levels.len() * 64);
        let mut level = 0;

        while !self.levels[level].is_empty() {
            let sibling = if index % 2 == 0 {
                index + 1
            } else {
                index - 1
            };

            paths.extend(self.levels[level][sibling].clone());
            level += 1;
            index /= 2;
        }
        paths
    }

    pub fn compute_root(&mut self) -> Hash {
        assert!(self.levels[0].len() > 0, "Must have at least one leaf to hash!");

        let mut level = 0;
        let mut node_count = self.levels[0].len();
        while node_count > 1 {
            level += 1;

            if self.levels.len() < level + 1 {
                self.levels.push(vec![]);
            }

            if node_count % 2 != 0 {
                self.levels[level - 1].push(vec![0; HASH_LENGTH as usize]);
                node_count += 1;
            }

            node_count /= 2;

            for i in 0..node_count {
                let hash = self.hash_nodes(&self.levels[level - 1][i*2], &self.levels[level - 1][(i*2)+1]);
                self.levels[level].push(hash);
            }
        }
        assert_eq!(self.levels[level].len(), 1);
        self.levels[level].pop().unwrap()
    }

    pub fn reset(&mut self) {
        for mut level in &mut self.levels {
            level.clear();
        }
    }

    fn hash_leaf(&self, leaf: &[u8]) -> Data {
        self.hash(&[TREE_LEAF_TWEAK, leaf])
    }

    fn hash_nodes(&self, first: &[u8], second: &[u8]) -> Data {
        self.hash(&[TREE_NODE_TWEAK, first, second])
    }

    fn hash(&self, to_hash: &[&[u8]]) -> Data {
        let mut ctx = digest::Context::new(&digest::SHA512);
        for data in to_hash {
            ctx.update(data);
        }
        Data::from(ctx.finish().as_ref())
    }
}

pub fn root_from_paths(mut index: usize, data: &[u8], paths: &[u8]) -> Hash {
    let mut hash = {
        let mut ctx = digest::Context::new(&digest::SHA512);
        ctx.update(TREE_LEAF_TWEAK);
        ctx.update(data);
        Hash::from(ctx.finish().as_ref())
    };

    assert_eq!(paths.len() % 64, 0);

    for path in paths.chunks(64) {
        let mut ctx = digest::Context::new(&digest::SHA512);
        ctx.update(TREE_NODE_TWEAK);

        if index & 1 == 0 {
            // Left
            ctx.update(&hash);
            ctx.update(path);
        } else {
            // Right
            ctx.update(path);
            ctx.update(&hash);
        }
        hash = Hash::from(ctx.finish().as_ref());

        index >>= 1;
    }
    hash
}

#[cfg(test)]
mod test {

    use merkle::*;

    fn test_paths_with_num(num: usize) {
        let mut merkle = MerkleTree::new();

        for i in 0..num {
            merkle.push_leaf(&[i as u8]);
        }

        let root = merkle.compute_root();

        for i in 0..num {
            println!("Testing {:?} {:?}", num, i);
            let paths: Vec<u8> = merkle.get_paths(i);
            let computed_root = root_from_paths(i, &[i as u8], &paths);

            assert_eq!(root, computed_root);
        }
    }

    #[test]
    fn power_of_two() {
        test_paths_with_num(2);
        test_paths_with_num(4);
        test_paths_with_num(8);
        test_paths_with_num(16);
    }

    #[test]
    fn not_power_of_two() {
        test_paths_with_num(1);
        test_paths_with_num(20);
    }
}
<|endoftext|>


<commit_before>
#[derive(Debug)]
struct CubeSat {
    id: u64,
}

#[derive(Debug)]
enum StatusMessage {
    Ok,
}

fn check_status(_sat_id: &CubeSat) -> StatusMessage {
    StatusMessage::Ok
}

fn main() {
    let sat_a = CubeSat { id: 0 };
    let sat_b = CubeSat { id: 1 };
    let sat_c = CubeSat { id: 2 };

    let a_status = check_status(&sat_a);
    let b_status = check_status(&sat_b);
    let c_status = check_status(&sat_c);
    println!("a: {:?}, b: {:?}, c: {:?}", a_status, b_status, c_status);

    // "waiting" ...
    let a_status = check_status(&sat_a);
    let b_status = check_status(&sat_b);
    let c_status = check_status(&sat_c);
    println!("a: {:?}, b: {:?}, c: {:?}", a_status, b_status, c_status);
}
<commit_msg>fix by using copy semantics<commit_after>
#[derive(Debug, Copy, Clone)]
struct CubeSat {
    id: u64,
}

#[derive(Debug)]
enum StatusMessage {
    Ok,
}

fn check_status(_sat_id: CubeSat) -> StatusMessage {
    StatusMessage::Ok
}

fn main() {
    let sat_a = CubeSat { id: 0 };
    let sat_b = CubeSat { id: 1 };
    let sat_c = CubeSat { id: 2 };

    let a_status = check_status(sat_a);
    let b_status = check_status(sat_b);
    let c_status = check_status(sat_c);
    println!("a: {:?}, b: {:?}, c: {:?}", a_status, b_status, c_status);

    // "waiting" ...
    let a_status = check_status(sat_a);
    let b_status = check_status(sat_b);
    let c_status = check_status(sat_c);
    println!("a: {:?}, b: {:?}, c: {:?}", a_status, b_status, c_status);
}
<|endoftext|>


<commit_before>use std::ops::{Add, Sub, Div};
use std::collections::HashMap;
use std::iter::FromIterator;
use std::iter::repeat;
use std::fmt::{Debug, Formatter, Error};
use std::cmp::Ordering::Equal;
use std::ops::Drop;
use std::cmp;
use std::path::Path;
use std::io::{BufWriter, Write, BufReader, Read, BufRead};
use std::fs::File;
use std::mem;

#[derive(Clone)]
pub struct WordVec {
    pub word: String,
    pub count: u64,
    vec: Vec<f32>,
}

impl PartialEq for WordVec {
    fn eq(&self, other: &WordVec) -> bool {
        self.vec == other.vec
    }
}

impl Debug for WordVec {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        try!(self.word.fmt(fmt));
        try!(fmt.write_str(": "));
        try!(self.count.fmt(fmt));
        try!(fmt.write_str(", "));
        self.vec.iter().take(5).collect::<Vec<_>>().fmt(fmt)
    }
}

impl WordVec {

    fn dot_prod(&self, other: &WordVec) -> f32 {
        self.vec.iter()
                .zip(other.vec.iter())
                .map(|(x, y)| x * y)
                .fold(0.0, |x, y| x + y)
    }

    fn magnitude(&self) -> f32 {
        self.vec.iter()
                .map(|x| x * x)
                .fold(0.0, |x, y| x + y)
                .sqrt()
    }

    pub fn distance(&self, other: &WordVec) -> f32 {
        self.vec.iter().zip(other.vec.iter())
                .map(|(x, y)| (x - y)*(x - y))
                .fold(0.0, |x, y| x + y)
                .sqrt()
    }

    fn new(word: String, num_words: usize) -> WordVec {
        WordVec {
            word: word,
            count: 0,
            vec: repeat(0.0).take(num_words).collect(),
        }
    }

    fn normalize(&mut self, cooccurences: f32) {
        for f in &mut self.vec {
            *f /= cooccurences;
        }
    }

    fn inc(&mut self, i: usize) {
        self.vec[i] += 1.0;
    }

}

impl Div<i32> for WordVec {
    type Output = WordVec;

    fn div(mut self, i: i32) -> WordVec {
        for f in &mut self.vec {
            *f /= i as f32;
        }

        self
    }
}

impl<'a> Add<&'a WordVec> for WordVec {
    type Output = WordVec;

    fn add(self, other: &WordVec) -> WordVec {
        debug_assert!(self.vec.len() == other.vec.len());
        let mut newvec = WordVec {
            word: format!("{} + {}", &self.word, &other.word),
            count: 0,
            vec: self.vec,
        };

        for i in 0..newvec.vec.len() {
            newvec.vec[i] += other.vec[i];
        }

        newvec
    }
}

impl<'a> Sub<&'a WordVec> for WordVec {
    type Output = WordVec;

    fn sub(self, other: &WordVec) -> WordVec {
        debug_assert!(self.vec.len() == other.vec.len());
        let mut newvec = WordVec {
            word: format!("{} - {}", &self.word, &other.word),
            count: 0,
            vec: self.vec,
        };

        for i in 0..(newvec.vec.len()) {
            newvec.vec[i] -= other.vec[i];
        }

        newvec
    }
}

#[derive(Clone, PartialEq, Debug)]
pub struct LanguageModel {
    words: HashMap<String, usize>,
    word_vecs: Vec<WordVec>,
}

pub struct LanguageModelBuilder {
    window_radius: usize,
    words: HashMap<String, usize>,
    word_vecs: Vec<WordVec>,
    sentence: Vec<Option<usize>>,
}

pub struct WordAcceptor<'a> {
    builder: &'a mut LanguageModelBuilder,
}

impl LanguageModelBuilder {
    pub fn new(window_radius: usize, words: Vec<String>) -> LanguageModelBuilder {

        let word_vecs = words.iter()
                             .map(|s| WordVec::new(s.clone(), words.len()))
                             .collect();

        let words = HashMap::from_iter(
                        words.into_iter()
                             .enumerate()
                             .map(|(a, b)| (b, a)));

        LanguageModelBuilder {
            window_radius: window_radius,
            words: words,
            word_vecs: word_vecs,
            sentence: vec![],
        }
    }

    pub fn build(mut self) -> LanguageModel {
        let mut cooccurences: Vec<f32> = repeat(0.0).take(self.word_vecs.len()).collect();
        for vec in &self.word_vecs {
            for (count, x) in cooccurences.iter_mut().zip(vec.vec.iter()) {
                *count += *x;
            }
        }

        for (vec, c) in self.word_vecs.iter_mut().zip(cooccurences.iter()) {
            vec.normalize(*c);
        }

        LanguageModel {
            words: self.words,
            word_vecs: self.word_vecs,
        }
    }

    pub fn new_sentence<'a>(&'a mut self) -> WordAcceptor<'a> {
        WordAcceptor {
            builder: self,
        }
    }

    fn word_seen(&mut self, word: usize) {
        self.word_vecs[word].count += 1;
    }

    pub fn save(&self, path: &Path) {
        let mut file = BufWriter::new(File::create(path).unwrap());

        write_raw(self.word_vecs.len(), &mut file);
        file.write(&[b'\n']).unwrap();

        for vec in &self.word_vecs {
            file.write(vec.word.as_bytes()).unwrap();
            file.write(&[b':']).unwrap();
            let count = vec.count;
            write_raw(count, &mut file);
            for f in &vec.vec {
                write_raw(*f, &mut file)
            }
            file.write(&[b'\n']).unwrap();
        }

    }

    pub fn load(path: &Path) -> LanguageModelBuilder {
        let mut file = BufReader::new(File::open(path).unwrap());
        let mut word_vecs = Vec::new();

        let size: u64 = unsafe { read_raw::<u64, _>(&mut file) };
        read_byte(b'\n', &mut file);

        for _ in 0..size {
            let mut word: Vec<u8> = Vec::new();
            file.read_until(b':', &mut word).unwrap();
            assert_eq!(Some(b':'), word.pop());
            let word = String::from_utf8(word).unwrap();
            let count: u64 = unsafe { read_raw::<u64, _>(&mut file) };

            let mut vec: Vec<f32> = repeat(0f32).take(size as usize).collect();
            for f in &mut vec {
                unsafe {
                    *f = read_raw::<f32, _>(&mut file);
                }
            }

            read_byte(b'\n', &mut file);

            word_vecs.push(WordVec {
                word: word,
                count: count,
                vec: vec,
            });
        }

        let words: HashMap<_, _> = word_vecs.iter()
                                            .map(|v| v.word.clone())
                                            .enumerate()
                                            .map(|(i, w)| (w, i))
                                            .collect();

        LanguageModelBuilder {
            window_radius: 0,
            words: words,
            word_vecs: word_vecs,
            sentence: Vec::new(),
        }
    }
}

impl<'a> WordAcceptor<'a> {
    pub fn add_word(&mut self, word: &str) {
        let idx_opt = self.builder.words.get(word).map(|w| *w);

        if let Some(next_idx) = idx_opt {
            self.builder.word_seen(next_idx);
            self.builder.sentence.push(Some(next_idx));
        }
        else {
            self.builder.sentence.push(None);
        }
    }
}

impl<'a> Drop for WordAcceptor<'a> {
    fn drop(&mut self) {
        let LanguageModelBuilder {
            ref mut sentence,
            ref mut word_vecs,
            window_radius,
            ..
        } = *self.builder;

        for (i, &word_idx) in sentence.iter().enumerate() {
            let start = cmp::max(0, i as isize - window_radius as isize) as usize;
            let end = cmp::min(sentence.len(), i + window_radius + 1);
            for &j in &sentence[start..end] {
                match (word_idx, j) {
                    (Some(w), Some(j)) if w != j =>
                        word_vecs[w].inc(j),
                    _ => {},
                }
            }
        }

        sentence.clear();
    }
}

impl LanguageModel {
    pub fn get(&self, word: &str) -> Option<&WordVec> {
        self.words.get(word).map(|i| &self.word_vecs[*i])
    }

    pub fn nearest_words(&self, word: &WordVec) -> Vec<&WordVec> {
        let mut vec_refs = self.word_vecs.iter().filter_map(|w| {
            let dist = w.distance(word);
            if w.word != word.word {
                Some((dist, w))
            } else {
                None
            }
        }).collect::<Vec<_>>();
        vec_refs.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or_else(|| {
            println!("bad vector: {:?}, {:?}", a, b);
            Equal
        }));
        vec_refs.into_iter().map(|x| x.1).collect()
    }

}

fn read_byte<R: Read>(b: u8, read: &mut R) {
    let buf = &mut [0];
    while read.read(buf).unwrap() == 0 {}
    assert_eq!(&[b], buf);
}

unsafe fn read_raw<T: Copy, R: Read>(reader: &mut BufReader<R>) -> T {
    let mut buffer = [0u8; 64];
    let t_size = mem::size_of::<T>();
    assert!(t_size <= buffer.len());

    let mut remainder = t_size;
    while remainder > 0 {
        let bytes_read = reader.read(&mut buffer[(t_size-remainder)..t_size]).unwrap();
        remainder -= bytes_read;
    }

    let bptr: *mut T = mem::transmute((&buffer).as_ptr());
    *bptr
}

fn write_raw<T: Copy, F: Write>(t: T, writer: &mut BufWriter<F>) {
    let mut buffer = [0u8; 64];
    let t_size = mem::size_of::<T>();
    assert!(t_size <= buffer.len());
    unsafe {
        let bptr: *mut T = mem::transmute((&buffer).as_ptr());
        *bptr = t;
    }

    writer.write(&buffer[0..t_size]);
}

#[cfg(test)]
mod test {
    use super::{WordVec, LanguageModel, LanguageModelBuilder};
    use std::path::Path;

    fn get_builder() -> LanguageModelBuilder {
        let words = "foo bar baz blort".words().map(|w| w.to_string()).collect::<Vec<_>>();
        let mut builder = LanguageModelBuilder::new(1, words);

        let input = "x foo bar baz x x x x x x x blort".words();

        {
            let mut acc = builder.new_sentence();
            for word in input {
                acc.add_word(word);
            }
        }

        builder
    }

    #[test]
    fn test_accept_sentences() {
        let model = get_builder().build();
        let foo = model.get("foo").unwrap();
        let baz = model.get("baz").unwrap();
        let bar = model.get("bar").unwrap();
        let blort = model.get("blort").unwrap();

        assert!(foo.distance(baz) < foo.distance(blort));
        assert!(foo.distance(bar) == bar.distance(baz));
    }

    #[test]
    fn test_serialization() {
        let builder = get_builder();
        let path = Path::new("/tmp/model.data");
        builder.save(&path);

        let loaded_model = LanguageModelBuilder::load(path).build();
        assert_eq!(builder.build(), loaded_model);
    }
}
<commit_msg>Minor cleanup<commit_after>use std::ops::{Add, Sub, Div};
use std::collections::HashMap;
use std::iter::FromIterator;
use std::iter::repeat;
use std::fmt::{Debug, Formatter, Error};
use std::cmp::Ordering::Equal;
use std::ops::Drop;
use std::cmp;
use std::path::Path;
use std::io::{BufWriter, Write, BufReader, Read, BufRead};
use std::fs::File;
use std::mem;

#[derive(Clone)]
pub struct WordVec {
    pub word: String,
    pub count: u64,
    vec: Vec<f32>,
}

impl PartialEq for WordVec {
    fn eq(&self, other: &WordVec) -> bool {
        self.vec == other.vec
    }
}

impl Debug for WordVec {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        try!(self.word.fmt(fmt));
        try!(fmt.write_str(": "));
        try!(self.count.fmt(fmt));
        try!(fmt.write_str(", "));
        self.vec.iter().take(5).collect::<Vec<_>>().fmt(fmt)
    }
}

impl WordVec {

    fn dot_prod(&self, other: &WordVec) -> f32 {
        self.vec.iter()
                .zip(other.vec.iter())
                .map(|(x, y)| x * y)
                .fold(0.0, |x, y| x + y)
    }

    fn magnitude(&self) -> f32 {
        self.vec.iter()
                .map(|x| x * x)
                .fold(0.0, |x, y| x + y)
                .sqrt()
    }

    pub fn distance(&self, other: &WordVec) -> f32 {
        self.vec.iter().zip(other.vec.iter())
                .map(|(x, y)| (x - y)*(x - y))
                .fold(0.0, |x, y| x + y)
                .sqrt()
    }

    fn new(word: String, num_words: usize) -> WordVec {
        WordVec {
            word: word,
            count: 0,
            vec: repeat(0.0).take(num_words).collect(),
        }
    }

    fn normalize(&mut self, cooccurences: f32) {
        for f in &mut self.vec {
            *f /= cooccurences;
        }
    }

    fn inc(&mut self, i: usize) {
        self.vec[i] += 1.0;
    }

}

impl Div<i32> for WordVec {
    type Output = WordVec;

    fn div(mut self, i: i32) -> WordVec {
        for f in &mut self.vec {
            *f /= i as f32;
        }

        self
    }
}

impl<'a> Add<&'a WordVec> for WordVec {
    type Output = WordVec;

    fn add(self, other: &WordVec) -> WordVec {
        debug_assert!(self.vec.len() == other.vec.len());
        let mut newvec = WordVec {
            word: format!("{} + {}", &self.word, &other.word),
            count: 0,
            vec: self.vec,
        };

        for i in 0..newvec.vec.len() {
            newvec.vec[i] += other.vec[i];
        }

        newvec
    }
}

impl<'a> Sub<&'a WordVec> for WordVec {
    type Output = WordVec;

    fn sub(self, other: &WordVec) -> WordVec {
        debug_assert!(self.vec.len() == other.vec.len());
        let mut newvec = WordVec {
            word: format!("{} - {}", &self.word, &other.word),
            count: 0,
            vec: self.vec,
        };

        for i in 0..(newvec.vec.len()) {
            newvec.vec[i] -= other.vec[i];
        }

        newvec
    }
}

#[derive(Clone, PartialEq, Debug)]
pub struct LanguageModel {
    words: HashMap<String, usize>,
    word_vecs: Vec<WordVec>,
}

pub struct LanguageModelBuilder {
    window_radius: usize,
    words: HashMap<String, usize>,
    word_vecs: Vec<WordVec>,
    sentence: Vec<Option<usize>>,
}

pub struct WordAcceptor<'a> {
    builder: &'a mut LanguageModelBuilder,
}

impl LanguageModelBuilder {
    pub fn new(window_radius: usize, words: Vec<String>) -> LanguageModelBuilder {

        let word_vecs = words.iter()
                             .map(|s| WordVec::new(s.clone(), words.len()))
                             .collect();

        let words = HashMap::from_iter(
                        words.into_iter()
                             .enumerate()
                             .map(|(a, b)| (b, a)));

        LanguageModelBuilder {
            window_radius: window_radius,
            words: words,
            word_vecs: word_vecs,
            sentence: vec![],
        }
    }

    pub fn build(mut self) -> LanguageModel {
        let mut cooccurences: Vec<f32> = repeat(0.0).take(self.word_vecs.len()).collect();
        for vec in &self.word_vecs {
            for (count, x) in cooccurences.iter_mut().zip(vec.vec.iter()) {
                *count += *x;
            }
        }

        for (vec, c) in self.word_vecs.iter_mut().zip(cooccurences.iter()) {
            vec.normalize(*c);
        }

        LanguageModel {
            words: self.words,
            word_vecs: self.word_vecs,
        }
    }

    pub fn new_sentence<'a>(&'a mut self) -> WordAcceptor<'a> {
        WordAcceptor {
            builder: self,
        }
    }

    fn word_seen(&mut self, word: usize) {
        self.word_vecs[word].count += 1;
    }

    pub fn save(&self, path: &Path) {
        let mut file = BufWriter::new(File::create(path).unwrap());

        write_raw(self.word_vecs.len(), &mut file);
        file.write(&[b'\n']).unwrap();

        for vec in &self.word_vecs {
            file.write(vec.word.as_bytes()).unwrap();
            file.write(&[b':']).unwrap();
            let count = vec.count;
            write_raw(count, &mut file);
            for f in &vec.vec {
                write_raw(*f, &mut file)
            }
            file.write(&[b'\n']).unwrap();
        }

    }

    pub fn load(path: &Path) -> LanguageModelBuilder {
        let mut file = BufReader::new(File::open(path).unwrap());
        let mut word_vecs = Vec::new();

        let size: u64 = unsafe { read_raw::<u64, _>(&mut file) };
        read_byte(b'\n', &mut file);

        for _ in 0..size {
            let mut word: Vec<u8> = Vec::new();
            file.read_until(b':', &mut word).unwrap();
            assert_eq!(Some(b':'), word.pop());
            let word = String::from_utf8(word).unwrap();
            let count: u64 = unsafe { read_raw::<u64, _>(&mut file) };

            let mut vec: Vec<f32> = repeat(0f32).take(size as usize).collect();
            for f in &mut vec {
                unsafe {
                    *f = read_raw::<f32, _>(&mut file);
                }
            }

            read_byte(b'\n', &mut file);

            word_vecs.push(WordVec {
                word: word,
                count: count,
                vec: vec,
            });
        }

        let words: HashMap<_, _> = word_vecs.iter()
                                            .map(|v| v.word.clone())
                                            .enumerate()
                                            .map(|(i, w)| (w, i))
                                            .collect();

        LanguageModelBuilder {
            window_radius: 0,
            words: words,
            word_vecs: word_vecs,
            sentence: Vec::new(),
        }
    }
}

impl<'a> WordAcceptor<'a> {
    pub fn add_word(&mut self, word: &str) {
        let idx_opt = self.builder.words.get(word).map(|w| *w);

        if let Some(next_idx) = idx_opt {
            self.builder.word_seen(next_idx);
            self.builder.sentence.push(Some(next_idx));
        }
        else {
            self.builder.sentence.push(None);
        }
    }
}

impl<'a> Drop for WordAcceptor<'a> {
    fn drop(&mut self) {
        let LanguageModelBuilder {
            ref mut sentence,
            ref mut word_vecs,
            window_radius,
            ..
        } = *self.builder;

        for (i, &word_idx) in sentence.iter().enumerate() {
            let start = cmp::max(0, i as isize - window_radius as isize) as usize;
            let end = cmp::min(sentence.len(), i + window_radius + 1);
            for &j in &sentence[start..end] {
                match (word_idx, j) {
                    (Some(w), Some(j)) if w != j =>
                        word_vecs[w].inc(j),
                    _ => {},
                }
            }
        }

        sentence.clear();
    }
}

impl LanguageModel {
    pub fn get(&self, word: &str) -> Option<&WordVec> {
        self.words.get(word).map(|i| &self.word_vecs[*i])
    }

    pub fn nearest_words(&self, word: &WordVec) -> Vec<&WordVec> {
        let mut vec_refs = self.word_vecs.iter().filter_map(|w| {
            let dist = w.distance(word);
            if w.word != word.word {
                Some((dist, w))
            } else {
                None
            }
        }).collect::<Vec<_>>();
        vec_refs.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or_else(|| {
            println!("bad vector: {:?}, {:?}", a, b);
            Equal
        }));
        vec_refs.into_iter().map(|x| x.1).collect()
    }

}

fn read_byte<R: Read>(b: u8, read: &mut R) {
    let buf = &mut [0];
    while read.read(buf).unwrap() == 0 {}
    assert_eq!(&[b], buf);
}

unsafe fn read_raw<T: Copy, R: Read>(reader: &mut BufReader<R>) -> T {
    let mut buffer = [0u8; 64];
    let t_size = mem::size_of::<T>();
    assert!(t_size <= buffer.len());

    let mut remainder = t_size;
    while remainder > 0 {
        let bytes_read = reader.read(&mut buffer[(t_size-remainder)..t_size]).unwrap();
        remainder -= bytes_read;
    }

    let bptr: *mut T = mem::transmute(buffer.as_ptr());
    *bptr
}

fn write_raw<T: Copy, F: Write>(t: T, writer: &mut BufWriter<F>) {
    let mut buffer = [0u8; 64];
    let t_size = mem::size_of::<T>();
    assert!(t_size <= buffer.len());
    unsafe {
        let bptr: *mut T = mem::transmute(buffer.as_ptr());
        *bptr = t;
    }

    writer.write(&buffer[0..t_size]);
}

#[cfg(test)]
mod test {
    use super::{WordVec, LanguageModel, LanguageModelBuilder};
    use std::path::Path;

    fn get_builder() -> LanguageModelBuilder {
        let words = "foo bar baz blort".split(" ").map(|w| w.to_string()).collect::<Vec<_>>();
        let mut builder = LanguageModelBuilder::new(1, words);

        let input = "x foo bar baz x x x x x x x blort".split(" ");

        {
            let mut acc = builder.new_sentence();
            for word in input {
                acc.add_word(word);
            }
        }

        builder
    }

    #[test]
    fn test_accept_sentences() {
        let model = get_builder().build();
        let foo = model.get("foo").unwrap();
        let baz = model.get("baz").unwrap();
        let bar = model.get("bar").unwrap();
        let blort = model.get("blort").unwrap();

        assert!(foo.distance(baz) < foo.distance(blort));
        assert!(foo.distance(bar) == bar.distance(baz));
    }

    #[test]
    fn test_serialization() {
        let builder = get_builder();
        let path = Path::new("/tmp/model.data");
        builder.save(&path);

        let loaded_model = LanguageModelBuilder::load(path).build();
        assert_eq!(builder.build(), loaded_model);
    }
}
<|endoftext|>


<commit_before>use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use std::io;
use std::fs;
use regex;
use regex::Regex;
use error::Error;

#[derive(Eq, PartialEq, Debug)]
struct Motion {
  add_path: PathBuf,
  sub_path: PathBuf,
}

#[derive(Eq, PartialEq, Debug)]
struct Template {
  extension: String,
  add_path: PathBuf,
  sub_path: PathBuf,
}

#[derive(Eq, PartialEq, Debug)]
struct Motions {
  template: Template,
  motions: Vec<Motion>,
}

fn discover(dir: &Path) -> Result<Motions, Error> {
  let paths = try!(find_paths(dir.to_path_buf()));
  let template = try!(discover_template(&paths));
  let motions = try!(discover_motions(&template, &paths));

  Ok(Motions {
    template: template,
    motions: motions,
  })
}

fn discover_template(paths: &Vec<PathBuf>) -> Result<Template, Error> {
  // Create the regexi which will match our template file names.
  let add_re = Regex::new(r"^template\.add($|\..+$)").unwrap();
  let sub_re = Regex::new(r"^template\.sub($|\..+$)").unwrap();

  // Find our add and sub paths in our list of paths. Error if we can’t find
  // anything.
  let add_path = try!(
    paths.iter()
    .find(|path| path.file_name().and_then(OsStr::to_str).map(|s| add_re.is_match(s)).unwrap_or(false))
    .ok_or(Error::new("Add template file was not found."))
  );

  let sub_path = try!(
    paths.iter()
    .find(|path| path.file_name().and_then(OsStr::to_str).map(|s| sub_re.is_match(s)).unwrap_or(false))
    .ok_or(Error::new("Sub template file was not found."))
  );

  // Get both the add extension and the sub extension. We can safely unwrap the
  // file names because part of being an `add_path` or `sub_path` means we
  // already checked that a file name exists.
  let add_ext = add_re.replace_all(add_path.file_name().unwrap().to_str().unwrap(), "$1");
  let sub_ext = sub_re.replace_all(sub_path.file_name().unwrap().to_str().unwrap(), "$1");

  // If the extensions are not equal, there is an error.
  if add_ext != sub_ext {
    return Err(Error::new(format!("Template extensions for add ('{}') and sub ('{}') do not match.", add_ext, sub_ext)))
  }

  // Return our template.
  Ok(Template {
    extension: add_ext,
    add_path: add_path.to_path_buf(),
    sub_path: sub_path.to_path_buf(),
  })
}

fn discover_motions(template: &Template, paths: &Vec<PathBuf>) -> Result<Vec<Motion>, Error> {
  // Get all the file names for our paths for later use. We also make sure we
  // return a tuple. This way we can keep the original path.
  let paths: Vec<(&PathBuf, &str)> = {
    paths.into_iter()
    .filter_map(|sub_path| sub_path.file_name().and_then(OsStr::to_str).map(|file_name| (sub_path, file_name)))
    .collect()
  };

  // Create the filename regexi for add and sub using the template extension.
  let add_re = Regex::new(&(r"^(\d{6}-.+)\.add".to_owned() + &regex::quote(&template.extension) + "$")).unwrap();
  let sub_re = Regex::new(&(r"^(\d{6}-.+)\.sub".to_owned() + &regex::quote(&template.extension) + "$")).unwrap();
  // Construct a motions accumulator.
  let mut motions: Vec<Motion> = Vec::new();

  // Iterate through all of our paths…
  for &(add_path, add_file_name) in paths.iter() {
    // If this path is an add file continue…
    if add_re.is_match(add_file_name) {
      // Get the name and timestamp for this motion.
      let name = add_re.replace_all(add_file_name, "$1");
      // Get the sub path with a name that matches our add path. If it does not
      // exist, throw an error.
      let &(sub_path, _) = try!(
        paths.iter()
        .find(|&&(_, sub_file_name)| sub_re.is_match(sub_file_name) && sub_re.replace_all(sub_file_name, "$1") == name)
        .ok_or(Error::new(format!("Sub file not found for add file '{}'.", add_file_name)))
      );
      // Add the motion to our accumulator.
      motions.push(Motion {
        add_path: add_path.to_path_buf(),
        sub_path: sub_path.to_path_buf(),
      });
    }
  }

  // Sort our motions by *file* name.
  motions.sort_by(|a, b| a.add_path.file_name().cmp(&b.add_path.file_name()));

  // Return all of our motions.
  Ok(motions)
}

fn find_paths(path: PathBuf) -> io::Result<Vec<PathBuf>> {
  // If the path is a directory let’s recursively go through every entry and
  // rerun our `discover_all` function.
  if try!(fs::metadata(&path)).is_dir() {
    // Create a new paths vec.
    let mut paths: Vec<PathBuf> = Vec::new();
    // Loop through the directory…
    for entry in try!(fs::read_dir(&path)) {
      // Get all the paths from this entry path by recursively calling the
      // function.
      let mut next_paths = try!(find_paths(try!(entry).path()));
      // Append these next paths to our top level motions vec.
      paths.append(&mut next_paths);
    }
    // Return all of our motions.
    Ok(paths)
  }
  // Otherwise our path is not a directory and we should return a singleton
  // vector of the path.
  else {
    Ok(vec![path])
  }
}

#[cfg(test)]
mod tests {
  use std::path::{Path, PathBuf};
  use super::{find_paths, discover, Motions, Template, Motion};

  fn pb(path: &str) -> PathBuf {
    Path::new(path).to_path_buf()
  }

  #[test]
  fn test_find_paths() {
    assert_eq!(find_paths(pb("tests/fixtures/nested")).unwrap(), vec![
      pb("tests/fixtures/nested/234567-bar.add"),
      pb("tests/fixtures/nested/234567-bar.sub"),
      pb("tests/fixtures/nested/a/345678-baz.add"),
      pb("tests/fixtures/nested/a/345678-baz.sub"),
      pb("tests/fixtures/nested/b/123456-foo.add"),
      pb("tests/fixtures/nested/b/123456-foo.sub"),
      pb("tests/fixtures/nested/b/c/456789-qux.add"),
      pb("tests/fixtures/nested/b/c/456789-qux.sub"),
      pb("tests/fixtures/nested/template.add"),
      pb("tests/fixtures/nested/template.sub"),
    ]);
  }

  #[test]
  fn test_basic() {
    assert_eq!(discover(Path::new("tests/fixtures/basic")).unwrap(), Motions {
      template: Template {
        extension: "".to_string(),
        add_path: pb("tests/fixtures/basic/template.add"),
        sub_path: pb("tests/fixtures/basic/template.sub"),
      },
      motions: vec![
        Motion {
          add_path: pb("tests/fixtures/basic/123456-foo.add"),
          sub_path: pb("tests/fixtures/basic/123456-foo.sub"),
        },
        Motion {
          add_path: pb("tests/fixtures/basic/234567-bar.add"),
          sub_path: pb("tests/fixtures/basic/234567-bar.sub"),
        },
      ],
    });
  }

  #[test]
  fn test_nested() {
    assert_eq!(discover(Path::new("tests/fixtures/nested")).unwrap(), Motions {
      template: Template {
        extension: "".to_string(),
        add_path: pb("tests/fixtures/nested/template.add"),
        sub_path: pb("tests/fixtures/nested/template.sub"),
      },
      motions: vec![
        Motion {
          add_path: pb("tests/fixtures/nested/b/123456-foo.add"),
          sub_path: pb("tests/fixtures/nested/b/123456-foo.sub"),
        },
        Motion {
          add_path: pb("tests/fixtures/nested/234567-bar.add"),
          sub_path: pb("tests/fixtures/nested/234567-bar.sub"),
        },
        Motion {
          add_path: pb("tests/fixtures/nested/a/345678-baz.add"),
          sub_path: pb("tests/fixtures/nested/a/345678-baz.sub"),
        },
        Motion {
          add_path: pb("tests/fixtures/nested/b/c/456789-qux.add"),
          sub_path: pb("tests/fixtures/nested/b/c/456789-qux.sub"),
        },
      ],
    });
  }

  #[test]
  fn test_extension() {
    assert_eq!(discover(Path::new("tests/fixtures/extension")).unwrap(), Motions {
      template: Template {
        extension: ".sql".to_string(),
        add_path: pb("tests/fixtures/extension/template.add.sql"),
        sub_path: pb("tests/fixtures/extension/template.sub.sql"),
      },
      motions: vec![
        Motion {
          add_path: pb("tests/fixtures/extension/123456-foo.add.sql"),
          sub_path: pb("tests/fixtures/extension/123456-foo.sub.sql"),
        },
        Motion {
          add_path: pb("tests/fixtures/extension/234567-bar.add.sql"),
          sub_path: pb("tests/fixtures/extension/234567-bar.sub.sql"),
        },
      ],
    });
  }

  #[test]
  fn test_bad_templateless() {
    assert!(discover(Path::new("tests/fixtures/bad/templateless")).is_err());
  }

  #[test]
  fn test_bad_names() {
    assert!(discover(Path::new("tests/fixtures/bad/names")).is_err());
  }
}
<commit_msg>refactor motion module a bit<commit_after>use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use std::io;
use std::fs;
use regex;
use regex::Regex;
use error::Error;

#[derive(Eq, PartialEq, Debug)]
struct Motion {
  add_path: PathBuf,
  sub_path: PathBuf,
}

#[derive(Eq, PartialEq, Debug)]
struct Template {
  extension: String,
  add_path: PathBuf,
  sub_path: PathBuf,
}

fn find(dir: &Path) -> Result<Vec<Motion>, Error> {
  let template = try!(find_template(dir));
  let motions = try!(find_motions(&template, dir));
  Ok(motions)
}

fn find_template(dir: &Path) -> Result<Template, Error> {
  let paths = try!(find_paths(dir.to_path_buf(), 1));

  // Create the regexi which will match our template file names.
  let add_re = Regex::new(r"^template\.add($|\..+$)").unwrap();
  let sub_re = Regex::new(r"^template\.sub($|\..+$)").unwrap();

  // Find our add and sub paths in our list of paths. Error if we can’t find
  // anything.
  let add_path = try!(
    paths.iter()
    .find(|path| path.file_name().and_then(OsStr::to_str).map(|s| add_re.is_match(s)).unwrap_or(false))
    .ok_or(Error::new("Add template file was not found."))
  );

  let sub_path = try!(
    paths.iter()
    .find(|path| path.file_name().and_then(OsStr::to_str).map(|s| sub_re.is_match(s)).unwrap_or(false))
    .ok_or(Error::new("Sub template file was not found."))
  );

  // Get both the add extension and the sub extension. We can safely unwrap the
  // file names because part of being an `add_path` or `sub_path` means we
  // already checked that a file name exists.
  let add_ext = add_re.replace_all(add_path.file_name().unwrap().to_str().unwrap(), "$1");
  let sub_ext = sub_re.replace_all(sub_path.file_name().unwrap().to_str().unwrap(), "$1");

  // If the extensions are not equal, there is an error.
  if add_ext != sub_ext {
    return Err(Error::new(format!("Template extensions for add ('{}') and sub ('{}') do not match.", add_ext, sub_ext)))
  }

  // Return our template.
  Ok(Template {
    extension: add_ext,
    add_path: add_path.to_path_buf(),
    sub_path: sub_path.to_path_buf(),
  })
}

fn find_motions(template: &Template, dir: &Path) -> Result<Vec<Motion>, Error> {
  // Get all the file names for our paths for later use. We also make sure we
  // return a tuple. This way we can keep the original path.
  let paths = try!(find_paths(dir.to_path_buf(), 100));
  let paths: Vec<(&PathBuf, &str)> = {
    paths
    .iter()
    .filter_map(|path| path.file_name().and_then(OsStr::to_str).map(|file_name| (path, file_name)))
    .collect()
  };

  // Create the filename regexi for add and sub using the template extension.
  let add_re = Regex::new(&(r"^(\d{6}-.+)\.add".to_owned() + &regex::quote(&template.extension) + "$")).unwrap();
  let sub_re = Regex::new(&(r"^(\d{6}-.+)\.sub".to_owned() + &regex::quote(&template.extension) + "$")).unwrap();
  // Construct a motions accumulator.
  let mut motions: Vec<Motion> = Vec::new();

  // Iterate through all of our paths…
  for &(ref add_path, add_file_name) in paths.iter() {
    // If this path is an add file continue…
    if add_re.is_match(add_file_name) {
      // Get the name and timestamp for this motion.
      let name = add_re.replace_all(add_file_name, "$1");
      // Get the sub path with a name that matches our add path. If it does not
      // exist, throw an error.
      let &(ref sub_path, _) = try!(
        paths
        .iter()
        .find(|&&(_, sub_file_name)| sub_re.is_match(sub_file_name) && sub_re.replace_all(sub_file_name, "$1") == name)
        .ok_or(Error::new(format!("Sub file not found for add file '{}'.", add_file_name)))
      );
      // Add the motion to our accumulator.
      motions.push(Motion {
        add_path: add_path.to_path_buf(),
        sub_path: sub_path.to_path_buf(),
      });
    }
  }

  // Sort our motions by *file* name.
  motions.sort_by(|a, b| a.add_path.file_name().cmp(&b.add_path.file_name()));

  // Return all of our motions.
  Ok(motions)
}

fn find_paths(path: PathBuf, recurse: u8) -> io::Result<Vec<PathBuf>> {
  // If the path is a directory let’s recursively go through every entry and
  // rerun our `discover_all` function.
  if try!(fs::metadata(&path)).is_dir() {
    // If we have ended our recursion, just return an empty vec.
    if recurse == 0 {
      return Ok(vec![])
    }
    // Create a new paths vec.
    let mut paths: Vec<PathBuf> = Vec::new();
    // Loop through the directory…
    for entry in try!(fs::read_dir(&path)) {
      // Get all the paths from this entry path by recursively calling the
      // function.
      let mut next_paths = try!(find_paths(try!(entry).path(), recurse - 1));
      // Append these next paths to our top level motions vec.
      paths.append(&mut next_paths);
    }
    // Return all of our motions.
    Ok(paths)
  }
  // Otherwise our path is not a directory and we should return a singleton
  // vector of the path.
  else {
    Ok(vec![path])
  }
}

#[cfg(test)]
mod tests {
  use std::path::{Path, PathBuf};
  use super::{find_paths, find, Motion, find_template, Template};

  fn pb(path: &str) -> PathBuf {
    Path::new(path).to_path_buf()
  }

  #[test]
  fn test_find_paths() {
    assert_eq!(find_paths(pb("tests/fixtures/nested"), 100).unwrap(), vec![
      pb("tests/fixtures/nested/234567-bar.add"),
      pb("tests/fixtures/nested/234567-bar.sub"),
      pb("tests/fixtures/nested/a/345678-baz.add"),
      pb("tests/fixtures/nested/a/345678-baz.sub"),
      pb("tests/fixtures/nested/b/123456-foo.add"),
      pb("tests/fixtures/nested/b/123456-foo.sub"),
      pb("tests/fixtures/nested/b/c/456789-qux.add"),
      pb("tests/fixtures/nested/b/c/456789-qux.sub"),
      pb("tests/fixtures/nested/template.add"),
      pb("tests/fixtures/nested/template.sub"),
    ]);
  }

  #[test]
  fn test_find_paths_limit_recurse_1() {
    assert_eq!(find_paths(pb("tests/fixtures/nested"), 1).unwrap(), vec![
      pb("tests/fixtures/nested/234567-bar.add"),
      pb("tests/fixtures/nested/234567-bar.sub"),
      pb("tests/fixtures/nested/template.add"),
      pb("tests/fixtures/nested/template.sub"),
    ]);
  }

  #[test]
  fn test_find_paths_limit_recurse_2() {
    assert_eq!(find_paths(pb("tests/fixtures/nested"), 2).unwrap(), vec![
      pb("tests/fixtures/nested/234567-bar.add"),
      pb("tests/fixtures/nested/234567-bar.sub"),
      pb("tests/fixtures/nested/a/345678-baz.add"),
      pb("tests/fixtures/nested/a/345678-baz.sub"),
      pb("tests/fixtures/nested/b/123456-foo.add"),
      pb("tests/fixtures/nested/b/123456-foo.sub"),
      pb("tests/fixtures/nested/template.add"),
      pb("tests/fixtures/nested/template.sub"),
    ]);
  }

  #[test]
  fn test_fixtures_basic() {
    assert_eq!(find(Path::new("tests/fixtures/basic")).unwrap(), vec![
      Motion {
        add_path: pb("tests/fixtures/basic/123456-foo.add"),
        sub_path: pb("tests/fixtures/basic/123456-foo.sub"),
      },
      Motion {
        add_path: pb("tests/fixtures/basic/234567-bar.add"),
        sub_path: pb("tests/fixtures/basic/234567-bar.sub"),
      },
    ]);
  }

  #[test]
  fn test_template_basic() {
    assert_eq!(find_template(Path::new("tests/fixtures/basic")).unwrap(), Template {
      extension: "".to_string(),
      add_path: pb("tests/fixtures/basic/template.add"),
      sub_path: pb("tests/fixtures/basic/template.sub"),
    });
  }

  #[test]
  fn test_fixtures_nested() {
    assert_eq!(find(Path::new("tests/fixtures/nested")).unwrap(), vec![
      Motion {
        add_path: pb("tests/fixtures/nested/b/123456-foo.add"),
        sub_path: pb("tests/fixtures/nested/b/123456-foo.sub"),
      },
      Motion {
        add_path: pb("tests/fixtures/nested/234567-bar.add"),
        sub_path: pb("tests/fixtures/nested/234567-bar.sub"),
      },
      Motion {
        add_path: pb("tests/fixtures/nested/a/345678-baz.add"),
        sub_path: pb("tests/fixtures/nested/a/345678-baz.sub"),
      },
      Motion {
        add_path: pb("tests/fixtures/nested/b/c/456789-qux.add"),
        sub_path: pb("tests/fixtures/nested/b/c/456789-qux.sub"),
      },
    ]);
  }

  #[test]
  fn test_template_nested() {
    assert_eq!(find_template(Path::new("tests/fixtures/nested")).unwrap(), Template {
      extension: "".to_string(),
      add_path: pb("tests/fixtures/nested/template.add"),
      sub_path: pb("tests/fixtures/nested/template.sub"),
    });
  }

  #[test]
  fn test_fixtures_extension() {
    assert_eq!(find(Path::new("tests/fixtures/extension")).unwrap(), vec![
      Motion {
        add_path: pb("tests/fixtures/extension/123456-foo.add.sql"),
        sub_path: pb("tests/fixtures/extension/123456-foo.sub.sql"),
      },
      Motion {
        add_path: pb("tests/fixtures/extension/234567-bar.add.sql"),
        sub_path: pb("tests/fixtures/extension/234567-bar.sub.sql"),
      },
    ]);
  }

  #[test]
  fn test_template_extension() {
    assert_eq!(find_template(Path::new("tests/fixtures/extension")).unwrap(), Template {
      extension: ".sql".to_string(),
      add_path: pb("tests/fixtures/extension/template.add.sql"),
      sub_path: pb("tests/fixtures/extension/template.sub.sql"),
    });
  }

  #[test]
  fn test_fixtures_bad_templateless() {
    assert!(find(Path::new("tests/fixtures/bad/templateless")).is_err());
  }

  #[test]
  fn test_bad_names() {
    assert!(find(Path::new("tests/fixtures/bad/names")).is_err());
  }
}
<|endoftext|>