<commit_before>/// score is responsible for calculating the scores of the similarity between
/// the query and the choice.
///
/// It is modeled after https://github.com/felipesere/icepick.git

use std::cmp::max;
use std::cell::RefCell;
use regex::Regex;

const BONUS_UPPER_MATCH: i64 = 10;
const BONUS_ADJACENCY: i64 = 10;
const BONUS_SEPARATOR: i64 = 20;
const BONUS_CAMEL: i64 = 20;
const PENALTY_CASE_UNMATCHED: i64 = -1;
const PENALTY_LEADING: i64 = -6; // penalty applied for every letter before the first match
const PENALTY_MAX_LEADING: i64 = -18; // maxing penalty for leading letters
const PENALTY_UNMATCHED: i64 = -2;

use std::io::Write;
macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

// judge how many scores the current index should get
fn fuzzy_score(string: &[char], index: usize, pattern: &[char], pattern_idx: usize) -> i64 {
    let mut score = 0;

    let pattern_char = pattern[pattern_idx];
    let cur = string[index];

    if pattern_char.is_uppercase() && cur.is_uppercase() && pattern_char == cur {
        score += BONUS_UPPER_MATCH;
    } else {
        score += PENALTY_CASE_UNMATCHED;
    }

    if index == 0 {
        return score + if cur.is_uppercase() {BONUS_CAMEL} else {0};
    }

    let prev = string[index-1];

    // apply bonus for matches after a separator
    if prev == ' ' || prev == '_' || prev == '-' || prev == '/' || prev == '\\' {
        score += BONUS_SEPARATOR;
    }

    // apply bonus for camelCases
    if prev.is_lowercase() && cur.is_uppercase() {
        score += BONUS_CAMEL;
    }

    if pattern_idx == 0 {
        score += max((index as i64) * PENALTY_LEADING, PENALTY_MAX_LEADING);
    }

    score
}

pub fn fuzzy_match(choice: &[char],
                   pattern: &[char],
                   pattern_lower: &[char]) -> Option<(i64, Vec<usize>)>{
    if pattern.len() == 0 {
        return Some((0, Vec::new()));
    }

    let mut scores = vec![];
    let mut picked = vec![];

    let mut prev_matched_idx = -1; // to ensure that the pushed char are able to match the pattern
    for (pattern_idx, &pattern_char) in pattern_lower.iter().enumerate() {
        let vec_cell = RefCell::new(vec![]);
        {
            let mut vec = vec_cell.borrow_mut();
            for (idx, &ch) in choice.iter().enumerate() {
                if ch == pattern_char && (idx as i64) > prev_matched_idx {
                    vec.push((idx, fuzzy_score(choice, idx, pattern, pattern_idx), 0)); // (char_idx, score, vec_idx back_ref)
                }
            }

            if vec.is_empty() {
                // not matched
                return None;
            }
            prev_matched_idx = vec[0].0 as i64;
        }
        scores.push(vec_cell);
    }

    for pattern_idx in 0..pattern.len()-1 {
        let cur_row = scores[pattern_idx].borrow();
        let mut next_row = scores[pattern_idx+1].borrow_mut();

        for idx in 0..next_row.len() {
            let (next_char_idx, next_score, _) = next_row[idx];
//(back_ref, &score)
            let (back_ref, score) = cur_row.iter()
                .take_while(|&&(idx, _, _)| idx < next_char_idx)
                .map(|&(char_idx, score, _)| {
                    let adjacent_num = next_char_idx - char_idx - 1;
                    score + next_score + if adjacent_num == 0 {BONUS_ADJACENCY} else {PENALTY_UNMATCHED * adjacent_num as i64}
                })
                .enumerate()
                .max_by_key(|&(_, x)| x)
                .unwrap();

            next_row[idx] = (next_char_idx, score, back_ref);
        }
    }

    let (mut next_col, &(_, score, _)) = scores[pattern.len()-1].borrow().iter().enumerate().max_by_key(|&(_, &x)| x.1).unwrap();
    let mut pattern_idx = pattern.len() as i64 - 1;
    while pattern_idx >= 0 {
        let (idx, _, next) = scores[pattern_idx as usize].borrow()[next_col];
        next_col = next;
        picked.push(idx);
        pattern_idx -= 1;
    }
    picked.reverse();
    Some((score, picked))
}

pub fn regex_match(choice: &str, pattern: &Option<Regex>) -> Option<(i64, i64)>{
    match *pattern {
        Some(ref pat) => {
            let ret = pat.find(choice);
            if ret.is_none() {
                return None;
            }

            let (start, end) = ret.unwrap();
            let first = (&choice[0..start]).chars().count();
            let last = first + (&choice[start..end]).chars().count();
            Some((first as i64, last as i64))
        }
        None => None,
    }
}

// Pattern may appear in sevearl places, return the first and last occurrence
pub fn exact_match(choice: &str, pattern: &str) -> Option<((usize, usize), (usize, usize))>{
    // search from the start
    let start_pos = choice.find(pattern);
    if start_pos.is_none() {return None};

    let pattern_len = pattern.chars().count();

    let first_occur = start_pos.map(|s| {
        let start = if s == 0 { 0 } else { (&choice[0..s]).chars().count() };
        (start, start + pattern_len)
    }).unwrap();

    let last_pos = choice.rfind(pattern);
    if last_pos.is_none() {return None};
    let last_occur = last_pos.map(|s| {
        let start = if s == 0 { 0 } else { (&choice[0..s]).chars().count() };
        (start, start + pattern_len)
    }).unwrap();

    Some((first_occur, last_occur))
}

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

    //#[test]
    //fn teset_fuzzy_match() {
        //// the score in this test doesn't actually matter, but the index matters.
        //let choice_1 = "1111121";
        //let query_1 = "21";
        //assert_eq!(fuzzy_match(&choice_1, &query_1), Some((-10, vec![5,6])));

        //let choice_2 = "Ca";
        //let query_2 = "ac";
        //assert_eq!(fuzzy_match(&choice_2, &query_2), None);

        //let choice_3 = ".";
        //let query_3 = "s";
        //assert_eq!(fuzzy_match(&choice_3, &query_3), None);

        //let choice_4 = "AaBbCc";
        //let query_4 = "abc";
        //assert_eq!(fuzzy_match(&choice_4, &query_4), Some((53, vec![0,2,4])));
    //}
}
<commit_msg>[score] decrese the weight of separator and camel cases<commit_after>/// score is responsible for calculating the scores of the similarity between
/// the query and the choice.
///
/// It is modeled after https://github.com/felipesere/icepick.git

use std::cmp::max;
use std::cell::RefCell;
use regex::Regex;

const BONUS_UPPER_MATCH: i64 = 10;
const BONUS_ADJACENCY: i64 = 10;
const BONUS_SEPARATOR: i64 = 8;
const BONUS_CAMEL: i64 = 8;
const PENALTY_CASE_UNMATCHED: i64 = -1;
const PENALTY_LEADING: i64 = -6; // penalty applied for every letter before the first match
const PENALTY_MAX_LEADING: i64 = -18; // maxing penalty for leading letters
const PENALTY_UNMATCHED: i64 = -2;

use std::io::Write;
macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

// judge how many scores the current index should get
fn fuzzy_score(string: &[char], index: usize, pattern: &[char], pattern_idx: usize) -> i64 {
    let mut score = 0;

    let pattern_char = pattern[pattern_idx];
    let cur = string[index];

    if pattern_char.is_uppercase() && cur.is_uppercase() && pattern_char == cur {
        score += BONUS_UPPER_MATCH;
    } else {
        score += PENALTY_CASE_UNMATCHED;
    }

    if index == 0 {
        return score + if cur.is_uppercase() {BONUS_CAMEL} else {0};
    }

    let prev = string[index-1];

    // apply bonus for matches after a separator
    if prev == ' ' || prev == '_' || prev == '-' || prev == '/' || prev == '\\' {
        score += BONUS_SEPARATOR;
    }

    // apply bonus for camelCases
    if prev.is_lowercase() && cur.is_uppercase() {
        score += BONUS_CAMEL;
    }

    if pattern_idx == 0 {
        score += max((index as i64) * PENALTY_LEADING, PENALTY_MAX_LEADING);
    }

    score
}

pub fn fuzzy_match(choice: &[char],
                   pattern: &[char],
                   pattern_lower: &[char]) -> Option<(i64, Vec<usize>)>{
    if pattern.len() == 0 {
        return Some((0, Vec::new()));
    }

    let mut scores = vec![];
    let mut picked = vec![];

    let mut prev_matched_idx = -1; // to ensure that the pushed char are able to match the pattern
    for (pattern_idx, &pattern_char) in pattern_lower.iter().enumerate() {
        let vec_cell = RefCell::new(vec![]);
        {
            let mut vec = vec_cell.borrow_mut();
            for (idx, &ch) in choice.iter().enumerate() {
                if ch == pattern_char && (idx as i64) > prev_matched_idx {
                    vec.push((idx, fuzzy_score(choice, idx, pattern, pattern_idx), 0)); // (char_idx, score, vec_idx back_ref)
                }
            }

            if vec.is_empty() {
                // not matched
                return None;
            }
            prev_matched_idx = vec[0].0 as i64;
        }
        scores.push(vec_cell);
    }

    for pattern_idx in 0..pattern.len()-1 {
        let cur_row = scores[pattern_idx].borrow();
        let mut next_row = scores[pattern_idx+1].borrow_mut();

        for idx in 0..next_row.len() {
            let (next_char_idx, next_score, _) = next_row[idx];
//(back_ref, &score)
            let (back_ref, score) = cur_row.iter()
                .take_while(|&&(idx, _, _)| idx < next_char_idx)
                .map(|&(char_idx, score, _)| {
                    let adjacent_num = next_char_idx - char_idx - 1;
                    score + next_score + if adjacent_num == 0 {BONUS_ADJACENCY} else {PENALTY_UNMATCHED * adjacent_num as i64}
                })
                .enumerate()
                .max_by_key(|&(_, x)| x)
                .unwrap();

            next_row[idx] = (next_char_idx, score, back_ref);
        }
    }

    let (mut next_col, &(_, score, _)) = scores[pattern.len()-1].borrow().iter().enumerate().max_by_key(|&(_, &x)| x.1).unwrap();
    let mut pattern_idx = pattern.len() as i64 - 1;
    while pattern_idx >= 0 {
        let (idx, _, next) = scores[pattern_idx as usize].borrow()[next_col];
        next_col = next;
        picked.push(idx);
        pattern_idx -= 1;
    }
    picked.reverse();
    Some((score, picked))
}

