<commit_before>//! This module implements encoding and decoding of the (63, 16, 23) BCH code used to
//! protect P25's NID field.
//!
//! It uses an optimized "matrix multiplication" for encoding and
//! the Berlekamp-Massey algorithm followed by Chien search for decoding, and both use
//! only stack memory.
//!
//! Most Galois field information as well as the Berlekamp-Massey implementation are
//! derived from \[1] and the Chien search was derived from \[2].
//!
//! \[1]: "Coding Theory and Cryptography: The Essentials", 2nd ed, Hankerson, Hoffman, et
//! al, 2000
//!
//! \[2]: https://en.wikipedia.org/wiki/Chien_search

use std;

use galois::{GaloisField, P25Field, P25Codeword, Polynomial, PolynomialCoefs};
use bmcf;

/// Encode the given word into a P25 BCH codeword.
pub fn encode(word: u16) -> u64 {
    matrix_mul_systematic!(word, GEN, u64)
}

/// Decode the given codeword into data bits, correcting up to 11 errors. Return
/// `Some((data, err))`, where `data` is the data bits and `err` is the number of errors,
/// if the codeword could be corrected and `None` if it couldn't.
pub fn decode(word: u64) -> Option<(u16, usize)> {
    // The BCH code is only over the first 63 bits, so strip off the P25 parity bit.
    let word = word >> 1;

    let syn = syndromes(word);
    // Get the error location polynomial.
    let poly = BCHDecoder::new(syn).decode();

    // The degree indicates the number of errors that need to be corrected.
    let errors = match poly.degree() {
        Some(deg) => deg,
        None => panic!("invalid polynomial"),
    };

    // Even if there are more errors, the BM algorithm produces a polynomial with degree
    // no greater than ERRORS.
    assert!(errors <= BCHCoefs::errors());

    // Get the bit locations from the polynomial.
    let locs = bmcf::Errors::new(poly, syn);

    // Correct the codeword and count the number of corrected errors. Stop the
    // `Errors` iteration after `errors` iterations since it won't yield any more
    // locations after that anyway.
    let (word, count) = locs.take(errors).fold((word, 0), |(w, s), (loc, val)| {
        assert!(val.power().unwrap() == 0);
        (w ^ 1 << loc, s + 1)
    });

    if count == errors {
        // Strip off the (corrected) parity-check bits.
        Some(((word >> 47) as u16, errors))
    } else {
        None
    }
}

/// Generator matrix from P25, transformed for more efficient codeword generation.
const GEN: &'static [u16] = &[
    0b1110110001000111,
    0b1001101001100100,
    0b0100110100110010,
    0b0010011010011001,
    0b1111111100001011,
    0b1001001111000010,
    0b0100100111100001,
    0b1100100010110111,
    0b1000100000011100,
    0b0100010000001110,
    0b0010001000000111,
    0b1111110101000100,
    0b0111111010100010,
    0b0011111101010001,
    0b1111001111101111,
    0b1001010110110000,
    0b0100101011011000,
    0b0010010101101100,
    0b0001001010110110,
    0b0000100101011011,
    0b1110100011101010,
    0b0111010001110101,
    0b1101011001111101,
    0b1000011101111001,
    0b1010111111111011,
    0b1011101110111010,
    0b0101110111011101,
    0b1100001010101001,
    0b1000110100010011,
    0b1010101011001110,
    0b0101010101100111,
    0b1100011011110100,
    0b0110001101111010,
    0b0011000110111101,
    0b1111010010011001,
    0b1001011000001011,
    0b1010011101000010,
    0b0101001110100001,
    0b1100010110010111,
    0b1000111010001100,
    0b0100011101000110,
    0b0010001110100011,
    0b1111110110010110,
    0b0111111011001011,
    0b1101001100100010,
    0b0110100110010001,
    0b1101100010001111,
    0b0000000000000011,
];

#[derive(Copy, Clone, Default)]
struct BCHCoefs([P25Codeword; 22 + 2]);

impl std::ops::Deref for BCHCoefs {
    type Target = [P25Codeword];
    fn deref(&self) -> &Self::Target { &self.0[..] }
}

impl std::ops::DerefMut for BCHCoefs {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0[..] }
}

impl PolynomialCoefs for BCHCoefs {
    fn distance() -> usize { 23 }
}

type BCHPolynomial = Polynomial<BCHCoefs>;
type BCHDecoder = bmcf::BerlMasseyDecoder<BCHCoefs>;

/// Generate the syndrome polynomial for the given received word.
fn syndromes(word: u64) -> BCHPolynomial {
    BCHPolynomial::new(std::iter::once(P25Codeword::for_power(0))
        .chain((1..BCHCoefs::distance()).map(|pow| {
            (0..P25Field::size()).fold(P25Codeword::default(), |s, b| {
                if word >> b & 1 == 0 {
                    s
                } else {
                    s + P25Codeword::for_power(b * pow)
                }
            })
        }))
    )
}

#[cfg(test)]
mod test {
    use super::*;
    use super::{syndromes, BCHDecoder, BCHCoefs, BCHPolynomial};
    use galois::{P25Codeword, PolynomialCoefs};
    use bmcf::Errors;

    #[test]
    fn validate_coefs() {
        BCHCoefs::default().validate();
    }

    #[test]
    fn test_encode() {
        assert_eq!(encode(0b1111111100000000), 0b1111111100000000100100110001000011000010001100000110100001101000);
        assert_eq!(encode(0b0011)&1, 0);
        assert_eq!(encode(0b0101)&1, 1);
        assert_eq!(encode(0b1010)&1, 1);
        assert_eq!(encode(0b1100)&1, 0);
        assert_eq!(encode(0b1111)&1, 0);
    }

    #[test]
    fn test_syndromes() {
        let w = encode(0b1111111100000000)>>1;
        let p = syndromes(w);

        assert_eq!(p.len(), 24);
        assert_eq!(p.degree().unwrap(), 0);
        assert_eq!(syndromes(w ^ 1<<60).degree().unwrap(), 22);
        assert_eq!(p[0], P25Codeword::for_power(0));
    }

    #[test]
    fn test_decoder() {
        let w = encode(0b1111111100000000)^0b11<<61;
        let poly = BCHDecoder::new(syndromes(w >> 1)).decode();

        assert!(poly.coef(0).power().unwrap() == 0);
        assert!(poly.coef(1).power().unwrap() == 3);
        assert!(poly.coef(2).power().unwrap() == 58);
    }

    #[test]
    fn test_locs() {
        let w = encode(0b0000111100001111)^0b11<<61;
        let p = syndromes(w >> 1);

        let coefs = BCHPolynomial::new([
            P25Codeword::for_power(0),
            P25Codeword::for_power(3),
            P25Codeword::for_power(58),
        ].into_iter().cloned());

        let mut locs = Errors::new(coefs, p);

        assert_eq!(locs.next().unwrap(), (61, P25Codeword::for_power(0)));
        assert_eq!(locs.next().unwrap(), (60, P25Codeword::for_power(0)));
        assert!(locs.next().is_none());
    }

    #[test]
    fn test_decode() {
        assert!(decode(encode(0b0000111100001111) ^ 1<<63).unwrap() ==
                (0b0000111100001111, 1));

        assert!(decode(encode(0b1100011111111111) ^ 1).unwrap() ==
                (0b1100011111111111, 0));

        assert!(decode(encode(0b1111111100000000) ^ 0b11010011<<30).unwrap() ==
                (0b1111111100000000, 5));

        assert!(decode(encode(0b1101101101010001) ^ (1<<63 | 1)).unwrap() ==
                (0b1101101101010001, 1));

        assert!(decode(encode(0b1111111111111111) ^ 0b11111111111).unwrap() ==
                (0b1111111111111111, 10));

        assert!(decode(encode(0b0000000000000000) ^ 0b11111111111).unwrap() ==
                (0b0000000000000000, 10));

        assert!(decode(encode(0b0000111110000000) ^ 0b111111111110).unwrap() ==
                (0b0000111110000000, 11));

        assert!(decode(encode(0b0000111110000000) ^ 0b111111111110).unwrap() ==
                (0b0000111110000000, 11));

        assert!(decode(encode(0b0000111110001010) ^ 0b1111111111110).is_none());
        assert!(decode(encode(0b0000001111111111) ^ 0b11111111111111111111110).is_none());
        assert!(decode(encode(0b0000001111111111) ^
                       0b00100101010101000010001100100010011111111110).is_none());
    }
}
<commit_msg>Use expect in bch<commit_after>//! This module implements encoding and decoding of the (63, 16, 23) BCH code used to
//! protect P25's NID field.
//!
//! It uses an optimized "matrix multiplication" for encoding and
//! the Berlekamp-Massey algorithm followed by Chien search for decoding, and both use
//! only stack memory.
//!
//! Most Galois field information as well as the Berlekamp-Massey implementation are
//! derived from \[1] and the Chien search was derived from \[2].
//!
//! \[1]: "Coding Theory and Cryptography: The Essentials", 2nd ed, Hankerson, Hoffman, et
//! al, 2000
//!
//! \[2]: https://en.wikipedia.org/wiki/Chien_search

use std;

use galois::{GaloisField, P25Field, P25Codeword, Polynomial, PolynomialCoefs};
use bmcf;

/// Encode the given word into a P25 BCH codeword.
pub fn encode(word: u16) -> u64 {
    matrix_mul_systematic!(word, GEN, u64)
}

/// Decode the given codeword into data bits, correcting up to 11 errors. Return
/// `Some((data, err))`, where `data` is the data bits and `err` is the number of errors,
/// if the codeword could be corrected and `None` if it couldn't.
pub fn decode(word: u64) -> Option<(u16, usize)> {
    // The BCH code is only over the first 63 bits, so strip off the P25 parity bit.
    let word = word >> 1;

    let syn = syndromes(word);
    // Get the error location polynomial.
    let poly = BCHDecoder::new(syn).decode();

    // The degree indicates the number of errors that need to be corrected.
    let errors = poly.degree().expect("invalid error polynomial");

    // Even if there are more errors, the BM algorithm produces a polynomial with degree
    // no greater than ERRORS.
    assert!(errors <= BCHCoefs::errors());

    // Get the bit locations from the polynomial.
    let locs = bmcf::Errors::new(poly, syn);

    // Correct the codeword and count the number of corrected errors. Stop the
    // `Errors` iteration after `errors` iterations since it won't yield any more
    // locations after that anyway.
    let (word, count) = locs.take(errors).fold((word, 0), |(w, s), (loc, val)| {
        assert!(val.power().unwrap() == 0);
        (w ^ 1 << loc, s + 1)
    });

    if count == errors {
        // Strip off the (corrected) parity-check bits.
        Some(((word >> 47) as u16, errors))
    } else {
        None
    }
}

/// Generator matrix from P25, transformed for more efficient codeword generation.
const GEN: &'static [u16] = &[
    0b1110110001000111,
    0b1001101001100100,
    0b0100110100110010,
    0b0010011010011001,
    0b1111111100001011,
    0b1001001111000010,
    0b0100100111100001,
    0b1100100010110111,
    0b1000100000011100,
    0b0100010000001110,
    0b0010001000000111,
    0b1111110101000100,
    0b0111111010100010,
    0b0011111101010001,
    0b1111001111101111,
    0b1001010110110000,
    0b0100101011011000,
    0b0010010101101100,
    0b0001001010110110,
    0b0000100101011011,
    0b1110100011101010,
    0b0111010001110101,
    0b1101011001111101,
    0b1000011101111001,
    0b1010111111111011,
    0b1011101110111010,
    0b0101110111011101,
    0b1100001010101001,
    0b1000110100010011,
    0b1010101011001110,
    0b0101010101100111,
    0b1100011011110100,
    0b0110001101111010,
    0b0011000110111101,
    0b1111010010011001,
    0b1001011000001011,
    0b1010011101000010,
    0b0101001110100001,
    0b1100010110010111,
    0b1000111010001100,
    0b0100011101000110,
    0b0010001110100011,
    0b1111110110010110,
    0b0111111011001011,
    0b1101001100100010,
    0b0110100110010001,
    0b1101100010001111,
    0b0000000000000011,
];

#[derive(Copy, Clone, Default)]
struct BCHCoefs([P25Codeword; 22 + 2]);

impl std::ops::Deref for BCHCoefs {
    type Target = [P25Codeword];
    fn deref(&self) -> &Self::Target { &self.0[..] }
}

impl std::ops::DerefMut for BCHCoefs {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0[..] }
}

impl PolynomialCoefs for BCHCoefs {
    fn distance() -> usize { 23 }
}

type BCHPolynomial = Polynomial<BCHCoefs>;
type BCHDecoder = bmcf::BerlMasseyDecoder<BCHCoefs>;

/// Generate the syndrome polynomial for the given received word.
fn syndromes(word: u64) -> BCHPolynomial {
    BCHPolynomial::new(std::iter::once(P25Codeword::for_power(0))
        .chain((1..BCHCoefs::distance()).map(|pow| {
            (0..P25Field::size()).fold(P25Codeword::default(), |s, b| {
                if word >> b & 1 == 0 {
                    s
                } else {
                    s + P25Codeword::for_power(b * pow)
                }
            })
        }))
    )
}

#[cfg(test)]
mod test {
    use super::*;
    use super::{syndromes, BCHDecoder, BCHCoefs, BCHPolynomial};
    use galois::{P25Codeword, PolynomialCoefs};
    use bmcf::Errors;

    #[test]
    fn validate_coefs() {
        BCHCoefs::default().validate();
    }

    #[test]
    fn test_encode() {
        assert_eq!(encode(0b1111111100000000), 0b1111111100000000100100110001000011000010001100000110100001101000);
        assert_eq!(encode(0b0011)&1, 0);
        assert_eq!(encode(0b0101)&1, 1);
        assert_eq!(encode(0b1010)&1, 1);
        assert_eq!(encode(0b1100)&1, 0);
        assert_eq!(encode(0b1111)&1, 0);
    }

    #[test]
    fn test_syndromes() {
        let w = encode(0b1111111100000000)>>1;
        let p = syndromes(w);

        assert_eq!(p.len(), 24);
        assert_eq!(p.degree().unwrap(), 0);
        assert_eq!(syndromes(w ^ 1<<60).degree().unwrap(), 22);
        assert_eq!(p[0], P25Codeword::for_power(0));
    }

    #[test]
    fn test_decoder() {
        let w = encode(0b1111111100000000)^0b11<<61;
        let poly = BCHDecoder::new(syndromes(w >> 1)).decode();

        assert!(poly.coef(0).power().unwrap() == 0);
        assert!(poly.coef(1).power().unwrap() == 3);
        assert!(poly.coef(2).power().unwrap() == 58);
    }

    #[test]
    fn test_locs() {
        let w = encode(0b0000111100001111)^0b11<<61;
        let p = syndromes(w >> 1);

        let coefs = BCHPolynomial::new([
            P25Codeword::for_power(0),
            P25Codeword::for_power(3),
            P25Codeword::for_power(58),
        ].into_iter().cloned());

        let mut locs = Errors::new(coefs, p);

        assert_eq!(locs.next().unwrap(), (61, P25Codeword::for_power(0)));
        assert_eq!(locs.next().unwrap(), (60, P25Codeword::for_power(0)));
        assert!(locs.next().is_none());
    }

    #[test]
    fn test_decode() {
        assert!(decode(encode(0b0000111100001111) ^ 1<<63).unwrap() ==
                (0b0000111100001111, 1));

        assert!(decode(encode(0b1100011111111111) ^ 1).unwrap() ==
                (0b1100011111111111, 0));

        assert!(decode(encode(0b1111111100000000) ^ 0b11010011<<30).unwrap() ==
                (0b1111111100000000, 5));

        assert!(decode(encode(0b1101101101010001) ^ (1<<63 | 1)).unwrap() ==
                (0b1101101101010001, 1));

        assert!(decode(encode(0b1111111111111111) ^ 0b11111111111).unwrap() ==
                (0b1111111111111111, 10));

        assert!(decode(encode(0b0000000000000000) ^ 0b11111111111).unwrap() ==
                (0b0000000000000000, 10));

        assert!(decode(encode(0b0000111110000000) ^ 0b111111111110).unwrap() ==
                (0b0000111110000000, 11));

        assert!(decode(encode(0b0000111110000000) ^ 0b111111111110).unwrap() ==
                (0b0000111110000000, 11));

        assert!(decode(encode(0b0000111110001010) ^ 0b1111111111110).is_none());
        assert!(decode(encode(0b0000001111111111) ^ 0b11111111111111111111110).is_none());
        assert!(decode(encode(0b0000001111111111) ^
                       0b00100101010101000010001100100010011111111110).is_none());
    }
}
<|endoftext|>


<commit_before>use std::iter::FromIterator;

use hashbrown::HashMap;

use crate::context::{merge_json, Context};
use crate::error::RenderError;
use crate::output::Output;
use crate::registry::Registry;
use crate::render::{Directive, Evaluable, RenderContext, Renderable};
use crate::template::Template;
use crate::value::DEFAULT_VALUE;

fn render_partial<'reg: 'rc, 'rc>(
    t: &'reg Template,
    d: &Directive<'reg, 'rc>,
    r: &'reg Registry,
    ctx: &'rc Context,
    local_rc: &mut RenderContext<'reg>,
    out: &mut Output,
) -> Result<(), RenderError> {
    // partial context path
    if let Some(ref p) = d.param(0) {
        if let Some(ref param_path) = p.path() {
            let old_path = local_rc.get_path().clone();
            local_rc.promote_local_vars();
            let new_path = format!("{}/{}", old_path, param_path);
            local_rc.set_path(new_path);
        }
    };

    // @partial-block
    if let Some(t) = d.template() {
        local_rc.set_partial("@partial-block".to_owned(), t);
    }

    if d.hash().is_empty() {
        t.render(r, ctx, local_rc, out)
    } else {
        let hash_ctx =
            HashMap::from_iter(d.hash().iter().map(|(k, v)| (k.clone(), v.value().clone())));
        let partial_context = merge_json(
            local_rc
                .evaluate(ctx, ".")?
                .unwrap_or_else(|| &DEFAULT_VALUE),
            &hash_ctx,
        );
        let ctx = Context::wraps(&partial_context)?;
        let mut partial_rc = local_rc.new_for_block();
        t.render(r, &ctx, &mut partial_rc, out)
    }
}

pub fn expand_partial<'reg: 'rc, 'rc>(
    d: &Directive<'reg, 'rc>,
    r: &'reg Registry,
    ctx: &'rc Context,
    rc: &mut RenderContext<'reg>,
    out: &mut Output,
) -> Result<(), RenderError> {
    // try eval inline partials first
    if let Some(t) = d.template() {
        t.eval(r, ctx, rc)?;
    }

    let tname = d.name();
    if rc.is_current_template(tname) {
        return Err(RenderError::new("Cannot include self in >"));
    }

    let partial = rc.get_partial(tname);

    match partial {
        Some(t) => {
            let mut local_rc = rc.derive();
            render_partial(&t, d, r, ctx, &mut local_rc, out)?;
        }
        None => {
            if let Some(t) = r.get_template(tname).or_else(|| d.template()) {
                let mut local_rc = rc.derive();
                render_partial(t, d, r, ctx, &mut local_rc, out)?;
            }
        }
    }

    Ok(())
}