pub fn regex_match(choice: &str, pattern: &Option<Regex>) -> Option<(i64, i64)>{
    match *pattern {
        Some(ref pat) => {
            let ret = pat.find(choice);
            if ret.is_none() {
                return None;
            }

            let (start, end) = ret.unwrap();
            let first = (&choice[0..start]).chars().count();
            let last = first + (&choice[start..end]).chars().count();
            Some((first as i64, last as i64))
        }
        None => None,
    }
}

// Pattern may appear in sevearl places, return the first and last occurrence
pub fn exact_match(choice: &str, pattern: &str) -> Option<((usize, usize), (usize, usize))>{
    // search from the start
    let start_pos = choice.find(pattern);
    if start_pos.is_none() {return None};

    let pattern_len = pattern.chars().count();

    let first_occur = start_pos.map(|s| {
        let start = if s == 0 { 0 } else { (&choice[0..s]).chars().count() };
        (start, start + pattern_len)
    }).unwrap();

    let last_pos = choice.rfind(pattern);
    if last_pos.is_none() {return None};
    let last_occur = last_pos.map(|s| {
        let start = if s == 0 { 0 } else { (&choice[0..s]).chars().count() };
        (start, start + pattern_len)
    }).unwrap();

    Some((first_occur, last_occur))
}

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

    //#[test]
    //fn teset_fuzzy_match() {
        //// the score in this test doesn't actually matter, but the index matters.
        //let choice_1 = "1111121";
        //let query_1 = "21";
        //assert_eq!(fuzzy_match(&choice_1, &query_1), Some((-10, vec![5,6])));

        //let choice_2 = "Ca";
        //let query_2 = "ac";
        //assert_eq!(fuzzy_match(&choice_2, &query_2), None);

        //let choice_3 = ".";
        //let query_3 = "s";
        //assert_eq!(fuzzy_match(&choice_3, &query_3), None);

        //let choice_4 = "AaBbCc";
        //let query_4 = "abc";
        //assert_eq!(fuzzy_match(&choice_4, &query_4), Some((53, vec![0,2,4])));
    //}
}
<|endoftext|>


<commit_before>use super::{max, min};

/// Trait for setting up anisotropic distance function computation.
///
/// Represents the __dual norm__ of the desired anisotropic norm.
///
/// `V` is the vector type, either `[S; 2]` or `[S; 3]` and `S` is the scalar type, usually `f64`.
///
pub trait DualNorm<V, S> {
    /// `dual_norm` returns the __dual__ norm. It must be a positively one-homogeneous function.
    fn dual_norm(&self, p: V) -> S;
    /// Solves the "inverse problem" for the norm: Given values `v_i` at points `-s_i e_i` (`e_i`
    /// is the canonical basis), find the largest value `t ≤ d` at the origin such that `||p|| ≤
    /// 1`, where `p_i = s_i (t - v_i)_+` and `||p||` is the __dual__ anisotropic norm.
    fn inv_dual_norm(&self, d: S, v: V, s: V) -> S;
}

/// Euclidean (l^2) norm
pub struct EuclideanNorm;

/// Dual norm for the max (l^∞) norm is the l^1 norm.
impl DualNorm<[f64; 2], f64> for EuclideanNorm {
    fn dual_norm(&self, p: [f64; 2]) -> f64 {
        (p[0] * p[0] + p[1] * p[1]).sqrt()
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 2], _: [f64; 2]) -> f64 {
        let a = v[0];
        let b = v[1];

        let x = if (a - b).abs() >= 1. {
            min(a, b) + 1.
        } else {
            0.5 * (a + b + (2. - (a - b) * (a - b)).sqrt())
        };

        min(d, x)
    }
}

/// Dual norm for the max (l^∞) norm is the l^1 norm.
impl DualNorm<[f64; 3], f64> for EuclideanNorm {
    fn dual_norm(&self, p: [f64; 3]) -> f64 {
        (p[0] * p[0] + p[1] * p[1] + p[2] * p[2]).sqrt()
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 3], _: [f64; 3]) -> f64 {
        let (a, b, c) = {
            use std::mem::swap;
            let mut a = v[0];
            let mut b = v[1];
            let mut c = v[2];

            if a > b {
                swap(&mut a, &mut b);
            }
            if b > c {
                swap(&mut b, &mut c);
            }
            if a > b {
                swap(&mut a, &mut b);
            }

            (a, b, c)
        };

        let x = if b >= a + 1. {
            a + 1.
        } else {
            let x = 0.5 * (a + b + (2. - (a - b) * (a - b)).sqrt());
            if x <= c {
                x
            } else {
                let v = (1. / 3.)
                    * (a + b + c
                        + (3. + (a + b + c).powi(2) - 3. * (a * a + b * b + c * c)).sqrt());
                v
            }
        };

        min(d, x)
    }
}

/// l^1 (taxicab, Manhattan) norm
pub struct L1Norm;

/// Dual norm for the l^1 norm is the l^∞ norm.
impl DualNorm<[f64; 2], f64> for L1Norm {
    fn dual_norm(&self, p: [f64; 2]) -> f64 {
        max(p[0].abs(), p[1].abs())
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 2], _: [f64; 2]) -> f64 {
        min(d, min(v[0], v[1]) + 1.)
    }
}

/// Maximum (l^∞) norm
pub struct MaxNorm;

/// Dual norm for the max (l^∞) norm is the l^1 norm.
impl DualNorm<[f64; 2], f64> for MaxNorm {
    fn dual_norm(&self, p: [f64; 2]) -> f64 {
        p[0].abs() + p[1].abs()
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 2], _: [f64; 2]) -> f64 {
        min(min(d, v[0] + 1.), min(v[1] + 1., 0.5 * (v[0] + v[1] + 1.)))
    }
}

/// Dual norm for the max (l^∞) norm is the l^1 norm.
impl DualNorm<[f64; 3], f64> for MaxNorm {
    fn dual_norm(&self, p: [f64; 3]) -> f64 {
        p[0].abs() + p[1].abs() + p[2].abs()
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 3], _: [f64; 3]) -> f64 {
        let (a, b, c) = {
            use std::mem::swap;
            let mut a = v[0];
            let mut b = v[1];
            let mut c = v[2];

            if a > b {
                swap(&mut a, &mut b);
            }
            if b > c {
                swap(&mut b, &mut c);
            }
            if a > b {
                swap(&mut a, &mut b);
            }

            (a, b, c)
        };
        min(
            min(d, a + 1.),
            min(0.5 * (a + b + 1.), (1. / 3.) * (a + b + c + 1.)),
        )
    }
}

/// Convenience function to test the consistency of the `inv_dual_norm` implementation with
/// `dual_norm` by generating vectors on a `(n + 1)^3` grid with values in the interval [-m, m].
pub fn test_inv_dual_norm_2d<N>(norm: N, m: f64, n: u32)
where
    N: DualNorm<[f64; 2], f64>,
{
    let h = 2. * m / n as f64;

    for i in 0..(n + 1) {
        for j in 0..(n + 1) {
            let v = [i as f64 * h - m, j as f64 * h - m];
            let s = [-v[0].signum(), -v[1].signum()];
            let t = norm.inv_dual_norm(0., v, s);
            assert!(t <= 0., "returned t > d");

            let x = norm.dual_norm([s[0] * (t - v[0]).max(0.), s[1] * (t - v[1]).max(0.)]);
            if t < 0. {
                assert!((x - 1.).abs() < 1e-7, "t = {}, v = {:?}, s = {:?}", t, v, s);
            } else {
                assert!(t < 1. + 1e-7, "t = {}, v = {:?}, s = {:?}", t, v, s);
            }
        }
    }
}

/// Convenience function to test the consistency of the `inv_dual_norm` implementation with
/// `dual_norm` by generating vectors on a `(n + 1)^3` grid with values in the interval [-m, m].
pub fn test_inv_dual_norm_3d<N>(norm: N, m: f64, n: u32)
where
    N: DualNorm<[f64; 3], f64>,
{
    let h = 2. * m / n as f64;

    for i in 0..(n + 1) {
        for j in 0..(n + 1) {
            for k in 0..(n + 1) {
                let v = [i as f64 * h - m, j as f64 * h - m, k as f64 * h - m];
                let s = [-v[0].signum(), -v[1].signum(), -v[2].signum()];
                let t = norm.inv_dual_norm(0., v, s);
                assert!(t <= 0.);

                let x = norm.dual_norm([
                    s[0] * (t - v[0]).max(0.),
                    s[1] * (t - v[1]).max(0.),
                    s[2] * (t - v[2]).max(0.),
                ]);
                if t < 0. {
                    assert!(
                        (x - 1.).abs() < 1e-7,
                        "dual_norm = {}, t = {}, v = {:?}, s = {:?}",
                        x,
                        t,
                        v,
                        s
                    );
                } else {
                    assert!(
                        t < 1. + 1e-7,
                        "dual_norm = {}, t = {}, v = {:?}, s = {:?}",
                        x,
                        t,
                        v,
                        s
                    );
                }
            }
        }
    }
}

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

    #[test]
    fn dual_norm_max_norm() {
        test_inv_dual_norm_2d(MaxNorm, 2., 5);
        test_inv_dual_norm_3d(MaxNorm, 2., 5);
    }

    #[test]
    fn dual_norm_euclidean_norm() {
        test_inv_dual_norm_2d(EuclideanNorm, 2., 5);
        test_inv_dual_norm_3d(EuclideanNorm, 2., 5);
    }

    #[test]
    fn dual_norm_l1_norm() {
        test_inv_dual_norm_2d(L1Norm, 2., 5);
    }
}
<commit_msg>module comment<commit_after>//! Norms for the computation of anisotropic distance functions.
//!
//! For the fast sweeping algorithm, it is necessary to know the dual norm (convex polar) of the
//! desired norm, not the norm itself. This is captured by the trait `DualNorm`.
//!
//! The correctness of the implementation can be tested using `test_inv_dual_norm_2d` and
//! `test_inv_dual_norm_3d` functions.
use super::{max, min};