#[cfg(test)]
mod test {
    use crate::registry::Registry;

    #[test]
    fn test() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{> t1}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t1", "{{this}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t2", "{{#> t99}}not there{{/t99}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t3", "{{#*inline \"t31\"}}{{this}}{{/inline}}{{> t31}}")
            .is_ok());
        assert!(handlebars
            .register_template_string(
                "t4",
                "{{#> t5}}{{#*inline \"nav\"}}navbar{{/inline}}{{/t5}}"
            )
            .is_ok());
        assert!(handlebars
            .register_template_string("t5", "include {{> nav}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t6", "{{> t1 a}}")
            .is_ok());
        assert!(handlebars
            .register_template_string(
                "t7",
                "{{#*inline \"t71\"}}{{a}}{{/inline}}{{> t71 a=\"world\"}}"
            )
            .is_ok());
        assert!(handlebars.register_template_string("t8", "{{a}}").is_ok());
        assert!(handlebars
            .register_template_string("t9", "{{> t8 a=2}}")
            .is_ok());

        assert_eq!(handlebars.render("t0", &1).ok().unwrap(), "1".to_string());
        assert_eq!(
            handlebars.render("t2", &1).ok().unwrap(),
            "not there".to_string()
        );
        assert_eq!(handlebars.render("t3", &1).ok().unwrap(), "1".to_string());
        assert_eq!(
            handlebars.render("t4", &1).ok().unwrap(),
            "include navbar".to_string()
        );
        assert_eq!(
            handlebars
                .render("t6", &btreemap! {"a".to_string() => "2".to_string()})
                .ok()
                .unwrap(),
            "2".to_string()
        );
        assert_eq!(
            handlebars.render("t7", &1).ok().unwrap(),
            "world".to_string()
        );
        assert_eq!(handlebars.render("t9", &1).ok().unwrap(), "2".to_string());
    }

    #[test]
    fn test_include_partial_block() {
        let t0 = "hello {{> @partial-block}}";
        let t1 = "{{#> t0}}inner {{this}}{{/t0}}";

        let mut handlebars = Registry::new();
        assert!(handlebars.register_template_string("t0", t0).is_ok());
        assert!(handlebars.register_template_string("t1", t1).is_ok());

        let r0 = handlebars.render("t1", &true);
        assert_eq!(r0.ok().unwrap(), "hello inner true".to_string());
    }

    #[test]
    fn test_self_inclusion() {
        let t0 = "hello {{> t1}} {{> t0}}";
        let t1 = "some template";
        let mut handlebars = Registry::new();
        assert!(handlebars.register_template_string("t0", t0).is_ok());
        assert!(handlebars.register_template_string("t1", t1).is_ok());

        let r0 = handlebars.render("t0", &true);
        assert!(r0.is_err());
    }

    #[test]
    fn test_issue_143() {
        let main_template = "one{{> two }}three{{> two }}";
        let two_partial = "--- two ---";

        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("template", main_template)
            .is_ok());
        assert!(handlebars
            .register_template_string("two", two_partial)
            .is_ok());

        let r0 = handlebars.render("template", &true);
        assert_eq!(r0.ok().unwrap(), "one--- two ---three--- two ---");
    }

    #[test]
    fn test_hash_context_outscope() {
        let main_template = "In: {{> p a=2}} Out: {{a}}";
        let p_partial = "{{a}}";

        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("template", main_template)
            .is_ok());
        assert!(handlebars.register_template_string("p", p_partial).is_ok());

        let r0 = handlebars.render("template", &true);
        assert_eq!(r0.ok().unwrap(), "In: 2 Out: ");
    }

    #[test]
    fn test_nested_partial_scope() {
        let t = "{{#*inline \"pp\"}}{{a}} {{b}}{{/inline}}{{#each c}}{{> pp a=2}}{{/each}}";
        let data = json!({"c": [{"b": true}, {"b": false}]});

        let mut handlebars = Registry::new();
        assert!(handlebars.register_template_string("t", t).is_ok());
        let r0 = handlebars.render("t", &data);
        assert_eq!(r0.ok().unwrap(), "2 true2 false");
    }
}
<commit_msg>(fix) partial context resolution [#260]<commit_after>use hashbrown::HashMap;

use serde_json::value::Value as Json;

use crate::context::{merge_json, Context};
use crate::error::RenderError;
use crate::output::Output;
use crate::registry::Registry;
use crate::render::{Directive, Evaluable, RenderContext, Renderable};
use crate::template::Template;
use crate::value::DEFAULT_VALUE;

fn render_partial<'reg: 'rc, 'rc>(
    t: &'reg Template,
    d: &Directive<'reg, 'rc>,
    r: &'reg Registry,
    ctx: &'rc Context,
    local_rc: &mut RenderContext<'reg>,
    out: &mut Output,
) -> Result<(), RenderError> {
    let param_context = d.param(0).map(|v| v.value()).unwrap_or_else(|| {
        local_rc
            .evaluate(ctx, ".")
            .unwrap_or_else(|_| Some(&DEFAULT_VALUE))
            .unwrap()
    });

    // TODO: avoid clone
    let hash_context = d
        .hash()
        .iter()
        .map(|(k, v)| (k.to_owned(), v.value().clone()))
        .collect::<HashMap<String, Json>>();
    let ctx = if hash_context.is_empty() {
        Context::wraps(param_context)?
    } else {
        Context::wraps(&merge_json(&param_context, &hash_context))?
    };
    let mut partial_rc = local_rc.new_for_block();

    // @partial-block
    if let Some(t) = d.template() {
        partial_rc.set_partial("@partial-block".to_owned(), t);
    }

    t.render(r, &ctx, &mut partial_rc, out)
}

pub fn expand_partial<'reg: 'rc, 'rc>(
    d: &Directive<'reg, 'rc>,
    r: &'reg Registry,
    ctx: &'rc Context,
    rc: &mut RenderContext<'reg>,
    out: &mut Output,
) -> Result<(), RenderError> {
    // try eval inline partials first
    if let Some(t) = d.template() {
        t.eval(r, ctx, rc)?;
    }

    let tname = d.name();
    if rc.is_current_template(tname) {
        return Err(RenderError::new("Cannot include self in >"));
    }

    let partial = rc.get_partial(tname);

    match partial {
        Some(t) => {
            let mut local_rc = rc.derive();
            render_partial(&t, d, r, ctx, &mut local_rc, out)?;
        }
        None => {
            if let Some(t) = r.get_template(tname).or_else(|| d.template()) {
                let mut local_rc = rc.derive();
                render_partial(t, d, r, ctx, &mut local_rc, out)?;
            }
        }
    }

    Ok(())
}

#[cfg(test)]
mod test {
    use crate::registry::Registry;

    #[test]
    fn test() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{> t1}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t1", "{{this}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t2", "{{#> t99}}not there{{/t99}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t3", "{{#*inline \"t31\"}}{{this}}{{/inline}}{{> t31}}")
            .is_ok());
        assert!(handlebars
            .register_template_string(
                "t4",
                "{{#> t5}}{{#*inline \"nav\"}}navbar{{/inline}}{{/t5}}"
            )
            .is_ok());
        assert!(handlebars
            .register_template_string("t5", "include {{> nav}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t6", "{{> t1 a}}")
            .is_ok());
        assert!(handlebars
            .register_template_string(
                "t7",
                "{{#*inline \"t71\"}}{{a}}{{/inline}}{{> t71 a=\"world\"}}"
            )
            .is_ok());
        assert!(handlebars.register_template_string("t8", "{{a}}").is_ok());
        assert!(handlebars
            .register_template_string("t9", "{{> t8 a=2}}")
            .is_ok());

        assert_eq!(handlebars.render("t0", &1).ok().unwrap(), "1".to_string());
        assert_eq!(
            handlebars.render("t2", &1).ok().unwrap(),
            "not there".to_string()
        );
        assert_eq!(handlebars.render("t3", &1).ok().unwrap(), "1".to_string());
        assert_eq!(
            handlebars.render("t4", &1).ok().unwrap(),
            "include navbar".to_string()
        );
        assert_eq!(
            handlebars
                .render("t6", &btreemap! {"a".to_string() => "2".to_string()})
                .ok()
                .unwrap(),
            "2".to_string()
        );
        assert_eq!(
            handlebars.render("t7", &1).ok().unwrap(),
            "world".to_string()
        );
        assert_eq!(handlebars.render("t9", &1).ok().unwrap(), "2".to_string());
    }

    #[test]
    fn test_include_partial_block() {
        let t0 = "hello {{> @partial-block}}";
        let t1 = "{{#> t0}}inner {{this}}{{/t0}}";

        let mut handlebars = Registry::new();
        assert!(handlebars.register_template_string("t0", t0).is_ok());
        assert!(handlebars.register_template_string("t1", t1).is_ok());

        let r0 = handlebars.render("t1", &true);
        assert_eq!(r0.ok().unwrap(), "hello inner true".to_string());
    }

    #[test]
    fn test_self_inclusion() {
        let t0 = "hello {{> t1}} {{> t0}}";
        let t1 = "some template";
        let mut handlebars = Registry::new();
        assert!(handlebars.register_template_string("t0", t0).is_ok());
        assert!(handlebars.register_template_string("t1", t1).is_ok());

        let r0 = handlebars.render("t0", &true);
        assert!(r0.is_err());
    }

    #[test]
    fn test_issue_143() {
        let main_template = "one{{> two }}three{{> two }}";
        let two_partial = "--- two ---";

        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("template", main_template)
            .is_ok());
        assert!(handlebars
            .register_template_string("two", two_partial)
            .is_ok());

        let r0 = handlebars.render("template", &true);
        assert_eq!(r0.ok().unwrap(), "one--- two ---three--- two ---");
    }

    #[test]
    fn test_hash_context_outscope() {
        let main_template = "In: {{> p a=2}} Out: {{a}}";
        let p_partial = "{{a}}";

        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("template", main_template)
            .is_ok());
        assert!(handlebars.register_template_string("p", p_partial).is_ok());

        let r0 = handlebars.render("template", &true);
        assert_eq!(r0.ok().unwrap(), "In: 2 Out: ");
    }

    #[test]
    fn test_nested_partial_scope() {
        let t = "{{#*inline \"pp\"}}{{a}} {{b}}{{/inline}}{{#each c}}{{> pp a=2}}{{/each}}";
        let data = json!({"c": [{"b": true}, {"b": false}]});

        let mut handlebars = Registry::new();
        assert!(handlebars.register_template_string("t", t).is_ok());
        let r0 = handlebars.render("t", &data);
        assert_eq!(r0.ok().unwrap(), "2 true2 false");
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

pub use self::imp::*;

#[cfg(target_family = "unix")]
mod imp {
    use libc::pid_t;
    use std::io::Result;
    use std::path::PathBuf;
    use std::process::Command;

    pub struct Process {
        pgid: pid_t,
    }

    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use libc::exit;
            use nix::unistd::*;
            use std::io;
            use std::os::unix::process::CommandExt;

            let mut command = Command::new("sh");
            command.arg("-c").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            // Until process_exec lands in stable, handle fork/exec ourselves
            //command.before_exec(|| setpgid(0, 0).map_err(io::Error::from))
                //.spawn()
                //.and_then(|p| Ok(Process { pid: p.id() as i32 }))

            // Wait for child to call setpgid()
            // Else, we risk racing waitpid/killpg (mostly just in tests, but hey)
            let (r, w) = try!(pipe());

            match fork() {
                Ok(ForkResult::Parent {child, .. }) => {
                    let mut buffer = vec![0];
                    let _ = read(r, &mut buffer);
                    let _ = close(r);
                    let _ = close(w);

                    Ok(Process {
                        pgid: child
                    })
                },
                Ok(ForkResult::Child) => {
                    let _ = setpgid(0, 0);

                    let _ = write(w, &[42]);
                    let _ = close(w);
                    let _ = close(r);

                    let _ = command.exec();

                    // If we get here, there isn't much we can do
                    unsafe {
                        exit(1);
                    }
                }
                Err(e) => { Err(io::Error::from(e)) }
            }
        }

        pub fn kill(&self) {
            use libc::*;

            extern "C" {
                fn killpg(pgrp: pid_t, sig: c_int) -> c_int;
            }

            unsafe {
                killpg(self.pgid, SIGTERM);
            }
        }

        pub fn wait(&self) {
            use nix::sys::wait::waitpid;

            while let Ok(_) = waitpid(-self.pgid, None) {}
        }
    }
}

#[cfg(target_family = "windows")]
mod imp {
    use std::io;
    use std::io::Result;
    use std::mem;
    use std::path::PathBuf;
    use std::process::Command;
    use kernel32::*;
    use winapi::*;

    pub struct Process {
        job: HANDLE,
    }

    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use std::os::windows::io::IntoRawHandle;

            fn last_err() -> io::Error {
                io::Error::last_os_error()
            }

            let job = unsafe { CreateJobObjectW(0 as *mut _, 0 as *const _) };
            if job.is_null() {
                panic!("failed to create job object: {}", last_err());
            }

            let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION = unsafe { mem::zeroed() };
            info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
            let r = unsafe {
                SetInformationJobObject(job,
                                        JobObjectExtendedLimitInformation,
                                        &mut info as *mut _ as LPVOID,
                                        mem::size_of_val(&info) as DWORD)
            };
            if r == 0 {
                panic!("failed to set job info: {}", last_err());
            }

            let mut command = Command::new("cmd.exe");
            command.arg("/C").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            command.spawn()
                .and_then(|p| {
                    let r = unsafe { AssignProcessToJobObject(job, p.into_raw_handle()) };
                    if r == 0 {
                        panic!("failed to add to job object: {}", last_err());
                    }

                    Ok(Process { job: job })
                })
        }

        pub fn kill(&self) {
            unsafe {
                let _ = TerminateJobObject(self.job, 1);
            }
        }

        pub fn wait(&self) {
            unsafe {
                let _ = WaitForSingleObject(self.job, INFINITE);
            }
        }
    }

    impl Drop for Process {
        fn drop(&mut self) {
            unsafe {
                let _ = CloseHandle(self.job);
            }
        }
    }

    unsafe impl Send for Process {}
    unsafe impl Sync for Process {}
}

fn get_single_updated_path(paths: &[PathBuf]) -> Option<&str> {
    paths.get(0).and_then(|p| p.to_str())
}

fn get_longest_common_path(paths: &[PathBuf]) -> Option<String> {
    match paths.len() {
        0 => return None,
        1 => return paths[0].to_str().map(|ref_val| ref_val.to_string()),
        _ => {}
    };

    let mut longest_path: Vec<_> = paths[0].components().collect();

    for path in &paths[1..] {
        let mut greatest_distance = 0;
        for component_pair in path.components().zip(longest_path.iter()) {
            if component_pair.0 != *component_pair.1 {
                break;
            }

            greatest_distance += 1;
        }

        if greatest_distance != longest_path.len() {
            longest_path.truncate(greatest_distance);
        }
    }

    let mut result = PathBuf::new();
    for component in longest_path {
        result.push(component.as_os_str());
    }

    result.to_str().map(|ref_val| ref_val.to_string())
}

#[cfg(test)]
#[cfg(target_family = "unix")]
mod tests {
    use std::path::{Path, PathBuf};

    use mktemp::Temp;

    use super::imp::Process;
    use super::get_longest_common_path;

    fn file_contents(path: &Path) -> String {
        use std::fs::File;
        use std::io::Read;

        let mut f = File::open(path).unwrap();
        let mut s = String::new();
        f.read_to_string(&mut s).unwrap();

        s
    }

    #[test]
    fn test_start() {
        let process = Process::new("echo hi", vec![]);

        assert!(process.is_ok());
    }

    #[test]
    fn test_wait() {
        let file = Temp::new_file().unwrap();
        let path = file.to_path_buf();
        let process = Process::new(&format!("echo hi > {}", path.to_str().unwrap()), vec![])
            .unwrap();
        process.wait();

        assert!(file_contents(&path).starts_with("hi"));
    }

    #[test]
    fn test_kill() {
        let file = Temp::new_file().unwrap();
        let path = file.to_path_buf();

        let process = Process::new(&format!("sleep 20; echo hi > {}", path.to_str().unwrap()),
                                       vec![])
            .unwrap();
        process.kill();
        process.wait();

        assert!(file_contents(&path) == "");
    }

    #[test]
    fn longest_common_path_should_return_correct_value() {
        let single_path = vec![PathBuf::from("/tmp/random/")];
        let single_result = get_longest_common_path(&single_path).unwrap();
        assert_eq!(single_result, "/tmp/random/");

        let common_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/fly")];

        let common_result = get_longest_common_path(&common_paths).unwrap();
        assert_eq!(common_result, "/tmp/logs");

        let diverging_paths = vec![PathBuf::from("/tmp/logs/hi"), PathBuf::from("/var/logs/hi")];

        let diverging_result = get_longest_common_path(&diverging_paths).unwrap();
        assert_eq!(diverging_result, "/");

        let uneven_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/"),
                                PathBuf::from("/tmp/logs/bye")];

        let uneven_result = get_longest_common_path(&uneven_paths).unwrap();
        assert_eq!(uneven_result, "/tmp/logs");
    }
}
<commit_msg>Unix: pipe read/write handles EINTR<commit_after>use std::path::PathBuf;

pub use self::imp::*;

#[cfg(target_family = "unix")]
mod imp {
    use libc::pid_t;
    use std::io::Result;
    use std::path::PathBuf;
    use std::process::Command;

    pub struct Process {
        pgid: pid_t,
    }

    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use libc::exit;
            use nix::unistd::*;
            use std::fs::File;
            use std::io;
            use std::io::{Read, Write};
            use std::os::unix::io::FromRawFd;
            use std::os::unix::process::CommandExt;

            let mut command = Command::new("sh");
            command.arg("-c").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            // Until process_exec lands in stable, handle fork/exec ourselves
            // command.before_exec(|| setpgid(0, 0).map_err(io::Error::from))
            // .spawn()
            // .and_then(|p| Ok(Process { pid: p.id() as i32 }))

            // Wait for child to call setpgid()
            // Else, we risk racing waitpid/killpg (mostly just in tests, but hey)
            let (r, w) = try!(pipe());