/// Trait for setting up anisotropic distance function computation.
///
/// Represents the __dual norm__ of the desired anisotropic norm.
///
/// `V` is the vector type, either `[S; 2]` or `[S; 3]` and `S` is the scalar type, usually `f64`.
///
pub trait DualNorm<V, S> {
    /// `dual_norm` returns the __dual__ norm. It must be a positively one-homogeneous function.
    fn dual_norm(&self, p: V) -> S;
    /// Solves the "inverse problem" for the norm: Given values `v_i` at points `-s_i e_i` (`e_i`
    /// is the canonical basis), find the largest value `t ≤ d` at the origin such that `||p|| ≤
    /// 1`, where `p_i = s_i (t - v_i)_+` and `||p||` is the __dual__ anisotropic norm.
    fn inv_dual_norm(&self, d: S, v: V, s: V) -> S;
}

/// Euclidean (l^2) norm
pub struct EuclideanNorm;

/// Dual norm for the max (l^∞) norm is the l^1 norm.
impl DualNorm<[f64; 2], f64> for EuclideanNorm {
    fn dual_norm(&self, p: [f64; 2]) -> f64 {
        (p[0] * p[0] + p[1] * p[1]).sqrt()
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 2], _: [f64; 2]) -> f64 {
        let a = v[0];
        let b = v[1];

        let x = if (a - b).abs() >= 1. {
            min(a, b) + 1.
        } else {
            0.5 * (a + b + (2. - (a - b) * (a - b)).sqrt())
        };

        min(d, x)
    }
}

/// Dual norm for the max (l^∞) norm is the l^1 norm.
impl DualNorm<[f64; 3], f64> for EuclideanNorm {
    fn dual_norm(&self, p: [f64; 3]) -> f64 {
        (p[0] * p[0] + p[1] * p[1] + p[2] * p[2]).sqrt()
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 3], _: [f64; 3]) -> f64 {
        let (a, b, c) = {
            use std::mem::swap;
            let mut a = v[0];
            let mut b = v[1];
            let mut c = v[2];

            if a > b {
                swap(&mut a, &mut b);
            }
            if b > c {
                swap(&mut b, &mut c);
            }
            if a > b {
                swap(&mut a, &mut b);
            }

            (a, b, c)
        };

        let x = if b >= a + 1. {
            a + 1.
        } else {
            let x = 0.5 * (a + b + (2. - (a - b) * (a - b)).sqrt());
            if x <= c {
                x
            } else {
                let v = (1. / 3.)
                    * (a + b + c
                        + (3. + (a + b + c).powi(2) - 3. * (a * a + b * b + c * c)).sqrt());
                v
            }
        };

        min(d, x)
    }
}

/// l^1 (taxicab, Manhattan) norm
pub struct L1Norm;

/// Dual norm for the l^1 norm is the l^∞ norm.
impl DualNorm<[f64; 2], f64> for L1Norm {
    fn dual_norm(&self, p: [f64; 2]) -> f64 {
        max(p[0].abs(), p[1].abs())
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 2], _: [f64; 2]) -> f64 {
        min(d, min(v[0], v[1]) + 1.)
    }
}

/// Maximum (l^∞) norm
pub struct MaxNorm;

/// Dual norm for the max (l^∞) norm is the l^1 norm.
impl DualNorm<[f64; 2], f64> for MaxNorm {
    fn dual_norm(&self, p: [f64; 2]) -> f64 {
        p[0].abs() + p[1].abs()
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 2], _: [f64; 2]) -> f64 {
        min(min(d, v[0] + 1.), min(v[1] + 1., 0.5 * (v[0] + v[1] + 1.)))
    }
}

/// Dual norm for the max (l^∞) norm is the l^1 norm.
impl DualNorm<[f64; 3], f64> for MaxNorm {
    fn dual_norm(&self, p: [f64; 3]) -> f64 {
        p[0].abs() + p[1].abs() + p[2].abs()
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 3], _: [f64; 3]) -> f64 {
        let (a, b, c) = {
            use std::mem::swap;
            let mut a = v[0];
            let mut b = v[1];
            let mut c = v[2];

            if a > b {
                swap(&mut a, &mut b);
            }
            if b > c {
                swap(&mut b, &mut c);
            }
            if a > b {
                swap(&mut a, &mut b);
            }

            (a, b, c)
        };
        min(
            min(d, a + 1.),
            min(0.5 * (a + b + 1.), (1. / 3.) * (a + b + c + 1.)),
        )
    }
}

/// Convenience function to test the consistency of the `inv_dual_norm` implementation with
/// `dual_norm` by generating vectors on a `(n + 1)^3` grid with values in the interval [-m, m].
pub fn test_inv_dual_norm_2d<N>(norm: N, m: f64, n: u32)
where
    N: DualNorm<[f64; 2], f64>,
{
    let h = 2. * m / n as f64;

    for i in 0..(n + 1) {
        for j in 0..(n + 1) {
            let v = [i as f64 * h - m, j as f64 * h - m];
            let s = [-v[0].signum(), -v[1].signum()];
            let t = norm.inv_dual_norm(0., v, s);
            assert!(t <= 0., "returned t > d");

            let x = norm.dual_norm([s[0] * (t - v[0]).max(0.), s[1] * (t - v[1]).max(0.)]);
            if t < 0. {
                assert!((x - 1.).abs() < 1e-7, "t = {}, v = {:?}, s = {:?}", t, v, s);
            } else {
                assert!(t < 1. + 1e-7, "t = {}, v = {:?}, s = {:?}", t, v, s);
            }
        }
    }
}

/// Convenience function to test the consistency of the `inv_dual_norm` implementation with
/// `dual_norm` by generating vectors on a `(n + 1)^3` grid with values in the interval [-m, m].
pub fn test_inv_dual_norm_3d<N>(norm: N, m: f64, n: u32)
where
    N: DualNorm<[f64; 3], f64>,
{
    let h = 2. * m / n as f64;

    for i in 0..(n + 1) {
        for j in 0..(n + 1) {
            for k in 0..(n + 1) {
                let v = [i as f64 * h - m, j as f64 * h - m, k as f64 * h - m];
                let s = [-v[0].signum(), -v[1].signum(), -v[2].signum()];
                let t = norm.inv_dual_norm(0., v, s);
                assert!(t <= 0.);

                let x = norm.dual_norm([
                    s[0] * (t - v[0]).max(0.),
                    s[1] * (t - v[1]).max(0.),
                    s[2] * (t - v[2]).max(0.),
                ]);
                if t < 0. {
                    assert!(
                        (x - 1.).abs() < 1e-7,
                        "dual_norm = {}, t = {}, v = {:?}, s = {:?}",
                        x,
                        t,
                        v,
                        s
                    );
                } else {
                    assert!(
                        t < 1. + 1e-7,
                        "dual_norm = {}, t = {}, v = {:?}, s = {:?}",
                        x,
                        t,
                        v,
                        s
                    );
                }
            }
        }
    }
}

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

    #[test]
    fn dual_norm_max_norm() {
        test_inv_dual_norm_2d(MaxNorm, 2., 5);
        test_inv_dual_norm_3d(MaxNorm, 2., 5);
    }

    #[test]
    fn dual_norm_euclidean_norm() {
        test_inv_dual_norm_2d(EuclideanNorm, 2., 5);
        test_inv_dual_norm_3d(EuclideanNorm, 2., 5);
    }

    #[test]
    fn dual_norm_l1_norm() {
        test_inv_dual_norm_2d(L1Norm, 2., 5);
    }
}
<|endoftext|>


<commit_before>use std;
use libc::c_void;

use ffi;
use ffi::{Direction, MeasureMode, Size};
use context::Context;
use measure::measure;

#[derive(Debug)]
pub struct Node {
    pub _node: *mut ffi::Node, // TODO Into/From trait
}

impl Node {
    pub fn new() -> Node {
        Node { _node: unsafe { ffi::YGNodeNew() } }
    }

    pub fn get_instance_count() -> i32 {
        unsafe { ffi::YGNodeGetInstanceCount() }
    }

    pub fn reset(&mut self) {
        unsafe { ffi::YGNodeReset(self._node) }
    }

    pub fn free(self) {
        unsafe { ffi::YGNodeFree(self._node) }
    }

    pub fn free_recursive(self) {
        unsafe { ffi::YGNodeFreeRecursive(self._node) }
    }

    pub fn set_direction(&mut self, value: ffi::Direction) {
        unsafe { ffi::YGNodeStyleSetDirection(self._node, value) }
    }

    pub fn get_direction(&self) -> ffi::Direction {
        unsafe { ffi::YGNodeStyleGetDirection(self._node) }
    }

    pub fn set_flex_direction(&mut self, value: ffi::FlexDirection) {
        unsafe { ffi::YGNodeStyleSetFlexDirection(self._node, value) }
    }

    pub fn get_flex_direction(&self) -> ffi::FlexDirection {
        unsafe { ffi::YGNodeStyleGetFlexDirection(self._node) }
    }

    pub fn set_width(&mut self, width: f32) {
        unsafe { ffi::YGNodeStyleSetWidth(self._node, width) }
    }