            match fork() {
                Ok(ForkResult::Parent { child, .. }) => {
                    {
                        let mut reader = unsafe { File::from_raw_fd(r) };
                        let mut buffer = vec![0];
                        let _ = reader.read_exact(&mut buffer);
                    }
                    let _ = close(w);

                    Ok(Process { pgid: child })
                }
                Ok(ForkResult::Child) => {
                    let _ = setpgid(0, 0);

                    {
                        let mut writer = unsafe { File::from_raw_fd(w) };
                        let _ = writer.write_all(&[42]);
                    }
                    let _ = close(r);

                    let _ = command.exec();

                    // If we get here, there isn't much we can do
                    unsafe {
                        exit(1);
                    }
                }
                Err(e) => Err(io::Error::from(e)),
            }
        }

        pub fn kill(&self) {
            use libc::*;

            extern "C" {
                fn killpg(pgrp: pid_t, sig: c_int) -> c_int;
            }

            unsafe {
                killpg(self.pgid, SIGTERM);
            }
        }

        pub fn wait(&self) {
            use nix::sys::wait::waitpid;

            while let Ok(_) = waitpid(-self.pgid, None) {}
        }
    }
}

#[cfg(target_family = "windows")]
mod imp {
    use std::io;
    use std::io::Result;
    use std::mem;
    use std::path::PathBuf;
    use std::process::Command;
    use kernel32::*;
    use winapi::*;

    pub struct Process {
        job: HANDLE,
    }

    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use std::os::windows::io::IntoRawHandle;

            fn last_err() -> io::Error {
                io::Error::last_os_error()
            }

            let job = unsafe { CreateJobObjectW(0 as *mut _, 0 as *const _) };
            if job.is_null() {
                panic!("failed to create job object: {}", last_err());
            }

            let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION = unsafe { mem::zeroed() };
            info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
            let r = unsafe {
                SetInformationJobObject(job,
                                        JobObjectExtendedLimitInformation,
                                        &mut info as *mut _ as LPVOID,
                                        mem::size_of_val(&info) as DWORD)
            };
            if r == 0 {
                panic!("failed to set job info: {}", last_err());
            }

            let mut command = Command::new("cmd.exe");
            command.arg("/C").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            command.spawn()
                .and_then(|p| {
                    let r = unsafe { AssignProcessToJobObject(job, p.into_raw_handle()) };
                    if r == 0 {
                        panic!("failed to add to job object: {}", last_err());
                    }

                    Ok(Process { job: job })
                })
        }

        pub fn kill(&self) {
            unsafe {
                let _ = TerminateJobObject(self.job, 1);
            }
        }

        pub fn wait(&self) {
            unsafe {
                let _ = WaitForSingleObject(self.job, INFINITE);
            }
        }
    }

    impl Drop for Process {
        fn drop(&mut self) {
            unsafe {
                let _ = CloseHandle(self.job);
            }
        }
    }

    unsafe impl Send for Process {}
    unsafe impl Sync for Process {}
}

fn get_single_updated_path(paths: &[PathBuf]) -> Option<&str> {
    paths.get(0).and_then(|p| p.to_str())
}

fn get_longest_common_path(paths: &[PathBuf]) -> Option<String> {
    match paths.len() {
        0 => return None,
        1 => return paths[0].to_str().map(|ref_val| ref_val.to_string()),
        _ => {}
    };

    let mut longest_path: Vec<_> = paths[0].components().collect();

    for path in &paths[1..] {
        let mut greatest_distance = 0;
        for component_pair in path.components().zip(longest_path.iter()) {
            if component_pair.0 != *component_pair.1 {
                break;
            }

            greatest_distance += 1;
        }

        if greatest_distance != longest_path.len() {
            longest_path.truncate(greatest_distance);
        }
    }

    let mut result = PathBuf::new();
    for component in longest_path {
        result.push(component.as_os_str());
    }

    result.to_str().map(|ref_val| ref_val.to_string())
}

#[cfg(test)]
#[cfg(target_family = "unix")]
mod tests {
    use std::path::{Path, PathBuf};

    use mktemp::Temp;

    use super::imp::Process;
    use super::get_longest_common_path;

    fn file_contents(path: &Path) -> String {
        use std::fs::File;
        use std::io::Read;

        let mut f = File::open(path).unwrap();
        let mut s = String::new();
        f.read_to_string(&mut s).unwrap();

        s
    }

    #[test]
    fn test_start() {
        let process = Process::new("echo hi", vec![]);

        assert!(process.is_ok());
    }

    #[test]
    fn test_wait() {
        let file = Temp::new_file().unwrap();
        let path = file.to_path_buf();
        let process = Process::new(&format!("echo hi > {}", path.to_str().unwrap()), vec![])
            .unwrap();
        process.wait();

        assert!(file_contents(&path).starts_with("hi"));
    }

    #[test]
    fn test_kill() {
        let file = Temp::new_file().unwrap();
        let path = file.to_path_buf();

        let process = Process::new(&format!("sleep 20; echo hi > {}", path.to_str().unwrap()),
                                   vec![])
            .unwrap();
        process.kill();
        process.wait();

        assert!(file_contents(&path) == "");
    }

    #[test]
    fn longest_common_path_should_return_correct_value() {
        let single_path = vec![PathBuf::from("/tmp/random/")];
        let single_result = get_longest_common_path(&single_path).unwrap();
        assert_eq!(single_result, "/tmp/random/");

        let common_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/fly")];

        let common_result = get_longest_common_path(&common_paths).unwrap();
        assert_eq!(common_result, "/tmp/logs");

        let diverging_paths = vec![PathBuf::from("/tmp/logs/hi"), PathBuf::from("/var/logs/hi")];

        let diverging_result = get_longest_common_path(&diverging_paths).unwrap();
        assert_eq!(diverging_result, "/");

        let uneven_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/"),
                                PathBuf::from("/tmp/logs/bye")];

        let uneven_result = get_longest_common_path(&uneven_paths).unwrap();
        assert_eq!(uneven_result, "/tmp/logs");
    }
}
<|endoftext|>


<commit_before>use command::Command;

pub struct Program {
    instructions : Vec<Command>,
    is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}
<commit_msg>Add Program::new()<commit_after>use command::Command;

pub struct Program {
    instructions : Vec<Command>,
    is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }
}
<|endoftext|>


<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use std::io::signal::{Listener, Interrupt};
use std::libc;
use std::num;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
    cmd_history: ~[~str]
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
	    cmd_history: ~[]
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
	    self.cmd_history.push(cmd_line.clone());
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

	    let mut mod_prog = program.clone();
	    let prog_length = mod_prog.len();
	    if mod_prog.slice_from(prog_length - 1) == "&" {
	       mod_prog = mod_prog.slice_to(prog_length - 1);
	    }

            match mod_prog {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                _       =>  { self.run_pipes(cmd_line); }
            }
        }
    }

    fn run_pipes(&mut self, cmd_line: &str) {
       let progs: ~[~str] =
       	       	      cmd_line.split('|').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
       let mut channels: ~[std::os::Pipe] = ~[];
       for _ in range(0, progs.len()) {
       	   channels.push(std::os::pipe());
       }
       for i in range(0, progs.len()) {
       	   let mut in_chan = libc::STDIN_FILENO;
	   let mut out_chan = libc::STDOUT_FILENO;
	   if i == 0 {
	      out_chan = channels[i].out;
	   }
       	   if i > 0 {
	      in_chan = channels[i-1].input;
	      out_chan = channels[i].out;
	   }
	   if i == progs.len() - 1 {
	      out_chan = libc::STDOUT_FILENO;
	   }
	   self.run_cmdline(progs[i].trim().clone(), in_chan, out_chan);
       }
    }

    fn run_cmdline(&mut self, cmd_line: &str, in_chan: libc::c_int, out_chan: libc::c_int) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
        if argv.len() > 0 {
	   let program: ~str = argv.remove(0);
	   let mut mod_prog = program.clone();
	   /*
	   if mod_prog == ~"grep" {
	      if argv.len() > 0 {
	      	 let mut matching = argv.pop();
		 if matching.slice_to(1) == "\"" && matching.slice_from(matching.len() - 1) == "\"" {
		    matching = matching.slice_to(matching.len() - 1).to_owned();
		    matching = matching.slice_from(1).to_owned();
	      	 }
		 argv.push(matching);
	      }
	   }
	   */
	   let mut background = false;
	   if argv.len() == 0 {
	      let prog_length = mod_prog.len();
	      if mod_prog.slice_from(prog_length - 1) == "&" {
	      	 mod_prog = mod_prog.slice_to(prog_length - 1).trim().to_owned();
	       	 background = true;
	      }
	   }
	   else {
	      let mut last_arg = argv[argv.len() - 1].clone();
	      if last_arg == ~"&" {
	      	 argv.pop();
		 background = true;
	      }
	      else {
	      	   let arg_length = last_arg.len();
	      	   if last_arg.slice_from(arg_length - 1) == "&" {
	      	      last_arg = last_arg.slice_to(arg_length - 1).to_owned();
		      argv.pop();
		      argv.push(last_arg);
		      background = true;
	      	   }
	      }
	   }

	   // Handle IO redirection
	   let mut input: libc::c_int = in_chan;
	   let mut output: libc::c_int = out_chan;
	   let argv_length = argv.len();
	   for i in range(0, argv_length) {
	       if i >= argv.len() {
	       	  break;
	       }
	       if argv[i] == ~"<" {
	       	  argv.remove(i);
	       	  if i >= argv.len() {
		     println!("No file specified for input.")
		     return;
		  }
		  else {
		       unsafe{
			let in_file_name = argv.remove(i);
		       	let mode = "r".to_c_str().unwrap();
			let file_path = Path::new(in_file_name.clone());
			if file_path.exists() {
			   let name_in_str = in_file_name.clone().to_c_str().unwrap();
			   let in_file = libc::fopen(name_in_str, mode);
		       	   input = libc::fileno(in_file);
			}
			else {
			   println!("Input file does not exists!");
			   return;
			}
		       }
		  }
	       }
	       if i >= argv.len() {
	       	  break;
	       }
	       if argv[i] == ~">" {
	       	  argv.remove(i);
		  if i >= argv.len() {
		     println!("No file specified for output.")
		     return;
		  }
		  else {
		       unsafe {
		       	 let out_file_name = argv.remove(i).to_c_str().unwrap();
		       	 let mode = "w".to_c_str().unwrap();
		       	 let out_file = libc::fopen(out_file_name, mode);
		       	 output = libc::fileno(out_file);
		       }
		     if output == -1 {
		     	println!("Invalid file for output.");
			return;
		     }
		  }
	       }
	   }

	   if background {
	      let prog = mod_prog.clone();
	      let arguments = argv.clone();
	      let fin_chan = input.clone();
	      let fout_chan = output.clone();
	      let err_chan = libc::STDERR_FILENO;
	      if self.cmd_exists(prog) {
	      	 do spawn {
		    let proc_run_opt = run::Process::new(prog, arguments, run::ProcessOptions {
		    		  			  	     env: None,
								     dir: None,
								     in_fd: Some(fin_chan),
								     out_fd: Some(fout_chan),
								     err_fd: Some(err_chan)
		    		  			  	     });
		    let mut proc_run = proc_run_opt.unwrap();
		    let mut listener = Listener::new();
		    listener.register(Interrupt);
		    proc_run.finish();
		    if fin_chan != 0 {
		       std::os::close(fin_chan);
		    }
		    if fout_chan != 1 {
		       std::os::close(fout_chan);
		    }
		 }
	      }
	      else {
	      	 println!("{:s}: command not found", prog);
	      }
	   }
	   else {
	   	self.run_cmd(program, argv, input, output);
	   }
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str], input_chan: libc::c_int, output_chan: libc::c_int) {
        if self.cmd_exists(program) {
	    if program == "cd" {
	       if argv.len() > 1 {
	       	  println!("Usage: cd <directory>!");
	       }
	       else if argv.len() == 0 {
	       	  let tar_path = std::os::homedir().unwrap();
		  os::change_dir(&tar_path);
	       }
	       else {
	       	  let tar_path = Path::new(argv[0].clone());
		  match os::change_dir(&tar_path) {
		  	true => { return; }
			false => { println!("No such directory!"); }
		  }
	       }
	    }
	    else {
            	  let proc_run_opt = run::Process::new(program, argv, run::ProcessOptions {
		    		  			  	     env: None,
								     dir: None,
								     in_fd: Some(input_chan),
								     out_fd: Some(output_chan),
								     err_fd: Some(libc::STDERR_FILENO)
		    		  			  	     });
		  let mut proc_run = proc_run_opt.unwrap();
		  let mut listener = Listener::new();
		  listener.register(Interrupt);
		  proc_run.finish();
		  if input_chan != 0 {
		     std::os::close(input_chan);
		  }
		  if output_chan != 1 {
		     std::os::close(output_chan);
		  }
            }
        }
	else if program == "history" {
	     for i in range(0, self.cmd_history.len()) {
	     	 println!(" {:u} {:s}", i+1, self.cmd_history[i]);
	     }
	     let mut stdin = BufferedReader::new(stdin());
	     loop {
	     	  println!("Enter the next command you want to rerun (-1 to quit): ");
	     	  let input_no_str = stdin.read_line().unwrap_or(~"-1");
		  let input_no = from_str::<int>(input_no_str.slice_to(input_no_str.len() - 1)).unwrap();
		  if input_no == -1 {
		     break;
		  }
		  else if input_no < num::from_uint(self.cmd_history.len()).unwrap() {
		     let retrieved_cmd = self.cmd_history[input_no - 1].clone();
		     self.cmd_history.push(retrieved_cmd.clone());
		     self.run_pipes(retrieved_cmd);
		     break;
		  }
		  else {
		      println!("Invalid index for command!");
		  }
	     }
	}
	else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line, libc::STDIN_FILENO, libc::STDOUT_FILENO),
        None           => Shell::new("gash > ").run()
    }
}
<commit_msg>Trying the non-blocking pipeline<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use std::io::signal::{Listener, Interrupt};
use std::libc;
use std::num;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
    cmd_history: ~[~str]
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
	    cmd_history: ~[]
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
	    self.cmd_history.push(cmd_line.clone());
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

	    let mut mod_prog = program.clone();
	    let prog_length = mod_prog.len();
	    if mod_prog.slice_from(prog_length - 1) == "&" {
	       mod_prog = mod_prog.slice_to(prog_length - 1);
	    }

            match mod_prog {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                _       =>  { self.run_pipes(cmd_line); }
            }
        }
    }

    fn run_pipes(&mut self, cmd_line: &str) {
       let progs: ~[~str] =
       	       	      cmd_line.split('|').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
       let mut channels: ~[std::os::Pipe] = ~[];
       for _ in range(0, progs.len()) {
       	   channels.push(std::os::pipe());
       }
       for i in range(0, progs.len()) {
       	   let mut in_chan = libc::STDIN_FILENO;
	   let mut out_chan = libc::STDOUT_FILENO;
	   if i == 0 {
	      out_chan = channels[i].out;
	   }
       	   if i > 0 {
	      in_chan = channels[i-1].input;
	      out_chan = channels[i].out;
	   }
	   if i == progs.len() - 1 {
	      out_chan = libc::STDOUT_FILENO;
	   }
	   if i == progs.len() - 1 {
	      self.run_cmdline(progs[i].trim().clone(), in_chan, out_chan, false);
	   }
	   else {
	      self.run_cmdline(progs[i].trim().clone(), in_chan, out_chan, true);
	   }
       }
    }

    fn run_cmdline(&mut self, cmd_line: &str, in_chan: libc::c_int, out_chan: libc::c_int, bg: bool) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
        if argv.len() > 0 {
	   let program: ~str = argv.remove(0);
	   let mut mod_prog = program.clone();
	   /*
	   if mod_prog == ~"grep" {
	      if argv.len() > 0 {
	      	 let mut matching = argv.pop();
		 if matching.slice_to(1) == "\"" && matching.slice_from(matching.len() - 1) == "\"" {
		    matching = matching.slice_to(matching.len() - 1).to_owned();
		    matching = matching.slice_from(1).to_owned();
	      	 }
		 argv.push(matching);
	      }
	   }
	   */
	   let mut background = bg;
	   if argv.len() == 0 {
	      let prog_length = mod_prog.len();
	      if mod_prog.slice_from(prog_length - 1) == "&" {
	      	 mod_prog = mod_prog.slice_to(prog_length - 1).trim().to_owned();
	       	 background = true;
	      }
	   }
	   else {
	      let mut last_arg = argv[argv.len() - 1].clone();
	      if last_arg == ~"&" {
	      	 argv.pop();
		 background = true;
	      }
	      else {
	      	   let arg_length = last_arg.len();
	      	   if last_arg.slice_from(arg_length - 1) == "&" {
	      	      last_arg = last_arg.slice_to(arg_length - 1).to_owned();
		      argv.pop();
		      argv.push(last_arg);
		      background = true;
	      	   }
	      }
	   }

	   // Handle IO redirection
	   let mut input: libc::c_int = in_chan;
	   let mut output: libc::c_int = out_chan;
	   let argv_length = argv.len();
	   for i in range(0, argv_length) {
	       if i >= argv.len() {
	       	  break;
	       }
	       if argv[i] == ~"<" {
	       	  argv.remove(i);
	       	  if i >= argv.len() {
		     println!("No file specified for input.")
		     return;
		  }
		  else {
		       unsafe{
			let in_file_name = argv.remove(i);
		       	let mode = "r".to_c_str().unwrap();
			let file_path = Path::new(in_file_name.clone());
			if file_path.exists() {
			   let name_in_str = in_file_name.clone().to_c_str().unwrap();
			   let in_file = libc::fopen(name_in_str, mode);
		       	   input = libc::fileno(in_file);
			}
			else {
			   println!("Input file does not exists!");
			   return;
			}
		       }
		  }
	       }
	       if i >= argv.len() {
	       	  break;
	       }
	       if argv[i] == ~">" {
	       	  argv.remove(i);
		  if i >= argv.len() {
		     println!("No file specified for output.")
		     return;
		  }
		  else {
		       unsafe {
		       	 let out_file_name = argv.remove(i).to_c_str().unwrap();
		       	 let mode = "w".to_c_str().unwrap();
		       	 let out_file = libc::fopen(out_file_name, mode);
		       	 output = libc::fileno(out_file);
		       }
		     if output == -1 {
		     	println!("Invalid file for output.");
			return;
		     }
		  }
	       }
	   }

	   if background {
	      let prog = mod_prog.clone();
	      let arguments = argv.clone();
	      let fin_chan = input.clone();
	      let fout_chan = output.clone();
	      let err_chan = libc::STDERR_FILENO;
	      if self.cmd_exists(prog) {
	      	 do spawn {
		    let proc_run_opt = run::Process::new(prog, arguments, run::ProcessOptions {
		    		  			  	     env: None,
								     dir: None,
								     in_fd: Some(fin_chan),
								     out_fd: Some(fout_chan),
								     err_fd: Some(err_chan)
		    		  			  	     });
		    let mut proc_run = proc_run_opt.unwrap();
		    let mut listener = Listener::new();
		    listener.register(Interrupt);
		    proc_run.finish();
		    if fin_chan != 0 {
		       std::os::close(fin_chan);
		    }
		    if fout_chan != 1 {
		       std::os::close(fout_chan);
		    }
		 }
	      }
	      else {
	      	 println!("{:s}: command not found", prog);
	      }
	   }
	   else {
	   	self.run_cmd(program, argv, input, output);
	   }
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str], input_chan: libc::c_int, output_chan: libc::c_int) {
        if self.cmd_exists(program) {
	    if program == "cd" {
	       if argv.len() > 1 {
	       	  println!("Usage: cd <directory>!");
	       }
	       else if argv.len() == 0 {
	       	  let tar_path = std::os::homedir().unwrap();
		  os::change_dir(&tar_path);
	       }
	       else {
	       	  let tar_path = Path::new(argv[0].clone());
		  match os::change_dir(&tar_path) {
		  	true => { return; }
			false => { println!("No such directory!"); }
		  }
	       }
	    }
	    else {
            	  let proc_run_opt = run::Process::new(program, argv, run::ProcessOptions {
		    		  			  	     env: None,
								     dir: None,
								     in_fd: Some(input_chan),
								     out_fd: Some(output_chan),
								     err_fd: Some(libc::STDERR_FILENO)
		    		  			  	     });
		  let mut proc_run = proc_run_opt.unwrap();
		  let mut listener = Listener::new();
		  listener.register(Interrupt);
		  proc_run.finish();
		  if input_chan != 0 {
		     std::os::close(input_chan);
		  }
		  if output_chan != 1 {
		     std::os::close(output_chan);
		  }
            }
        }
	else if program == "history" {
	     for i in range(0, self.cmd_history.len()) {
	     	 println!(" {:u} {:s}", i+1, self.cmd_history[i]);
	     }
	     let mut stdin = BufferedReader::new(stdin());
	     loop {
	     	  println!("Enter the next command you want to rerun (-1 to quit): ");
	     	  let input_no_str = stdin.read_line().unwrap_or(~"-1");
		  let input_no = from_str::<int>(input_no_str.slice_to(input_no_str.len() - 1)).unwrap();
		  if input_no == -1 {
		     break;
		  }
		  else if input_no < num::from_uint(self.cmd_history.len()).unwrap() {
		     let retrieved_cmd = self.cmd_history[input_no - 1].clone();
		     self.cmd_history.push(retrieved_cmd.clone());
		     self.run_pipes(retrieved_cmd);
		     break;
		  }
		  else {
		      println!("Invalid index for command!");
		  }
	     }
	}
	else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line, libc::STDIN_FILENO, libc::STDOUT_FILENO, false),
        None           => Shell::new("gash > ").run()
    }
}
<|endoftext|>