    pub fn get_width(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetWidth(self._node) }
    }

    pub fn set_height(&mut self, height: f32) {
        unsafe { ffi::YGNodeStyleSetHeight(self._node, height) }
    }

    pub fn get_height(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetHeight(self._node) }
    }

    pub fn calculate_layout(&mut self) {
        unsafe {
            ffi::YGNodeCalculateLayout(self._node, std::f32::NAN, std::f32::NAN, Direction::LTR)
        }
    }

    pub fn get_layout_width(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetWidth(self._node) }
    }

    pub fn get_layout_height(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetHeight(self._node) }
    }

    pub fn get_layout_left(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetLeft(self._node) }
    }

    pub fn get_layout_top(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetTop(self._node) }
    }

    pub fn get_layout_direction(&self) -> ffi::Direction {
        unsafe { ffi::YGNodeLayoutGetDirection(self._node) }
    }

    pub fn insert_child(&mut self, child: &Node, index: u32) {
        unsafe { ffi::YGNodeInsertChild(self._node, child._node, index) }
    }

    pub fn remove_child(&mut self, child: &Node) {
        unsafe { ffi::YGNodeRemoveChild(self._node, child._node) }
    }

    pub fn get_child(&self, index: u32) -> Node {
        // FIXME this is wrong
        // also prevents Drop impl for Node
        unsafe { Node { _node: ffi::YGNodeGetChild(self._node, index) } }
    }

    pub fn get_child_count(&self) -> u32 {
        unsafe { ffi::YGNodeGetChildCount(self._node) }
    }

    pub fn get_parent(&self) -> Node {
        // FIXME this is wrong
        // also prevents Drop impl for Node
        unsafe { Node { _node: ffi::YGNodeGetParent(self._node) } }
    }

    pub fn set_justify_content(&mut self, value: ffi::JustifyContent) {
        unsafe { ffi::YGNodeStyleSetJustifyContent(self._node, value) }
    }

    pub fn get_justify_content(&self) -> ffi::JustifyContent {
        unsafe { ffi::YGNodeStyleGetJustifyContent(self._node) }
    }

    pub fn get_align_items(&self) -> ffi::Align {
        unsafe { ffi::YGNodeStyleGetAlignItems(self._node) }
    }

    pub fn set_align_items(&mut self, value: ffi::Align) {
        unsafe { ffi::YGNodeStyleSetAlignItems(self._node, value) }
    }

    pub fn get_align_self(&self) -> ffi::Align {
        unsafe { ffi::YGNodeStyleGetAlignSelf(self._node) }
    }

    pub fn set_align_self(&mut self, value: ffi::Align) {
        unsafe { ffi::YGNodeStyleSetAlignSelf(self._node, value) }
    }

    pub fn get_align_content(&self) -> ffi::Align {
        unsafe { ffi::YGNodeStyleGetAlignContent(self._node) }
    }

    pub fn set_align_content(&mut self, value: ffi::Align) {
        unsafe { ffi::YGNodeStyleSetAlignContent(self._node, value) }
    }

    pub fn get_position_type(&self) -> ffi::PositionType {
        unsafe { ffi::YGNodeStyleGetPositionType(self._node) }
    }

    pub fn set_position_type(&mut self, value: ffi::PositionType) {
        unsafe { ffi::YGNodeStyleSetPositionType(self._node, value) }
    }

    pub fn get_flex_wrap(&self) -> ffi::FlexWrap {
        unsafe { ffi::YGNodeStyleGetFlexWrap(self._node) }
    }

    pub fn set_flex_wrap(&mut self, value: ffi::FlexWrap) {
        unsafe { ffi::YGNodeStyleSetFlexWrap(self._node, value) }
    }

    pub fn get_overflow(&self) -> ffi::Overflow {
        unsafe { ffi::YGNodeStyleGetOverflow(self._node) }
    }

    pub fn set_overflow(&mut self, value: ffi::Overflow) {
        unsafe { ffi::YGNodeStyleSetOverflow(self._node, value) }
    }

    pub fn set_flex(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlex(self._node, value) }
    }

    pub fn get_flex_grow(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetFlexGrow(self._node) }
    }

    pub fn set_flex_grow(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlexGrow(self._node, value) }
    }

    pub fn get_flex_shrink(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetFlexShrink(self._node) }
    }

    pub fn set_flex_shrink(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlexShrink(self._node, value) }
    }

    pub fn get_flex_basis(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetFlexBasis(self._node) }
    }

    pub fn set_flex_basis(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlexBasis(self._node, value) }
    }

    pub fn get_margin(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetMargin(self._node, edge) }
    }

    pub fn set_margin(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetMargin(self._node, edge, value) }
    }

    pub fn get_padding(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetPadding(self._node, edge) }
    }

    pub fn set_padding(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetPadding(self._node, edge, value) }
    }

    pub fn get_border(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetBorder(self._node, edge) }
    }

    pub fn set_border(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetBorder(self._node, edge, value) }
    }

    pub fn get_position(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetPosition(self._node, edge) }
    }

    pub fn set_position(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetPosition(self._node, edge, value) }
    }

    pub fn set_measure_func(&mut self,
                            func: extern "C" fn(*mut ffi::Node,
                                                f32,
                                                MeasureMode,
                                                f32,
                                                MeasureMode)
                                                -> Size) {
        unsafe { ffi::YGNodeSetMeasureFunc(self._node, func) }
    }

    pub fn mark_dirty(&mut self) {
        unsafe { ffi::YGNodeMarkDirty(self._node) }
    }

    pub fn is_dirty(&self) -> bool {
        unsafe { ffi::YGNodeIsDirty(self._node) }
    }

    pub fn set_context(&mut self, context: *mut Context) {
        unsafe { ffi::YGNodeSetContext(self._node, context as *mut c_void) }
    }

    pub fn get_context(&self) -> &Context {
        unsafe {
            let context = ffi::YGNodeGetContext(self._node);
            let ref ctx: Context = *(context as *mut Context);
            ctx
        }
    }
}

#[cfg(test)]
mod tests {
    use Context;
    use Measures;
    use Node;
    use Size;
    use measure::measure;

    struct Measurer {}

    impl Measures for Measurer {
        fn measure(&self, text: &str) -> Size {
            Size {
                width: text.len() as f32,
                height: 1.0,
            }
        }
    }

    #[test]
    fn dirty_works() {
        let mut node = Node::new();
        node.set_measure_func(measure);
        assert!(!node.is_dirty());
        node.mark_dirty();
        assert!(node.is_dirty());
        node.free();
    }

    #[test]
    fn context_works() {
        let mut node = Node::new();
        node.set_context(&mut Context::new("Yo!", &Measurer {}));
        {
            let context = node.get_context();
            assert!(context.measure().width == 3.0);
        }
        node.free();
    }

    #[test]
    fn measure_works() {
        let mut node = Node::new();
        node.set_measure_func(measure);
        node.set_context(&mut Context::new("Yo!!", &Measurer {}));
        node.calculate_layout();
        assert!(node.get_layout_width() == 4.0);
        assert!(node.get_layout_height() == 1.0);
        node.free();
    }

    #[test]
    fn get_instance_count() {
        assert!(Node::get_instance_count() == 0);
        let mut node = Node::new();
        assert!(Node::get_instance_count() == 1);
        node.free();
        assert!(Node::get_instance_count() == 0);
    }

    #[test]
    fn get_child_count() {
        let mut p1 = Node::new();
        let mut c1 = Node::new();
        let mut c2 = Node::new();
        p1.insert_child(&c1, 0);
        p1.insert_child(&c2, 1);
        assert!(p1.get_child_count() == 2);
        p1.free();
        c1.free();
        c2.free();
    }

    #[test]
    fn get_child() {
        let mut p1 = Node::new();

        let mut c1 = Node::new();
        c1.set_width(1.0);

        let mut c2 = Node::new();
        c2.set_width(2.0);

        p1.insert_child(&c1, 0);
        p1.insert_child(&c2, 1);

        assert!(p1.get_child(0).get_width() == 1.0);
        assert!(p1.get_child(1).get_width() == 2.0);
        p1.free();
        c1.free();
        c2.free();
    }
}
<commit_msg>feat(Node): impl Default<commit_after>use std;
use std::default::Default;
use libc::c_void;

use ffi;
use ffi::{Direction, MeasureMode, Size};
use context::Context;
use measure::measure;

#[derive(Debug)]
pub struct Node {
    pub _node: *mut ffi::Node, // TODO Into/From trait
}

impl Default for Node {
    fn default() -> Node {
        Node::new()
    }
}

impl Node {
    pub fn new() -> Node {
        Node { _node: unsafe { ffi::YGNodeNew() } }
    }

    pub fn get_instance_count() -> i32 {
        unsafe { ffi::YGNodeGetInstanceCount() }
    }

    pub fn reset(&mut self) {
        unsafe { ffi::YGNodeReset(self._node) }
    }

    pub fn free(self) {
        unsafe { ffi::YGNodeFree(self._node) }
    }

    pub fn free_recursive(self) {
        unsafe { ffi::YGNodeFreeRecursive(self._node) }
    }

    pub fn set_direction(&mut self, value: ffi::Direction) {
        unsafe { ffi::YGNodeStyleSetDirection(self._node, value) }
    }

    pub fn get_direction(&self) -> ffi::Direction {
        unsafe { ffi::YGNodeStyleGetDirection(self._node) }
    }

    pub fn set_flex_direction(&mut self, value: ffi::FlexDirection) {
        unsafe { ffi::YGNodeStyleSetFlexDirection(self._node, value) }
    }

    pub fn get_flex_direction(&self) -> ffi::FlexDirection {
        unsafe { ffi::YGNodeStyleGetFlexDirection(self._node) }
    }

    pub fn set_width(&mut self, width: f32) {
        unsafe { ffi::YGNodeStyleSetWidth(self._node, width) }
    }