<commit_before>//! Proper testing, with QuickCheck.

use {Trie, TrieKey, TrieCommon};
use std::iter::FromIterator;
use std::collections::{HashSet, HashMap};
use quickcheck::{quickcheck, Gen, Arbitrary};

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
struct Key(Vec<u8>);

#[derive(Clone, Debug)]
struct RandomKeys(HashSet<Key>);

const MAX_KEYS: usize = 512;
const KEY_RUN_LEN: usize = 8;
const KEY_MAX_VAL: u8 = 4;

impl Arbitrary for Key {
    fn arbitrary<G: Gen>(g: &mut G) -> Key {
        let len = g.gen::<usize>() % KEY_RUN_LEN;
        let mut key = Vec::with_capacity(len);
        for _ in 0..len {
            key.push(g.gen::<u8>() % KEY_MAX_VAL);
        }
        Key(key)
    }
}

impl Key {
    fn extend_random<G: Gen>(&self, g: &mut G) -> Key {
        let mut key = self.clone();
        key.0.extend(Key::arbitrary(g).0);
        key
    }

    fn len(&self) -> usize {
        self.0.len()
    }
}

impl TrieKey for Key {
    fn encode_bytes(&self) -> Vec<u8> {
        self.0.clone()
    }
}

impl Arbitrary for RandomKeys {
    fn arbitrary<G: Gen>(g: &mut G) -> RandomKeys {
        let num_keys = g.gen::<usize>() % MAX_KEYS;
        let mut keys = Vec::with_capacity(num_keys);
        keys.push(Key::arbitrary(g));

        for _ in 0..num_keys {
            match g.gen::<u8>() % 10 {
                // Generate a new random key.
                1 => keys.push(Key::arbitrary(g)),
                // Extend an existing key.
                _ => {
                    let i = g.gen::<usize>() % keys.len();
                    let key = keys[i].extend_random(g);
                    keys.push(key);
                }
            }
        }

        RandomKeys(HashSet::from_iter(keys))
    }
}

#[test]
fn insert_all_remove_all() {
    fn prop(RandomKeys(keys): RandomKeys) -> bool {
        let mut trie = Trie::new();
        let mut length = 0;

        for k in &keys {
            if trie.insert(k.clone(), k.len()).is_some() {
                return false;
            }
            length += 1;
            if trie.len() != length {
                return false;
            }
        }

        if !trie.check_integrity() {
            return false;
        }

        for k in &keys {
            if trie.get(&k) != Some(&k.len()) {
                return false;
            }
            if trie.remove(&k) != Some(k.len()) {
                return false;
            }
            length -= 1;
            if trie.len() != length {
                return false;
            }
            if trie.get(&k).is_some() {
                return false;
            }
        }
        if !trie.check_integrity() {
            return false;
        }
        true
    }

    quickcheck(prop as fn(RandomKeys) -> bool);
}

#[test]
fn subtrie() {
    fn prop(RandomKeys(keys): RandomKeys) -> bool {
        let half = keys.len() / 2;
        let first_half = keys.iter().take(half).map(|k| (k.clone(), k.len()));
        let trie = Trie::from_iter(first_half);

        // Check node existence for inserted keys.
        for k in keys.iter().take(half) {
            match trie.subtrie(&k) {
                Some(node) => {
                    if node.value() != Some(&k.len()) {
                        return false;
                    }
                }
                None => return false,
            }
        }

        // Check that nodes for non-inserted keys don't have values.
        for k in keys.iter().skip(half) {
            if let Some(node) = trie.subtrie(&k) {
                if node.value().is_some() {
                    return false;
                }
            }
        }

        true
    }

    quickcheck(prop as fn(RandomKeys) -> bool);
}

// Construct a trie from a set of keys, with each key mapped to its length.
fn length_trie(keys: HashSet<Key>) -> Trie<Key, usize> {
    let mut t = Trie::new();
    for k in keys {
        let len = k.len();
        t.insert(k, len);
    }
    t
}

#[test]
fn keys_iter() {
    fn prop(RandomKeys(keys): RandomKeys) -> bool {
        let trie = length_trie(keys.clone());
        let trie_keys: HashSet<Key> = trie.keys().cloned().collect();
        trie_keys == keys
    }
    quickcheck(prop as fn(RandomKeys) -> bool);
}

#[test]
fn values_iter() {
    // Create a map of values to frequencies.
    fn frequency_map<I: Iterator<Item = usize>>(values: I) -> HashMap<usize, u64> {
        let mut map = HashMap::new();
        for v in values {
            let current_val = map.entry(v).or_insert(0);
            *current_val += 1;
        }
        map
    }

    fn prop(RandomKeys(keys): RandomKeys) -> bool {
        let trie = length_trie(keys.clone());
        let trie_values: HashMap<usize, u64> = frequency_map(trie.values().cloned());
        let key_values = frequency_map(keys.into_iter().map(|k| k.len()));
        trie_values == key_values
    }
    quickcheck(prop as fn(RandomKeys) -> bool);
}
<commit_msg>Some subtrie QuickCheck tests.<commit_after>//! Proper testing, with QuickCheck.

use {Trie, TrieKey, TrieCommon};
use std::iter::FromIterator;
use std::collections::{HashSet, HashMap};
use quickcheck::{quickcheck, Gen, Arbitrary};

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
struct Key(Vec<u8>);

#[derive(Clone, Debug)]
struct RandomKeys(HashSet<Key>);

const MAX_KEYS: usize = 512;
const KEY_RUN_LEN: usize = 8;
const KEY_MAX_VAL: u8 = 4;

impl Arbitrary for Key {
    fn arbitrary<G: Gen>(g: &mut G) -> Key {
        let len = g.gen::<usize>() % KEY_RUN_LEN;
        let mut key = Vec::with_capacity(len);
        for _ in 0..len {
            key.push(g.gen::<u8>() % KEY_MAX_VAL);
        }
        Key(key)
    }
}

impl Key {
    fn extend_random<G: Gen>(&self, g: &mut G) -> Key {
        self.extend(Key::arbitrary(g))
    }

    fn extend(&self, other: Key) -> Key {
        let mut key = self.clone();
        key.0.extend(other.0);
        key
    }

    fn len(&self) -> usize {
        self.0.len()
    }
}

impl TrieKey for Key {
    fn encode_bytes(&self) -> Vec<u8> {
        self.0.clone()
    }
}

impl Arbitrary for RandomKeys {
    fn arbitrary<G: Gen>(g: &mut G) -> RandomKeys {
        let num_keys = g.gen::<usize>() % MAX_KEYS;
        let mut keys = Vec::with_capacity(num_keys);
        keys.push(Key::arbitrary(g));

        for _ in 0..num_keys {
            match g.gen::<u8>() % 10 {
                // Generate a new random key.
                1 => keys.push(Key::arbitrary(g)),
                // Extend an existing key.
                _ => {
                    let i = g.gen::<usize>() % keys.len();
                    let key = keys[i].extend_random(g);
                    keys.push(key);
                }
            }
        }

        RandomKeys(HashSet::from_iter(keys))
    }
}

#[test]
fn insert_all_remove_all() {
    fn prop(RandomKeys(keys): RandomKeys) -> bool {
        let mut trie = Trie::new();
        let mut length = 0;

        for k in &keys {
            if trie.insert(k.clone(), k.len()).is_some() {
                return false;
            }
            length += 1;
            if trie.len() != length {
                return false;
            }
        }

        if !trie.check_integrity() {
            return false;
        }

        for k in &keys {
            if trie.get(&k) != Some(&k.len()) {
                return false;
            }
            if trie.remove(&k) != Some(k.len()) {
                return false;
            }
            length -= 1;
            if trie.len() != length {
                return false;
            }
            if trie.get(&k).is_some() {
                return false;
            }
        }
        if !trie.check_integrity() {
            return false;
        }
        true
    }

    quickcheck(prop as fn(RandomKeys) -> bool);
}

#[test]
fn subtrie() {
    fn prop(RandomKeys(keys): RandomKeys) -> bool {
        let half = keys.len() / 2;
        let first_half = keys.iter().take(half).map(|k| (k.clone(), k.len()));
        let trie = Trie::from_iter(first_half);

        // Check node existence for inserted keys.
        for k in keys.iter().take(half) {
            match trie.subtrie(&k) {
                Some(node) => {
                    if node.value() != Some(&k.len()) {
                        return false;
                    }
                }
                None => return false,
            }
        }

        // Check that nodes for non-inserted keys don't have values.
        for k in keys.iter().skip(half) {
            if let Some(node) = trie.subtrie(&k) {
                if node.value().is_some() {
                    return false;
                }
            }
        }

        true
    }

    quickcheck(prop as fn(RandomKeys) -> bool);
}

// trie.subtrie(k1).get(k2) should be the same as trie.get(k2) if k1 is a prefix of k2.
#[test]
fn subtrie_get() {
    fn prop(trie_keys: RandomKeys, k1: Key, k2: Key) -> bool {
        let mut trie = length_trie(trie_keys.0);
        trie.insert(k1.clone(), k1.len());

        let subtrie = trie.subtrie(&k1).unwrap();

        if k2.0.starts_with(&k1.0) {
            subtrie.get(&k2).unwrap() == trie.get(&k2)
        } else {
            subtrie.get(&k2).is_err()
        }
    }

    quickcheck(prop as fn(RandomKeys, Key, Key) -> bool);
}

#[test]
fn subtrie_mut_get() {
    fn prop(trie_keys: RandomKeys, k1: Key, k2: Key) -> bool {
        let mut trie = length_trie(trie_keys.0);
        trie.insert(k1.clone(), k1.len());

        let subtrie = trie.subtrie_mut(&k1).unwrap();

        if k2.0.starts_with(&k1.0) {
            subtrie.get(&k2).is_ok()
        } else {
            subtrie.get(&k2).is_err()
        }
    }

    quickcheck(prop as fn(RandomKeys, Key, Key) -> bool);
}

#[test]
fn subtrie_insert() {
    fn prop(
        trie_keys: RandomKeys,
        key_suffixes: RandomKeys,
        k1: Key
    ) -> bool {
        let mut trie = length_trie(trie_keys.0);
        trie.insert(k1.clone(), k1.len());

        {
            let mut subtrie = trie.subtrie_mut(&k1).unwrap();

            let insert_keys = key_suffixes.0.into_iter()
                .map(|x| k1.extend(x))
                .collect::<HashSet<_>>();

            for k in insert_keys.iter() {
                assert!(subtrie.insert(k.clone(), k.len()).is_ok());
            }

            for k in insert_keys.iter() {
                match subtrie.get(k) {
                    Ok(Some(_)) => (),
                    _ => return false
                }
            }
        }

        trie.check_integrity()
    }

    quickcheck(prop as fn(RandomKeys, RandomKeys, Key) -> bool);
}

// Construct a trie from a set of keys, with each key mapped to its length.
fn length_trie(keys: HashSet<Key>) -> Trie<Key, usize> {
    let mut t = Trie::new();
    for k in keys {
        let len = k.len();
        t.insert(k, len);
    }
    t
}

#[test]
fn keys_iter() {
    fn prop(RandomKeys(keys): RandomKeys) -> bool {
        let trie = length_trie(keys.clone());
        let trie_keys: HashSet<Key> = trie.keys().cloned().collect();
        trie_keys == keys
    }
    quickcheck(prop as fn(RandomKeys) -> bool);
}

#[test]
fn values_iter() {
    // Create a map of values to frequencies.
    fn frequency_map<I: Iterator<Item = usize>>(values: I) -> HashMap<usize, u64> {
        let mut map = HashMap::new();
        for v in values {
            let current_val = map.entry(v).or_insert(0);
            *current_val += 1;
        }
        map
    }

    fn prop(RandomKeys(keys): RandomKeys) -> bool {
        let trie = length_trie(keys.clone());
        let trie_values: HashMap<usize, u64> = frequency_map(trie.values().cloned());
        let key_values = frequency_map(keys.into_iter().map(|k| k.len()));
        trie_values == key_values
    }
    quickcheck(prop as fn(RandomKeys) -> bool);
}
<|endoftext|>


<commit_before>
use ffi;
use super::util::FFTW_MUTEX;

use num_complex::Complex64 as c64;
use std::slice::{from_raw_parts, from_raw_parts_mut};
use std::os::raw::c_void;
use std::ops::{Index, IndexMut};
use std::slice::{Iter, IterMut};

pub struct RawVec<T> {
    n: usize,
    data: *mut T,
}

impl<T> RawVec<T> {
    pub fn as_slice(&self) -> &[T] { unsafe { from_raw_parts(self.data, self.n) } }
    pub fn as_mut_slice(&mut self) -> &mut [T] { unsafe { from_raw_parts_mut(self.data, self.n) } }

    pub fn as_ptr(&self) -> *const T { self.data }
    pub fn as_mut_ptr(&mut self) -> *mut T { self.data }

    pub fn len(&self) -> usize { self.n }

    pub fn iter<'a>(&'a self) -> Iter<'a, T> { self.as_slice().iter() }
    pub fn iter_mut<'a>(&'a mut self) -> IterMut<'a, T> { self.as_mut_slice().iter_mut() }
}

impl<T> Drop for RawVec<T> {
    fn drop(&mut self) {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe { ffi::fftw_free(self.data as *mut c_void) };
        drop(lock);
    }
}

impl RawVec<f64> {
    pub fn new(n: usize) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let ptr = unsafe { ffi::fftw_alloc_real(n) };
        drop(lock);
        RawVec { n: n, data: ptr }
    }
}

impl RawVec<c64> {
    pub fn new(n: usize) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let ptr = unsafe { ffi::fftw_alloc_complex(n) } as *mut c64;
        drop(lock);
        RawVec { n: n, data: ptr }
    }
}

impl<T> Index<isize> for RawVec<T> {
    type Output = T;
    fn index(&self, index: isize) -> &Self::Output { unsafe { &*self.data.offset(index) } }
}

impl<T> IndexMut<isize> for RawVec<T> {
    fn index_mut(&mut self, index: isize) -> &mut Self::Output { unsafe { &mut *self.data.offset(index) } }
}
<commit_msg>raw_vec: Fill zero in RawVec<commit_after>
use ffi;
use super::util::FFTW_MUTEX;

use num_complex::Complex64 as c64;
use std::slice::{from_raw_parts, from_raw_parts_mut};
use std::os::raw::c_void;
use std::ops::{Index, IndexMut};
use std::slice::{Iter, IterMut};

pub struct RawVec<T> {
    n: usize,
    data: *mut T,
}

impl<T> RawVec<T> {
    pub fn as_slice(&self) -> &[T] { unsafe { from_raw_parts(self.data, self.n) } }
    pub fn as_mut_slice(&mut self) -> &mut [T] { unsafe { from_raw_parts_mut(self.data, self.n) } }

    pub fn as_ptr(&self) -> *const T { self.data }
    pub fn as_mut_ptr(&mut self) -> *mut T { self.data }

    pub fn len(&self) -> usize { self.n }

    pub fn iter<'a>(&'a self) -> Iter<'a, T> { self.as_slice().iter() }
    pub fn iter_mut<'a>(&'a mut self) -> IterMut<'a, T> { self.as_mut_slice().iter_mut() }
}

impl<T> Drop for RawVec<T> {
    fn drop(&mut self) {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe { ffi::fftw_free(self.data as *mut c_void) };
        drop(lock);
    }
}

impl RawVec<f64> {
    pub fn new(n: usize) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let ptr = unsafe { ffi::fftw_alloc_real(n) };
        drop(lock);
        let mut vec = RawVec { n: n, data: ptr };
        for v in vec.iter_mut() {
            *v = 0.0;
        }
        vec
    }
}

impl RawVec<c64> {
    pub fn new(n: usize) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let ptr = unsafe { ffi::fftw_alloc_complex(n) } as *mut c64;
        drop(lock);
        let mut vec = RawVec { n: n, data: ptr };
        for v in vec.iter_mut() {
            *v = c64::new(0.0, 0.0);
        }
        vec
    }
}

impl<T> Index<isize> for RawVec<T> {
    type Output = T;
    fn index(&self, index: isize) -> &Self::Output { unsafe { &*self.data.offset(index) } }
}

impl<T> IndexMut<isize> for RawVec<T> {
    fn index_mut(&mut self, index: isize) -> &mut Self::Output { unsafe { &mut *self.data.offset(index) } }
}
<|endoftext|>