    pub fn get_width(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetWidth(self._node) }
    }

    pub fn set_height(&mut self, height: f32) {
        unsafe { ffi::YGNodeStyleSetHeight(self._node, height) }
    }

    pub fn get_height(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetHeight(self._node) }
    }

    pub fn calculate_layout(&mut self) {
        unsafe {
            ffi::YGNodeCalculateLayout(self._node, std::f32::NAN, std::f32::NAN, Direction::LTR)
        }
    }

    pub fn get_layout_width(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetWidth(self._node) }
    }

    pub fn get_layout_height(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetHeight(self._node) }
    }

    pub fn get_layout_left(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetLeft(self._node) }
    }

    pub fn get_layout_top(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetTop(self._node) }
    }

    pub fn get_layout_direction(&self) -> ffi::Direction {
        unsafe { ffi::YGNodeLayoutGetDirection(self._node) }
    }

    pub fn insert_child(&mut self, child: &Node, index: u32) {
        unsafe { ffi::YGNodeInsertChild(self._node, child._node, index) }
    }

    pub fn remove_child(&mut self, child: &Node) {
        unsafe { ffi::YGNodeRemoveChild(self._node, child._node) }
    }

    pub fn get_child(&self, index: u32) -> Node {
        // FIXME this is wrong
        // also prevents Drop impl for Node
        unsafe { Node { _node: ffi::YGNodeGetChild(self._node, index) } }
    }

    pub fn get_child_count(&self) -> u32 {
        unsafe { ffi::YGNodeGetChildCount(self._node) }
    }

    pub fn get_parent(&self) -> Node {
        // FIXME this is wrong
        // also prevents Drop impl for Node
        unsafe { Node { _node: ffi::YGNodeGetParent(self._node) } }
    }

    pub fn set_justify_content(&mut self, value: ffi::JustifyContent) {
        unsafe { ffi::YGNodeStyleSetJustifyContent(self._node, value) }
    }

    pub fn get_justify_content(&self) -> ffi::JustifyContent {
        unsafe { ffi::YGNodeStyleGetJustifyContent(self._node) }
    }

    pub fn get_align_items(&self) -> ffi::Align {
        unsafe { ffi::YGNodeStyleGetAlignItems(self._node) }
    }

    pub fn set_align_items(&mut self, value: ffi::Align) {
        unsafe { ffi::YGNodeStyleSetAlignItems(self._node, value) }
    }

    pub fn get_align_self(&self) -> ffi::Align {
        unsafe { ffi::YGNodeStyleGetAlignSelf(self._node) }
    }

    pub fn set_align_self(&mut self, value: ffi::Align) {
        unsafe { ffi::YGNodeStyleSetAlignSelf(self._node, value) }
    }

    pub fn get_align_content(&self) -> ffi::Align {
        unsafe { ffi::YGNodeStyleGetAlignContent(self._node) }
    }

    pub fn set_align_content(&mut self, value: ffi::Align) {
        unsafe { ffi::YGNodeStyleSetAlignContent(self._node, value) }
    }

    pub fn get_position_type(&self) -> ffi::PositionType {
        unsafe { ffi::YGNodeStyleGetPositionType(self._node) }
    }

    pub fn set_position_type(&mut self, value: ffi::PositionType) {
        unsafe { ffi::YGNodeStyleSetPositionType(self._node, value) }
    }

    pub fn get_flex_wrap(&self) -> ffi::FlexWrap {
        unsafe { ffi::YGNodeStyleGetFlexWrap(self._node) }
    }

    pub fn set_flex_wrap(&mut self, value: ffi::FlexWrap) {
        unsafe { ffi::YGNodeStyleSetFlexWrap(self._node, value) }
    }

    pub fn get_overflow(&self) -> ffi::Overflow {
        unsafe { ffi::YGNodeStyleGetOverflow(self._node) }
    }

    pub fn set_overflow(&mut self, value: ffi::Overflow) {
        unsafe { ffi::YGNodeStyleSetOverflow(self._node, value) }
    }

    pub fn set_flex(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlex(self._node, value) }
    }

    pub fn get_flex_grow(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetFlexGrow(self._node) }
    }

    pub fn set_flex_grow(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlexGrow(self._node, value) }
    }

    pub fn get_flex_shrink(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetFlexShrink(self._node) }
    }

    pub fn set_flex_shrink(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlexShrink(self._node, value) }
    }

    pub fn get_flex_basis(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetFlexBasis(self._node) }
    }

    pub fn set_flex_basis(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlexBasis(self._node, value) }
    }

    pub fn get_margin(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetMargin(self._node, edge) }
    }

    pub fn set_margin(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetMargin(self._node, edge, value) }
    }

    pub fn get_padding(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetPadding(self._node, edge) }
    }

    pub fn set_padding(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetPadding(self._node, edge, value) }
    }

    pub fn get_border(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetBorder(self._node, edge) }
    }

    pub fn set_border(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetBorder(self._node, edge, value) }
    }

    pub fn get_position(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetPosition(self._node, edge) }
    }

    pub fn set_position(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetPosition(self._node, edge, value) }
    }

    pub fn set_measure_func(&mut self,
                            func: extern "C" fn(*mut ffi::Node,
                                                f32,
                                                MeasureMode,
                                                f32,
                                                MeasureMode)
                                                -> Size) {
        unsafe { ffi::YGNodeSetMeasureFunc(self._node, func) }
    }

    pub fn mark_dirty(&mut self) {
        unsafe { ffi::YGNodeMarkDirty(self._node) }
    }

    pub fn is_dirty(&self) -> bool {
        unsafe { ffi::YGNodeIsDirty(self._node) }
    }

    pub fn set_context(&mut self, context: *mut Context) {
        unsafe { ffi::YGNodeSetContext(self._node, context as *mut c_void) }
    }

    pub fn get_context(&self) -> &Context {
        unsafe {
            let context = ffi::YGNodeGetContext(self._node);
            let ref ctx: Context = *(context as *mut Context);
            ctx
        }
    }
}

#[cfg(test)]
mod tests {
    use Context;
    use Measures;
    use Node;
    use Size;
    use measure::measure;

    struct Measurer {}

    impl Measures for Measurer {
        fn measure(&self, text: &str) -> Size {
            Size {
                width: text.len() as f32,
                height: 1.0,
            }
        }
    }

    #[test]
    fn dirty_works() {
        let mut node = Node::new();
        node.set_measure_func(measure);
        assert!(!node.is_dirty());
        node.mark_dirty();
        assert!(node.is_dirty());
        node.free();
    }

    #[test]
    fn context_works() {
        let mut node = Node::new();
        node.set_context(&mut Context::new("Yo!", &Measurer {}));
        {
            let context = node.get_context();
            assert!(context.measure().width == 3.0);
        }
        node.free();
    }

    #[test]
    fn measure_works() {
        let mut node = Node::new();
        node.set_measure_func(measure);
        node.set_context(&mut Context::new("Yo!!", &Measurer {}));
        node.calculate_layout();
        assert!(node.get_layout_width() == 4.0);
        assert!(node.get_layout_height() == 1.0);
        node.free();
    }

    #[test]
    fn get_instance_count() {
        assert!(Node::get_instance_count() == 0);
        let mut node = Node::new();
        assert!(Node::get_instance_count() == 1);
        node.free();
        assert!(Node::get_instance_count() == 0);
    }

    #[test]
    fn get_child_count() {
        let mut p1 = Node::new();
        let mut c1 = Node::new();
        let mut c2 = Node::new();
        p1.insert_child(&c1, 0);
        p1.insert_child(&c2, 1);
        assert!(p1.get_child_count() == 2);
        p1.free();
        c1.free();
        c2.free();
    }

    #[test]
    fn get_child() {
        let mut p1 = Node::new();

        let mut c1 = Node::new();
        c1.set_width(1.0);

        let mut c2 = Node::new();
        c2.set_width(2.0);

        p1.insert_child(&c1, 0);
        p1.insert_child(&c2, 1);

        assert!(p1.get_child(0).get_width() == 1.0);
        assert!(p1.get_child(1).get_width() == 2.0);
        p1.free();
        c1.free();
        c2.free();
    }
}
<|endoftext|>


<commit_before>//!
//! Desync pipes provide a way to generate and process streams via a `Desync` object
//!
//! Pipes are an excellent way to interface `Desync` objects and the futures library. Piping
//! a stream into a `Desync` object is equivalent to spawning it with an executor, except
//! without the need to dedicate a thread to running it.
//!
//! There are two kinds of pipe. The `pipe_in` function creates a pipe that processes each
//! value made available from a stream on a desync object as they arrive, producing no
//! results. This is useful for cases where a `Desync` object is being used as the endpoint
//! for some data processing (for example, to insert the results of an operation into an
//! asynchronous database object).
//!
//! The `pipe` function pipes data through an object. For every input value, it produces
//! an output value. This is good for creating streams that perform some kind of asynchronous
//! processing operation or that need to access data from inside a `Desync` object.
//!
//! Here's an example of using `pipe_in` to store data in a `HashSet`:
//!
//! ```
//! # extern crate futures;
//! # extern crate desync;
//! # use std::collections::HashSet;
//! # use std::sync::*;
//! #
//! use futures::sync::mpsc;
//! use futures::executor;
//! use desync::*;
//!
//! let desync_hashset      = Arc::new(Desync::new(HashSet::new()));
//! let (sender, receiver)  = mpsc::channel(5);
//!
//! pipe_in(Arc::clone(&desync_hashset), receiver, |hashset, value| { value.map(|value| hashset.insert(value)); });
//!
//! let mut sender = executor::spawn(sender);
//! sender.wait_send("Test".to_string());
//! sender.wait_send("Another value".to_string());
//! #
//! # assert!(desync_hashset.sync(|hashset| hashset.contains(&("Test".to_string()))))
//! ```
//!

use super::desync::*;

use futures::*;
use futures::executor;
use futures::executor::Spawn;

use std::sync::*;
use std::result::Result;
use std::collections::VecDeque;

lazy_static! {
    /// The shared queue where we monitor for updates to the active pipe streams
    static ref PIPE_MONITOR: PipeMonitor = PipeMonitor::new();
}

/// The maximum number of items to queue on a pipe stream before we stop accepting new input
const PIPE_BACKPRESSURE_COUNT: usize = 5;

///
/// Pipes a stream into a desync object. Whenever an item becomes available on the stream, the
/// processing function is called asynchronously with the item that was received.
///
/// This takes a weak reference to the passed in `Desync` object, so the pipe will stop if it's
/// the only thing referencing this object.
///
/// Piping a stream to a `Desync` like this will cause it to start executing: ie, this is
/// similar to calling `executor::spawn(stream)`, except that the stream will immediately
/// start draining into the `Desync` object.
///
pub fn pipe_in<Core, S, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn)
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> () {

    // Need a mutable version of the stream
    let mut stream = stream;

    // We stop processing once the desync object is no longer used anywhere else
    let desync = Arc::downgrade(&desync);

    // Wrap the process fn up so we can call it asynchronously
    // (it doesn't really need to be in a mutex as it's only called by our object but we need to make it pass Rust's checks and we don't have a way to specify this at the moment)
    let process = Arc::new(Mutex::new(process));

    // Monitor the stream
    PIPE_MONITOR.monitor(move || {
        loop {
            let desync      = desync.upgrade();

            if let Some(desync) = desync {
                // Read the current status of the stream
                let process     = Arc::clone(&process);
                let next        = stream.poll();

                match next {
                    // Just wait if the stream is not ready
                    Ok(Async::NotReady) => { return Ok(Async::NotReady); },

                    // Stop processing when the stream is finished
                    Ok(Async::Ready(None)) => { return Ok(Async::Ready(())); }

                    // Stream returned a value
                    Ok(Async::Ready(Some(next))) => {
                        // Process the value on the stream
                        desync.async(move |core| {
                            let mut process = process.lock().unwrap();
                            let process     = &mut *process;
                            process(core, Ok(next));
                        });
                    },

                    // Stream returned an error
                    Err(e) => {
                        // Process the error on the stream
                        desync.async(move |core| {
                            let mut process = process.lock().unwrap();
                            let process     = &mut *process;
                            process(core, Err(e));
                        });
                    },
                }
            } else {
                // The desync target is no longer available - indicate that we've completed monitoring
                return Ok(Async::Ready(()));
            }
        }
    });
}

///
/// Pipes a stream into this object. Whenever an item becomes available on the stream, the
/// processing function is called asynchronously with the item that was received. The
/// return value is placed onto the output stream.
///
/// Unlike `pipe_in`, this keeps a strong reference to the `Desync` object so the processing
/// will continue so long as the input stream has data and the output stream is not dropped.
///
/// The input stream will start executing and reading values immediately when this is called.
/// Dropping the output stream will cause the pipe to be closed (the input stream will be
/// dropped and no further processing will occur).
///
/// This example demonstrates how to create a simple demonstration pipe that takes hashset values
/// and returns a stream indicating whether or not they were already included:
///
/// ```
/// # extern crate futures;
/// # extern crate desync;
/// # use std::collections::HashSet;
/// # use std::sync::*;
/// #
/// use futures::sync::mpsc;
/// use futures::executor;
/// use desync::*;
///
/// let desync_hashset      = Arc::new(Desync::new(HashSet::new()));
/// let (sender, receiver)  = mpsc::channel::<String>(5);
///
/// let value_inserted = pipe(Arc::clone(&desync_hashset), receiver,
///     |hashset, value| { value.map(|value| (value.clone(), hashset.insert(value))) });
///
/// let mut sender = executor::spawn(sender);
/// sender.wait_send("Test".to_string());
/// sender.wait_send("Another value".to_string());
/// sender.wait_send("Test".to_string());
///
/// let mut value_inserted = executor::spawn(value_inserted);
/// assert!(value_inserted.wait_stream() == Some(Ok(("Test".to_string(), true))));
/// assert!(value_inserted.wait_stream() == Some(Ok(("Another value".to_string(), true))));
/// assert!(value_inserted.wait_stream() == Some(Ok(("Test".to_string(), false))));
/// ```
///
pub fn pipe<Core, S, Output, OutputErr, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn) -> PipeStream<Output, OutputErr>
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        Output:     'static+Send,
        OutputErr:  'static+Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> Result<Output, OutputErr> {

    // Fetch the input stream and prepare the process function for async calling
    let mut input_stream    = stream;
    let process             = Arc::new(Mutex::new(process));

    // Create the output stream
    let output_stream   = PipeStream::new();
    let stream_core     = Arc::clone(&output_stream.core);
    let stream_core     = Arc::downgrade(&stream_core);

    // Monitor the input stream and pass data to the output stream
    PIPE_MONITOR.monitor(move || {
        loop {
            let stream_core = stream_core.upgrade();

            if let Some(stream_core) = stream_core {
                // Defer processing if the stream core is full
                {
                    // Fetch the core
                    let mut stream_core = stream_core.lock().unwrap();

                    // If the pending queue is full, then stop processing events
                    if stream_core.pending.len() >= stream_core.max_pipe_depth {
                        // Wake when the stream accepts some input
                        stream_core.backpressure_release_notify = Some(task::current());

                        // Go back to sleep without reading from the stream
                        return Ok(Async::NotReady);
                    }
                }

                // Read the current status of the stream
                let process         = Arc::clone(&process);
                let next            = input_stream.poll();
                let mut next_item;

                // Work out what the next item to pass to the process function should be
                match next {
                    // Just wait if the stream is not ready
                    Ok(Async::NotReady) => { return Ok(Async::NotReady); },

                    // Stop processing when the input stream is finished
                    Ok(Async::Ready(None)) => {
                        // Mark the target stream as closed
                        let mut stream_core = stream_core.lock().unwrap();
                        stream_core.closed = true;
                        stream_core.notify.take().map(|notify| notify.notify());

                        // Pipe has finished
                        return Ok(Async::Ready(()));
                    }

                    // Stream returned a value
                    Ok(Async::Ready(Some(next))) => next_item = Ok(next),

                    // Stream returned an error
                    Err(e) => next_item = Err(e),
                }

                // Send the next item to be processed
                desync.async(move |core| {
                    // Process the next item
                    let mut process     = process.lock().unwrap();
                    let process         = &mut *process;
                    let next_item       = process(core, next_item);

                    // Send to the pipe stream
                    let mut stream_core = stream_core.lock().unwrap();

                    stream_core.pending.push_back(next_item);
                    stream_core.notify.take().map(|notify| notify.notify());
                });

            } else {
                // We stop processing once nothing is reading from the target stream
                return Ok(Async::Ready(()));
            }
        }
    });

    // The pipe stream is the result
    output_stream
}

///
/// The shared data for a pipe stream
///
struct PipeStreamCore<Item, Error>  {
    /// The maximum number of items we allow to be queued in this stream before producing backpressure
    max_pipe_depth: usize,

    /// The pending data for this stream
    pending: VecDeque<Result<Item, Error>>,

    /// True if the input stream has closed (the stream is closed once this is true and there are no more pending items)
    closed: bool,

    /// The task to notify when the stream changes
    notify: Option<task::Task>,

    /// The task to notify when we reduce the amount of pending data
    backpressure_release_notify: Option<task::Task>
}

///
/// A stream generated by a pipe
///
pub struct PipeStream<Item, Error> {
    core: Arc<Mutex<PipeStreamCore<Item, Error>>>
}

impl<Item, Error> PipeStream<Item, Error> {
    ///
    /// Creates a new, empty, pipestream
    ///
    fn new() -> PipeStream<Item, Error> {
        PipeStream {
            core: Arc::new(Mutex::new(PipeStreamCore {
                max_pipe_depth:                 PIPE_BACKPRESSURE_COUNT,
                pending:                        VecDeque::new(),
                closed:                         false,
                notify:                         None,
                backpressure_release_notify:    None
            }))
        }
    }

    ///
    /// Sets the number of items that this pipe stream will buffer before producing backpressure
    ///
    /// If this call is not made, this will be set to 5.
    ///
    pub fn set_backpressure_depth(&mut self, max_depth: usize) {
        self.core.lock().unwrap().max_pipe_depth = max_depth;
    }
}

impl<Item, Error> Drop for PipeStream<Item, Error> {
    fn drop(&mut self) {
        let mut core = self.core.lock().unwrap();

        // Flush the pending queue
        core.pending = VecDeque::new();

        // TODO: wake the monitor and stop listening to the source stream
        // (Right now this will happen next time the source stream produces data)
    }
}

impl<Item, Error> Stream for PipeStream<Item, Error> {
    type Item   = Item;
    type Error  = Error;

    fn poll(&mut self) -> Poll<Option<Item>, Error> {
        // Fetch the core
        let mut core = self.core.lock().unwrap();

        if let Some(item) = core.pending.pop_front() {
            // Value waiting at the start of the stream
            core.backpressure_release_notify.take().map(|notify| notify.notify());

            match item {
                Ok(item)    => Ok(Async::Ready(Some(item))),
                Err(erm)    => Err(erm)
            }
        } else if core.closed {
            // No more data will be returned from this stream
            Ok(Async::Ready(None))
        } else {
            // Stream not ready
            core.notify = Some(task::current());

            Ok(Async::NotReady)
        }
    }
}

///
/// The main polling component for that implements the stream pipes
///
struct PipeMonitor {
}

///
/// Provides the 'Notify' interface for a polling function with a particular ID
///
struct PipeNotify<PollFn: Send> {
    next_poll: Arc<Desync<Option<Spawn<PollFn>>>>
}

impl PipeMonitor {
    ///
    /// Creates a new poll thread
    ///
    pub fn new() -> PipeMonitor {
        PipeMonitor {
        }
    }

    ///
    /// Performs a polling operation on a poll
    ///
    fn poll<PollFn>(this_poll: &mut Option<Spawn<PollFn>>, next_poll: Arc<Desync<Option<Spawn<PollFn>>>>)
    where PollFn: 'static+Send+Future<Item=(), Error=()> {
        // If the polling function exists...
        if let Some(mut poll) = this_poll.take() {
            // Create a notification
            let notify = PipeNotify {
                next_poll: next_poll
            };
            let notify = Arc::new(notify);

            // Poll the function
            let poll_result = poll.poll_future_notify(&notify, 0);

            // Keep the polling function alive if it has not finished yet
            if poll_result != Ok(Async::Ready(())) {
                // The take() call means that the polling won't continue unless we pass it forward like this
                *this_poll = Some(poll);
            }
        }
    }

    ///
    /// Adds a polling function to the current thread. It will be called using the futures
    /// notification system (ie, can call things like the stream poll function)
    ///
    pub fn monitor<PollFn>(&self, poll_fn: PollFn)
    where PollFn: 'static+Send+FnMut() -> Poll<(), ()> {
        // Turn the polling function into a future (it will complete when monitoring is complete)
        let poll_fn     = future::poll_fn(poll_fn);

        // Spawn it with an executor
        let poll_fn     = executor::spawn(poll_fn);

        // Create a desync object for polling
        let poll_fn     = Arc::new(Desync::new(Some(poll_fn)));
        let next_poll   = Arc::clone(&poll_fn);

        // Perform the initial polling
        poll_fn.sync(move |poll_fn| Self::poll(poll_fn, next_poll));
    }
}

impl<PollFn> executor::Notify for PipeNotify<PollFn>
where PollFn: 'static+Send+Future<Item=(), Error=()> {
    fn notify(&self, _id: usize) {
        // Poll the future whenever we're notified
        let next_poll = Arc::clone(&self.next_poll);
        self.next_poll.sync(move |poll_fn| PipeMonitor::poll(poll_fn, next_poll));
    }
}
<commit_msg>Only call notify() when we don't have the lock to avoid the chance of deadlocks<commit_after>//!
//! Desync pipes provide a way to generate and process streams via a `Desync` object
//!
//! Pipes are an excellent way to interface `Desync` objects and the futures library. Piping
//! a stream into a `Desync` object is equivalent to spawning it with an executor, except
//! without the need to dedicate a thread to running it.
//!
//! There are two kinds of pipe. The `pipe_in` function creates a pipe that processes each
//! value made available from a stream on a desync object as they arrive, producing no
//! results. This is useful for cases where a `Desync` object is being used as the endpoint
//! for some data processing (for example, to insert the results of an operation into an
//! asynchronous database object).
//!
//! The `pipe` function pipes data through an object. For every input value, it produces
//! an output value. This is good for creating streams that perform some kind of asynchronous
//! processing operation or that need to access data from inside a `Desync` object.
//!
//! Here's an example of using `pipe_in` to store data in a `HashSet`:
//!
//! ```
//! # extern crate futures;
//! # extern crate desync;
//! # use std::collections::HashSet;
//! # use std::sync::*;
//! #
//! use futures::sync::mpsc;
//! use futures::executor;
//! use desync::*;
//!
//! let desync_hashset      = Arc::new(Desync::new(HashSet::new()));
//! let (sender, receiver)  = mpsc::channel(5);
//!
//! pipe_in(Arc::clone(&desync_hashset), receiver, |hashset, value| { value.map(|value| hashset.insert(value)); });
//!
//! let mut sender = executor::spawn(sender);
//! sender.wait_send("Test".to_string());
//! sender.wait_send("Another value".to_string());
//! #
//! # assert!(desync_hashset.sync(|hashset| hashset.contains(&("Test".to_string()))))
//! ```
//!

use super::desync::*;

use futures::*;
use futures::executor;
use futures::executor::Spawn;

use std::sync::*;
use std::result::Result;
use std::collections::VecDeque;

lazy_static! {
    /// The shared queue where we monitor for updates to the active pipe streams
    static ref PIPE_MONITOR: PipeMonitor = PipeMonitor::new();
}

/// The maximum number of items to queue on a pipe stream before we stop accepting new input
const PIPE_BACKPRESSURE_COUNT: usize = 5;

///
/// Pipes a stream into a desync object. Whenever an item becomes available on the stream, the
/// processing function is called asynchronously with the item that was received.
///
/// This takes a weak reference to the passed in `Desync` object, so the pipe will stop if it's
/// the only thing referencing this object.
///
/// Piping a stream to a `Desync` like this will cause it to start executing: ie, this is
/// similar to calling `executor::spawn(stream)`, except that the stream will immediately
/// start draining into the `Desync` object.
///
pub fn pipe_in<Core, S, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn)
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> () {

    // Need a mutable version of the stream
    let mut stream = stream;

    // We stop processing once the desync object is no longer used anywhere else
    let desync = Arc::downgrade(&desync);

    // Wrap the process fn up so we can call it asynchronously
    // (it doesn't really need to be in a mutex as it's only called by our object but we need to make it pass Rust's checks and we don't have a way to specify this at the moment)
    let process = Arc::new(Mutex::new(process));

    // Monitor the stream
    PIPE_MONITOR.monitor(move || {
        loop {
            let desync      = desync.upgrade();

            if let Some(desync) = desync {
                // Read the current status of the stream
                let process     = Arc::clone(&process);
                let next        = stream.poll();

                match next {
                    // Just wait if the stream is not ready
                    Ok(Async::NotReady) => { return Ok(Async::NotReady); },

                    // Stop processing when the stream is finished
                    Ok(Async::Ready(None)) => { return Ok(Async::Ready(())); }

                    // Stream returned a value
                    Ok(Async::Ready(Some(next))) => {
                        // Process the value on the stream
                        desync.async(move |core| {
                            let mut process = process.lock().unwrap();
                            let process     = &mut *process;
                            process(core, Ok(next));
                        });
                    },

                    // Stream returned an error
                    Err(e) => {
                        // Process the error on the stream
                        desync.async(move |core| {
                            let mut process = process.lock().unwrap();
                            let process     = &mut *process;
                            process(core, Err(e));
                        });
                    },
                }
            } else {
                // The desync target is no longer available - indicate that we've completed monitoring
                return Ok(Async::Ready(()));
            }
        }
    });
}

///
/// Pipes a stream into this object. Whenever an item becomes available on the stream, the
/// processing function is called asynchronously with the item that was received. The
/// return value is placed onto the output stream.
///
/// Unlike `pipe_in`, this keeps a strong reference to the `Desync` object so the processing
/// will continue so long as the input stream has data and the output stream is not dropped.
///
/// The input stream will start executing and reading values immediately when this is called.
/// Dropping the output stream will cause the pipe to be closed (the input stream will be
/// dropped and no further processing will occur).
///
/// This example demonstrates how to create a simple demonstration pipe that takes hashset values
/// and returns a stream indicating whether or not they were already included:
///
/// ```
/// # extern crate futures;
/// # extern crate desync;
/// # use std::collections::HashSet;
/// # use std::sync::*;
/// #
/// use futures::sync::mpsc;
/// use futures::executor;
/// use desync::*;
///
/// let desync_hashset      = Arc::new(Desync::new(HashSet::new()));
/// let (sender, receiver)  = mpsc::channel::<String>(5);
///
/// let value_inserted = pipe(Arc::clone(&desync_hashset), receiver,
///     |hashset, value| { value.map(|value| (value.clone(), hashset.insert(value))) });
///
/// let mut sender = executor::spawn(sender);
/// sender.wait_send("Test".to_string());
/// sender.wait_send("Another value".to_string());
/// sender.wait_send("Test".to_string());
///
/// let mut value_inserted = executor::spawn(value_inserted);
/// assert!(value_inserted.wait_stream() == Some(Ok(("Test".to_string(), true))));
/// assert!(value_inserted.wait_stream() == Some(Ok(("Another value".to_string(), true))));
/// assert!(value_inserted.wait_stream() == Some(Ok(("Test".to_string(), false))));
/// ```
///
pub fn pipe<Core, S, Output, OutputErr, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn) -> PipeStream<Output, OutputErr>
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        Output:     'static+Send,
        OutputErr:  'static+Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> Result<Output, OutputErr> {

    // Fetch the input stream and prepare the process function for async calling
    let mut input_stream    = stream;
    let process             = Arc::new(Mutex::new(process));

    // Create the output stream
    let output_stream   = PipeStream::new();
    let stream_core     = Arc::clone(&output_stream.core);
    let stream_core     = Arc::downgrade(&stream_core);

    // Monitor the input stream and pass data to the output stream
    PIPE_MONITOR.monitor(move || {
        loop {
            let stream_core = stream_core.upgrade();

            if let Some(stream_core) = stream_core {
                // Defer processing if the stream core is full
                {
                    // Fetch the core
                    let mut stream_core = stream_core.lock().unwrap();

                    // If the pending queue is full, then stop processing events
                    if stream_core.pending.len() >= stream_core.max_pipe_depth {
                        // Wake when the stream accepts some input
                        stream_core.backpressure_release_notify = Some(task::current());

                        // Go back to sleep without reading from the stream
                        return Ok(Async::NotReady);
                    }
                }

                // Read the current status of the stream
                let process         = Arc::clone(&process);
                let next            = input_stream.poll();
                let mut next_item;

                // Work out what the next item to pass to the process function should be
                match next {
                    // Just wait if the stream is not ready
                    Ok(Async::NotReady) => { return Ok(Async::NotReady); },

                    // Stop processing when the input stream is finished
                    Ok(Async::Ready(None)) => {
                        // Mark the target stream as closed
                        let notify = {
                            let mut stream_core = stream_core.lock().unwrap();
                            stream_core.closed = true;
                            stream_core.notify.take()
                        };
                        notify.map(|notify| notify.notify());

                        // Pipe has finished
                        return Ok(Async::Ready(()));
                    }

                    // Stream returned a value
                    Ok(Async::Ready(Some(next))) => next_item = Ok(next),

                    // Stream returned an error
                    Err(e) => next_item = Err(e),
                }

                // Send the next item to be processed
                desync.async(move |core| {
                    // Process the next item
                    let mut process     = process.lock().unwrap();
                    let process         = &mut *process;
                    let next_item       = process(core, next_item);

                    // Send to the pipe stream
                    let notify = {
                        let mut stream_core = stream_core.lock().unwrap();

                        stream_core.pending.push_back(next_item);
                        stream_core.notify.take()
                    };
                    notify.map(|notify| notify.notify());
                });

            } else {
                // We stop processing once nothing is reading from the target stream
                return Ok(Async::Ready(()));
            }
        }
    });

    // The pipe stream is the result
    output_stream
}

///
/// The shared data for a pipe stream
///
struct PipeStreamCore<Item, Error>  {
    /// The maximum number of items we allow to be queued in this stream before producing backpressure
    max_pipe_depth: usize,

    /// The pending data for this stream
    pending: VecDeque<Result<Item, Error>>,

    /// True if the input stream has closed (the stream is closed once this is true and there are no more pending items)
    closed: bool,

    /// The task to notify when the stream changes
    notify: Option<task::Task>,

    /// The task to notify when we reduce the amount of pending data
    backpressure_release_notify: Option<task::Task>
}

///
/// A stream generated by a pipe
///
pub struct PipeStream<Item, Error> {
    core: Arc<Mutex<PipeStreamCore<Item, Error>>>
}

impl<Item, Error> PipeStream<Item, Error> {
    ///
    /// Creates a new, empty, pipestream
    ///
    fn new() -> PipeStream<Item, Error> {
        PipeStream {
            core: Arc::new(Mutex::new(PipeStreamCore {
                max_pipe_depth:                 PIPE_BACKPRESSURE_COUNT,
                pending:                        VecDeque::new(),
                closed:                         false,
                notify:                         None,
                backpressure_release_notify:    None
            }))
        }
    }

    ///
    /// Sets the number of items that this pipe stream will buffer before producing backpressure
    ///
    /// If this call is not made, this will be set to 5.
    ///
    pub fn set_backpressure_depth(&mut self, max_depth: usize) {
        self.core.lock().unwrap().max_pipe_depth = max_depth;
    }
}

impl<Item, Error> Drop for PipeStream<Item, Error> {
    fn drop(&mut self) {
        let mut core = self.core.lock().unwrap();

        // Flush the pending queue
        core.pending = VecDeque::new();

        // TODO: wake the monitor and stop listening to the source stream
        // (Right now this will happen next time the source stream produces data)
    }
}

impl<Item, Error> Stream for PipeStream<Item, Error> {
    type Item   = Item;
    type Error  = Error;

    fn poll(&mut self) -> Poll<Option<Item>, Error> {
        // Fetch the core
        let mut core = self.core.lock().unwrap();

        if let Some(item) = core.pending.pop_front() {
            // Value waiting at the start of the stream
            core.backpressure_release_notify.take().map(|notify| notify.notify());

            match item {
                Ok(item)    => Ok(Async::Ready(Some(item))),
                Err(erm)    => Err(erm)
            }
        } else if core.closed {
            // No more data will be returned from this stream
            Ok(Async::Ready(None))
        } else {
            // Stream not ready
            core.notify = Some(task::current());

            Ok(Async::NotReady)
        }
    }
}

///
/// The main polling component for that implements the stream pipes
///
struct PipeMonitor {
}

///
/// Provides the 'Notify' interface for a polling function with a particular ID
///
struct PipeNotify<PollFn: Send> {
    next_poll: Arc<Desync<Option<Spawn<PollFn>>>>
}

impl PipeMonitor {
    ///
    /// Creates a new poll thread
    ///
    pub fn new() -> PipeMonitor {
        PipeMonitor {
        }
    }

    ///
    /// Performs a polling operation on a poll
    ///
    fn poll<PollFn>(this_poll: &mut Option<Spawn<PollFn>>, next_poll: Arc<Desync<Option<Spawn<PollFn>>>>)
    where PollFn: 'static+Send+Future<Item=(), Error=()> {
        // If the polling function exists...
        if let Some(mut poll) = this_poll.take() {
            // Create a notification
            let notify = PipeNotify {
                next_poll: next_poll
            };
            let notify = Arc::new(notify);

            // Poll the function
            let poll_result = poll.poll_future_notify(&notify, 0);

            // Keep the polling function alive if it has not finished yet
            if poll_result != Ok(Async::Ready(())) {
                // The take() call means that the polling won't continue unless we pass it forward like this
                *this_poll = Some(poll);
            }
        }
    }

    ///
    /// Adds a polling function to the current thread. It will be called using the futures
    /// notification system (ie, can call things like the stream poll function)
    ///
    pub fn monitor<PollFn>(&self, poll_fn: PollFn)
    where PollFn: 'static+Send+FnMut() -> Poll<(), ()> {
        // Turn the polling function into a future (it will complete when monitoring is complete)
        let poll_fn     = future::poll_fn(poll_fn);

        // Spawn it with an executor
        let poll_fn     = executor::spawn(poll_fn);

        // Create a desync object for polling
        let poll_fn     = Arc::new(Desync::new(Some(poll_fn)));
        let next_poll   = Arc::clone(&poll_fn);

        // Perform the initial polling
        poll_fn.sync(move |poll_fn| Self::poll(poll_fn, next_poll));
    }
}

impl<PollFn> executor::Notify for PipeNotify<PollFn>
where PollFn: 'static+Send+Future<Item=(), Error=()> {
    fn notify(&self, _id: usize) {
        // Poll the future whenever we're notified
        let next_poll = Arc::clone(&self.next_poll);
        self.next_poll.sync(move |poll_fn| PipeMonitor::poll(poll_fn, next_poll));
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Alexander Reece
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::io;

use inflections::Inflect;
use specs::amqp0::Spec;

mod method;

pub use amqp0::DomainMapper;
use self::method::ModuleWriter;

pub struct SpecWriter<'a> {
    struct_name: String,
    mod_name: String,
    domain_mapper: DomainMapper<'a>,
    spec: &'a Spec,
}

impl<'a> SpecWriter<'a> {
    pub fn new(spec: &'a Spec) -> Self {
        let (minor, revision) = {
            let version = spec.version();
            (version.minor(), version.revision())
        };
        let struct_name = format!("{}{}_{}", spec.name().to_pascal_case(), minor, revision);
        let mod_name = format!("{}{}_{}", spec.name().to_snake_case(), minor, revision);

        SpecWriter {
            struct_name: struct_name,
            mod_name: mod_name,
            domain_mapper: DomainMapper::new(spec.domains()),
            spec: spec,
        }
    }

    pub fn mod_name(&self) -> &str {
        &self.mod_name
    }

    pub fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
        if self.spec.classes().len() == 0 {
            return Ok(());
        }
        //try!(writeln!(writer, "pub mod {} {{", self.mod_name));
        try!(self.write_class_constants(writer));
        try!(self.write_method_constants(writer));

        try!(writeln!(writer, "\n// Class Modules"));
        for class in self.spec.classes().values() {
            try!(writeln!(writer, "pub mod {} {{", class.name().to_camel_case()));
            for method in class.methods() {
                let method_writer = ModuleWriter::new(&class, &method, &self.domain_mapper);
                try!(method_writer.write_to(writer));
            }
            try!(writeln!(writer, "}}"));
        }

        /*
        try!(writeln!(writer, "fn parse(class: u8, method: u8, bytes: &[u8]) -> u8 {{"));
        try!(writeln!(writer, "match (class, method) {{"));
        for class in self.spec.classes().values() {
            for method in class.methods() {
                try!(writeln!(writer, "({}, {}) => {}::{}", class.index(), method.index()));
            }
        }
        try!(writeln!(writer, "}}"));
        try!(writeln!(writer, "}}"));
        */

        //try!(writeln!(writer, "}}")); // spec mod

        try!(writeln!(writer, "\n#[allow(non_camel_case_types)]"));
        try!(writeln!(writer, "pub struct {};", self.struct_name));
        try!(writeln!(writer, "impl Spec for {} {{}}\n", self.struct_name));

        Ok(())
    }

    pub fn write_class_constants<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
        try!(writeln!(writer, "// Class Constants"));
        for class in self.spec.classes().values() {
            let constant_class = class.name().to_constant_case();
            try!(writeln!(writer, "pub const CLASS_{}: u16 = {};", constant_class, class.index()));
        }

        Ok(())
    }

    pub fn write_method_constants<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
        try!(write!(writer, "\n// Class Methods"));
        for class in self.spec.classes().values() {
            try!(writeln!(writer, ""));
            let constant_class = class.name().to_constant_case();
            for method in class.methods() {
                let constant_method = method.name().to_constant_case();
                try!(writeln!(writer, "pub const METHOD_{}_{}: u16 = {};", constant_class, constant_method, method.index()));
            }
        }

        Ok(())
    }
}<commit_msg>[specs] Update definitions of write methods to use where clause.<commit_after>// Copyright 2016 Alexander Reece
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::io;

use inflections::Inflect;
use specs::amqp0::Spec;

mod method;

pub use amqp0::DomainMapper;
use self::method::ModuleWriter;

pub struct SpecWriter<'a> {
    struct_name: String,
    mod_name: String,
    domain_mapper: DomainMapper<'a>,
    spec: &'a Spec,
}

impl<'a> SpecWriter<'a> {
    pub fn new(spec: &'a Spec) -> Self {
        let (minor, revision) = {
            let version = spec.version();
            (version.minor(), version.revision())
        };
        let struct_name = format!("{}{}_{}", spec.name().to_pascal_case(), minor, revision);
        let mod_name = format!("{}{}_{}", spec.name().to_snake_case(), minor, revision);

        SpecWriter {
            struct_name: struct_name,
            mod_name: mod_name,
            domain_mapper: DomainMapper::new(spec.domains()),
            spec: spec,
        }
    }

    pub fn mod_name(&self) -> &str {
        &self.mod_name
    }

    pub fn write<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        if self.spec.classes().len() == 0 {
            return Ok(());
        }
        //try!(writeln!(writer, "pub mod {} {{", self.mod_name));
        try!(self.write_class_constants(writer));
        try!(self.write_method_constants(writer));

        try!(writeln!(writer, "\n// Class Modules"));
        for class in self.spec.classes().values() {
            try!(writeln!(writer, "pub mod {} {{", class.name().to_camel_case()));
            for method in class.methods() {
                let method_writer = ModuleWriter::new(&class, &method, &self.domain_mapper);
                try!(method_writer.write_to(writer));
            }
            try!(writeln!(writer, "}}"));
        }

        /*
        try!(writeln!(writer, "fn parse(class: u8, method: u8, bytes: &[u8]) -> u8 {{"));
        try!(writeln!(writer, "match (class, method) {{"));
        for class in self.spec.classes().values() {
            for method in class.methods() {
                try!(writeln!(writer, "({}, {}) => {}::{}", class.index(), method.index()));
            }
        }
        try!(writeln!(writer, "}}"));
        try!(writeln!(writer, "}}"));
        */

        //try!(writeln!(writer, "}}")); // spec mod

        try!(writeln!(writer, "\n#[allow(non_camel_case_types)]"));
        try!(writeln!(writer, "pub struct {};", self.struct_name));
        try!(writeln!(writer, "impl Spec for {} {{}}\n", self.struct_name));

        Ok(())
    }

    pub fn write_class_constants<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        try!(writeln!(writer, "// Class Constants"));
        for class in self.spec.classes().values() {
            let constant_class = class.name().to_constant_case();
            try!(writeln!(writer, "pub const CLASS_{}: u16 = {};", constant_class, class.index()));
        }

        Ok(())
    }

    pub fn write_method_constants<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        try!(write!(writer, "\n// Class Methods"));
        for class in self.spec.classes().values() {
            try!(writeln!(writer, ""));
            let constant_class = class.name().to_constant_case();
            for method in class.methods() {
                let constant_method = method.name().to_constant_case();
                try!(writeln!(writer, "pub const METHOD_{}_{}: u16 = {};", constant_class, constant_method, method.index()));
            }
        }

        Ok(())
    }
}<|endoftext|>