<commit_before>use std::collections::VecDeque;
use ordered_vec_map::InsertionResult;
use disambiguation_map::{DisambiguationMap, Match};
use termion::event::{Key, parse_event};
use op::{NormalOp, InsertOp};
use std::cmp::{min, max};
use std::cmp::Ordering;

/// By convention:
/// * K is a map's key type, implementing `Copy` and `Ord`.
/// * T is an arbitrary type, typically stored as a value in a map.
/// * Op is an arbitrary operation type (typically a mode-specific enum).

pub struct ModeMap<K, Op>
where
    K: Ord,
    K: Copy,
    Op: Copy,
{
    remap_map: DisambiguationMap<K, Vec<K>>,
    op_map: DisambiguationMap<K, Op>,
}

impl<K, Op> ModeMap<K, Op>
where
    K: Ord,
    K: Copy,
    Op: Copy,
{
    pub fn new() -> Self {
        ModeMap {
            remap_map: DisambiguationMap::new(),
            op_map: DisambiguationMap::new(),
        }
    }

    /// Process a typeahead buffer.
    pub fn process(&self, mut typeahead: &mut VecDeque<K>) -> Option<Op> {
        // Grab keys from the front of the queue, looking for matches.
        let mut i: usize = 0;
        const MAX_REMAP_ITERATIONS: usize = 1000;
        while typeahead.len() > 0 {
            if i > MAX_REMAP_ITERATIONS {
                panic!("Infinite loop suspected.");
            }
            i += 1;

            let remap_result = self.remap_map.process(&mut typeahead);
            let op_result = self.op_map.process(&mut typeahead);

            match (remap_result, op_result) {
                (Match::PartialMatch, _) |
                (_, Match::PartialMatch) => {
                    break; // Ambiguous results.
                }
                (Match::FullMatch(mapped), _) => {
                    // Remapping takes precedence over op-mapping.
                    let len = min(mapped.0.len(), typeahead.len());
                    typeahead.drain(..len);
                    for k in mapped.1.iter() {
                        typeahead.push_front(*k);
                    }
                }
                (Match::NoMatch, Match::FullMatch(mapped)) => {
                    // If no remapping, try op-mapping.
                    let len = min(mapped.0.len(), typeahead.len());
                    typeahead.drain(..len);
                    return Some(mapped.1);
                }
                (Match::NoMatch, Match::NoMatch) => {
                    break; // No matches found.
                }
            }
        }
        return None;
    }

    /// Insert a mapping from `key` to `value` in the operations map.
    /// Empty `key`s are not allowed.
    pub fn insert_op(&mut self, key: Vec<K>, value: Op) -> InsertionResult {
        // Disallow empty keys, as they would full-match against an empty
        // typeahead buffer.
        if key.is_empty() {
            return InsertionResult::InvalidKey;
        }
        return self.op_map.insert((key, value));
    }

    /// Insert a mapping from `key` to `value` in the remap map.
    /// Empty `key`s are not allowed.
    /// Pairs such that `key` and `value` are equal are not allowed.
    pub fn insert_remap(
        &mut self,
        key: Vec<K>,
        value: Vec<K>,
    ) -> InsertionResult {
        // Disallow empty keys, as they would full-match against an empty
        // typeahead buffer.
        if key.is_empty() || key == value {
            return InsertionResult::InvalidKey;
        }
        return self.remap_map.insert((key, value));
    }
}

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

    #[derive(Copy, Clone, Debug, PartialEq)]
    enum TestOp {
        ThingOne,
        ThingTwo,
    }

    #[test]
    fn insert_overwrite() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );
        assert_eq!(
            InsertionResult::Overwrite,
            mode_map.insert_op(vec![1u8], TestOp::ThingTwo)
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8], vec![2u8])
        );
        assert_eq!(
            InsertionResult::Overwrite,
            mode_map.insert_remap(vec![1u8], vec![3u8])
        );
    }

    #[test]
    fn insert_empty_key() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::InvalidKey,
            mode_map.insert_op(Vec::<u8>::new(), TestOp::ThingOne)
        );
        assert_eq!(
            InsertionResult::InvalidKey,
            mode_map.insert_remap(Vec::<u8>::new(), vec![1u8])
        );
    }

    #[test]
    fn insert_key_value_parity() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::InvalidKey,
            mode_map.insert_remap(vec![1u8], vec![1u8])
        );
    }

    #[test]
    fn process_one_op() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);

        assert_eq!(Some(TestOp::ThingOne), mode_map.process(&mut typeahead));
        assert!(typeahead.is_empty());
    }

    #[test]
    fn process_two_ops() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![2u8], TestOp::ThingTwo)
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(2u8);

        assert_eq!(Some(TestOp::ThingTwo), mode_map.process(&mut typeahead));
        assert!(typeahead.is_empty());
    }

    #[test]
    fn process_overspecified_full_match() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);
        typeahead.push_back(1u8);
        assert_eq!(Some(TestOp::ThingOne), mode_map.process(&mut typeahead));
    }

    #[test]
    fn process_put_back_leftovers() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);
        typeahead.push_back(1u8);

        assert_eq!(Some(TestOp::ThingOne), mode_map.process(&mut typeahead));
        assert_eq!(Some(1u8), typeahead.pop_front());
        assert_eq!(None, typeahead.pop_front());
    }

    #[test]
    fn process_remap() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8], vec![2u8])
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);
        typeahead.push_back(1u8);

        assert_eq!(None, mode_map.process(&mut typeahead));
        assert_eq!(Some(2u8), typeahead.pop_front());
        assert_eq!(Some(1u8), typeahead.pop_front());
        assert_eq!(None, typeahead.pop_front());
    }

    #[test]
    fn process_overspecified_remap() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8, 1u8, 1u8], vec![2u8])
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);
        typeahead.push_back(1u8);

        assert_eq!(None, mode_map.process(&mut typeahead));
        assert_eq!(Some(1u8), typeahead.pop_front());
        assert_eq!(Some(1u8), typeahead.pop_front());
        assert_eq!(None, typeahead.pop_front());
    }

    #[test]
    fn process_shadow_op_with_remap() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8], vec![2u8])
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![2u8], TestOp::ThingTwo)
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);
        typeahead.push_back(1u8);

        assert_eq!(Some(TestOp::ThingTwo), mode_map.process(&mut typeahead));
        assert_eq!(Some(1u8), typeahead.pop_front());
        assert_eq!(None, typeahead.pop_front());
    }

    #[test]
    fn process_remap_then_op() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8, 1u8], vec![2u8])
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![2u8], TestOp::ThingTwo)
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);
        typeahead.push_back(1u8);

        assert_eq!(Some(TestOp::ThingTwo), mode_map.process(&mut typeahead));
        assert_eq!(None, typeahead.pop_front());
    }

    #[test]
    fn process_op_remap_ambiguate() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8, 1u8], vec![2u8])
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8, 1u8, 1u8], TestOp::ThingOne)
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);
        typeahead.push_back(1u8);

        // In this test, we expect the remap not to take place since we haven't
        // yet disambiguated it from the op.
        assert_eq!(None, mode_map.process(&mut typeahead));
        assert_eq!(Some(1u8), typeahead.pop_front());
        assert_eq!(Some(1u8), typeahead.pop_front());
        assert_eq!(None, typeahead.pop_front());
    }

    #[test]
    fn process_ambiguous_sequence() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8, 1u8], vec![2u8])
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );

        let mut typeahead = VecDeque::<u8>::new();

        // Ambiguous sequence.
        typeahead.push_back(1u8);
        assert_eq!(None, mode_map.process(&mut typeahead));
        assert_eq!(1, typeahead.len());
    }

    #[test]
    fn process_disambiguated_remap() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8, 1u8], vec![2u8])
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );

        let mut typeahead = VecDeque::<u8>::new();

        // Disambiguate for remap.
        typeahead.push_back(1u8);
        typeahead.push_back(1u8);
        assert_eq!(None, mode_map.process(&mut typeahead));
        assert_eq!(Some(2u8), typeahead.pop_front());
        assert_eq!(0, typeahead.len());
    }

    #[test]
    fn process_disambiguated_op() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8, 1u8], vec![2u8])
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );

        let mut typeahead = VecDeque::<u8>::new();

        // Disambiguated sequence for op.
        typeahead.push_back(1u8); // Processing just this will result in None.
        typeahead.push_back(2u8); // This one disambiguates, so the op can map.
        assert_eq!(Some(TestOp::ThingOne), mode_map.process(&mut typeahead));
        assert_eq!(Some(2u8), typeahead.pop_front());
        assert_eq!(None, typeahead.pop_front());
    }

    // Test that infinite recursion eventuates in a panic.
    // TODO Instead of panic, consider returning a special InfRecursion op
    // so we can tell the user.
    #[test]
    #[should_panic]
    fn process_inf_recursion() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8], vec![2u8])
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![2u8], vec![1u8])
        );
        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);
        mode_map.process(&mut typeahead);
    }
}
<commit_msg>fix push front order<commit_after>use std::collections::VecDeque;
use ordered_vec_map::InsertionResult;
use disambiguation_map::{DisambiguationMap, Match};
use termion::event::{Key, parse_event};
use op::{NormalOp, InsertOp};
use std::cmp::{min, max};
use std::cmp::Ordering;

/// By convention:
/// * K is a map's key type, implementing `Copy` and `Ord`.
/// * T is an arbitrary type, typically stored as a value in a map.
/// * Op is an arbitrary operation type (typically a mode-specific enum).

pub struct ModeMap<K, Op>
where
    K: Ord,
    K: Copy,
    Op: Copy,
{
    remap_map: DisambiguationMap<K, Vec<K>>,
    op_map: DisambiguationMap<K, Op>,
}

impl<K, Op> ModeMap<K, Op>
where
    K: Ord,
    K: Copy,
    Op: Copy,
{
    pub fn new() -> Self {
        ModeMap {
            remap_map: DisambiguationMap::new(),
            op_map: DisambiguationMap::new(),
        }
    }

    /// Process a typeahead buffer.
    pub fn process(&self, mut typeahead: &mut VecDeque<K>) -> Option<Op> {
        // Grab keys from the front of the queue, looking for matches.
        let mut i: usize = 0;
        const MAX_REMAP_ITERATIONS: usize = 1000;
        while typeahead.len() > 0 {
            if i > MAX_REMAP_ITERATIONS {
                panic!("Infinite loop suspected.");
            }
            i += 1;

            let remap_result = self.remap_map.process(&mut typeahead);
            let op_result = self.op_map.process(&mut typeahead);

            match (remap_result, op_result) {
                (Match::PartialMatch, _) |
                (_, Match::PartialMatch) => {
                    break; // Ambiguous results.
                }
                (Match::FullMatch(mapped), _) => {
                    // Remapping takes precedence over op-mapping.
                    let len = min(mapped.0.len(), typeahead.len());
                    typeahead.drain(..len);
                    for k in mapped.1.iter().rev() {
                        typeahead.push_front(*k);
                    }
                }
                (Match::NoMatch, Match::FullMatch(mapped)) => {
                    // If no remapping, try op-mapping.
                    let len = min(mapped.0.len(), typeahead.len());
                    typeahead.drain(..len);
                    return Some(mapped.1);
                }
                (Match::NoMatch, Match::NoMatch) => {
                    break; // No matches found.
                }
            }
        }
        return None;
    }

    /// Insert a mapping from `key` to `value` in the operations map.
    /// Empty `key`s are not allowed.
    pub fn insert_op(&mut self, key: Vec<K>, value: Op) -> InsertionResult {
        if key.is_empty() {
            InsertionResult::InvalidKey
        } else {
            self.op_map.insert((key, value))
        }
    }

    /// Insert a mapping from `key` to `value` in the remap map.
    /// Empty `key`s are not allowed and `key` must not equal `value`.
    pub fn insert_remap(
        &mut self,
        key: Vec<K>,
        value: Vec<K>,
    ) -> InsertionResult {
        if key.is_empty() || key == value {
            InsertionResult::InvalidKey
        } else {
            self.remap_map.insert((key, value))
        }
    }
}

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

    #[derive(Copy, Clone, Debug, PartialEq)]
    enum TestOp {
        ThingOne,
        ThingTwo,
    }

    #[test]
    fn insert_overwrite() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );
        assert_eq!(
            InsertionResult::Overwrite,
            mode_map.insert_op(vec![1u8], TestOp::ThingTwo)
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8], vec![2u8])
        );
        assert_eq!(
            InsertionResult::Overwrite,
            mode_map.insert_remap(vec![1u8], vec![3u8])
        );
    }

    #[test]
    fn insert_empty_key() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::InvalidKey,
            mode_map.insert_op(Vec::<u8>::new(), TestOp::ThingOne)
        );
        assert_eq!(
            InsertionResult::InvalidKey,
            mode_map.insert_remap(Vec::<u8>::new(), vec![1u8])
        );
    }

    #[test]
    fn insert_key_value_parity() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::InvalidKey,
            mode_map.insert_remap(vec![1u8], vec![1u8])
        );
    }

    #[test]
    fn process_one_op() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);

        assert_eq!(Some(TestOp::ThingOne), mode_map.process(&mut typeahead));
        assert!(typeahead.is_empty());
    }

    #[test]
    fn process_two_ops() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![2u8], TestOp::ThingTwo)
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(2u8);

        assert_eq!(Some(TestOp::ThingTwo), mode_map.process(&mut typeahead));
        assert!(typeahead.is_empty());
    }

    #[test]
    fn process_overspecified_full_match() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);
        typeahead.push_back(1u8);
        assert_eq!(Some(TestOp::ThingOne), mode_map.process(&mut typeahead));
    }

    #[test]
    fn process_put_back_leftovers() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);
        typeahead.push_back(1u8);

        assert_eq!(Some(TestOp::ThingOne), mode_map.process(&mut typeahead));
        assert_eq!(Some(1u8), typeahead.pop_front());
        assert_eq!(None, typeahead.pop_front());
    }

    #[test]
    fn process_remap() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8], vec![2u8])
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);
        typeahead.push_back(1u8);

        assert_eq!(None, mode_map.process(&mut typeahead));
        assert_eq!(Some(2u8), typeahead.pop_front());
        assert_eq!(Some(1u8), typeahead.pop_front());
        assert_eq!(None, typeahead.pop_front());
    }

    #[test]
    fn process_overspecified_remap() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8, 1u8, 1u8], vec![2u8])
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);
        typeahead.push_back(1u8);

        assert_eq!(None, mode_map.process(&mut typeahead));
        assert_eq!(Some(1u8), typeahead.pop_front());
        assert_eq!(Some(1u8), typeahead.pop_front());
        assert_eq!(None, typeahead.pop_front());
    }

    #[test]
    fn process_shadow_op_with_remap() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8], vec![2u8])
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![2u8], TestOp::ThingTwo)
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);
        typeahead.push_back(1u8);

        assert_eq!(Some(TestOp::ThingTwo), mode_map.process(&mut typeahead));
        assert_eq!(Some(1u8), typeahead.pop_front());
        assert_eq!(None, typeahead.pop_front());
    }

    #[test]
    fn process_remap_then_op() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8, 1u8], vec![2u8])
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![2u8], TestOp::ThingTwo)
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);
        typeahead.push_back(1u8);

        assert_eq!(Some(TestOp::ThingTwo), mode_map.process(&mut typeahead));
        assert_eq!(None, typeahead.pop_front());
    }

    #[test]
    fn process_op_remap_ambiguate() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8, 1u8], vec![2u8])
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8, 1u8, 1u8], TestOp::ThingOne)
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);
        typeahead.push_back(1u8);

        // In this test, we expect the remap not to take place since we haven't
        // yet disambiguated it from the op.
        assert_eq!(None, mode_map.process(&mut typeahead));
        assert_eq!(Some(1u8), typeahead.pop_front());
        assert_eq!(Some(1u8), typeahead.pop_front());
        assert_eq!(None, typeahead.pop_front());
    }

    #[test]
    fn process_ambiguous_sequence() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8, 1u8], vec![2u8])
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );

        let mut typeahead = VecDeque::<u8>::new();

        // Ambiguous sequence.
        typeahead.push_back(1u8);
        assert_eq!(None, mode_map.process(&mut typeahead));
        assert_eq!(1, typeahead.len());
    }

    #[test]
    fn process_disambiguated_remap() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8, 1u8], vec![2u8])
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );

        let mut typeahead = VecDeque::<u8>::new();

        // Disambiguate for remap.
        typeahead.push_back(1u8);
        typeahead.push_back(1u8);
        assert_eq!(None, mode_map.process(&mut typeahead));
        assert_eq!(Some(2u8), typeahead.pop_front());
        assert_eq!(0, typeahead.len());
    }

    #[test]
    fn process_disambiguated_op() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8, 1u8], vec![2u8])
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_op(vec![1u8], TestOp::ThingOne)
        );

        let mut typeahead = VecDeque::<u8>::new();

        // Disambiguated sequence for op.
        typeahead.push_back(1u8); // Processing just this will result in None.
        typeahead.push_back(2u8); // This one disambiguates, so the op can map.
        assert_eq!(Some(TestOp::ThingOne), mode_map.process(&mut typeahead));
        assert_eq!(Some(2u8), typeahead.pop_front());
        assert_eq!(None, typeahead.pop_front());
    }

    #[test]
    fn process_push_front_reversed() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8, 2u8], vec![3u8, 4u8])
        );

        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);
        typeahead.push_back(2u8);
        assert_eq!(None, mode_map.process(&mut typeahead));
        assert_eq!(Some(3u8), typeahead.pop_front());
        assert_eq!(Some(4u8), typeahead.pop_front());
        assert_eq!(None, typeahead.pop_front());
    }

    // Test that infinite recursion eventuates in a panic.
    // TODO Instead of panic, consider returning a special InfRecursion op
    // so we can tell the user.
    #[test]
    #[should_panic]
    fn process_inf_recursion() {
        let mut mode_map = ModeMap::<u8, TestOp>::new();
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![1u8], vec![2u8])
        );
        assert_eq!(
            InsertionResult::Create,
            mode_map.insert_remap(vec![2u8], vec![1u8])
        );
        let mut typeahead = VecDeque::<u8>::new();
        typeahead.push_back(1u8);
        mode_map.process(&mut typeahead);
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use std::collections::HashSet;
use std::path::Path;
use std::path::PathBuf;

use common::PerfLogEvent;
use common::PerfLogger;
use log::debug;
use relay_typegen::TypegenLanguage;
use walkdir::WalkDir;

use super::File;
use crate::compiler_state::CompilerState;
use crate::config::Config;
use crate::errors::Result;
use crate::FileSourceResult;

#[derive(Debug)]
pub struct WalkDirFileSourceResult {
    pub files: Vec<File>,
    pub resolved_root: PathBuf,
}

pub struct WalkDirFileSource<'config> {
    pub config: &'config Config,
    expected_file_extensions: HashSet<&'config str>,
}

fn get_expected_file_extensions(config: &Config) -> HashSet<&str> {
    let mut file_extensions = HashSet::<&str>::with_capacity(5);
    file_extensions.insert("graphql");
    file_extensions.insert("gql");

    for project in config.enabled_projects() {
        match project.typegen_config.language {
            TypegenLanguage::Flow | TypegenLanguage::JavaScript => {
                file_extensions.insert("js");
                file_extensions.insert("jsx");
            }
            TypegenLanguage::TypeScript => {
                file_extensions.insert("js");
                file_extensions.insert("jsx");
                file_extensions.insert("ts");
                file_extensions.insert("tsx");
            }
        }
    }
    file_extensions
}

impl<'config> WalkDirFileSource<'config> {
    pub fn new(config: &'config Config) -> Self {
        debug!(
            "Watchman server is disabled, or not available. Using GlobFileSource to find files."
        );
        Self {
            config,
            expected_file_extensions: get_expected_file_extensions(config),
        }
    }

    fn should_include_file(&self, name: &Path) -> bool {
        matches!(
            name.extension().map(|extension| self
                .expected_file_extensions
                .contains(extension.to_str().unwrap())),
            Some(true)
        )
    }

    fn find_files(&self) -> Vec<File> {
        WalkDir::new(self.config.root_dir.clone())
            .into_iter()
            .filter_map(|entry| {
                let dir_entry = entry.ok()?;
                let relative_path = dir_entry
                    .path()
                    .strip_prefix(self.config.root_dir.clone())
                    .ok()?
                    .to_path_buf();

                self.should_include_file(&relative_path).then(|| File {
                    name: relative_path,
                    exists: true,
                })
            })
            .collect::<Vec<_>>()
    }

    pub fn create_compiler_state(&self, perf_logger: &impl PerfLogger) -> Result<CompilerState> {
        let setup_event = perf_logger.create_event("Glob_file_source_create_compiler_state");
        let timer = setup_event.start("create_compiler_state_file_files");
        let file_source_changes = FileSourceResult::WalkDir(WalkDirFileSourceResult {
            files: self.find_files(),
            resolved_root: self.config.root_dir.clone(),
        });
        setup_event.stop(timer);
        let compiler_state = CompilerState::from_file_source_changes(
            self.config,
            &file_source_changes,
            &setup_event,
            perf_logger,
        )?;

        setup_event.complete();

        Ok(compiler_state)
    }
}
<commit_msg>Pre-allocate a HashSet with capacity of 6 instead of 5<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use std::collections::HashSet;
use std::path::Path;
use std::path::PathBuf;

use common::PerfLogEvent;
use common::PerfLogger;
use log::debug;
use relay_typegen::TypegenLanguage;
use walkdir::WalkDir;

use super::File;
use crate::compiler_state::CompilerState;
use crate::config::Config;
use crate::errors::Result;
use crate::FileSourceResult;

#[derive(Debug)]
pub struct WalkDirFileSourceResult {
    pub files: Vec<File>,
    pub resolved_root: PathBuf,
}

pub struct WalkDirFileSource<'config> {
    pub config: &'config Config,
    expected_file_extensions: HashSet<&'config str>,
}

fn get_expected_file_extensions(config: &Config) -> HashSet<&str> {
    let mut file_extensions = HashSet::<&str>::with_capacity(6);
    file_extensions.insert("graphql");
    file_extensions.insert("gql");

    for project in config.enabled_projects() {
        match project.typegen_config.language {
            TypegenLanguage::Flow | TypegenLanguage::JavaScript => {
                file_extensions.insert("js");
                file_extensions.insert("jsx");
            }
            TypegenLanguage::TypeScript => {
                file_extensions.insert("js");
                file_extensions.insert("jsx");
                file_extensions.insert("ts");
                file_extensions.insert("tsx");
            }
        }
    }
    file_extensions
}

impl<'config> WalkDirFileSource<'config> {
    pub fn new(config: &'config Config) -> Self {
        debug!(
            "Watchman server is disabled, or not available. Using GlobFileSource to find files."
        );
        Self {
            config,
            expected_file_extensions: get_expected_file_extensions(config),
        }
    }

    fn should_include_file(&self, name: &Path) -> bool {
        matches!(
            name.extension().map(|extension| self
                .expected_file_extensions
                .contains(extension.to_str().unwrap())),
            Some(true)
        )
    }

    fn find_files(&self) -> Vec<File> {
        WalkDir::new(self.config.root_dir.clone())
            .into_iter()
            .filter_map(|entry| {
                let dir_entry = entry.ok()?;
                let relative_path = dir_entry
                    .path()
                    .strip_prefix(self.config.root_dir.clone())
                    .ok()?
                    .to_path_buf();

                self.should_include_file(&relative_path).then(|| File {
                    name: relative_path,
                    exists: true,
                })
            })
            .collect::<Vec<_>>()
    }

    pub fn create_compiler_state(&self, perf_logger: &impl PerfLogger) -> Result<CompilerState> {
        let setup_event = perf_logger.create_event("Glob_file_source_create_compiler_state");
        let timer = setup_event.start("create_compiler_state_file_files");
        let file_source_changes = FileSourceResult::WalkDir(WalkDirFileSourceResult {
            files: self.find_files(),
            resolved_root: self.config.root_dir.clone(),
        });
        setup_event.stop(timer);
        let compiler_state = CompilerState::from_file_source_changes(
            self.config,
            &file_source_changes,
            &setup_event,
            perf_logger,
        )?;

        setup_event.complete();

        Ok(compiler_state)
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use serialize::json;
use serialize::json::{ToJson};

// masks for pulling nibbles out of bytes
const BYTE_WIDTH: uint = 8;
const U4_LOW:     u8   = 0b00001111;
const U4_HIGH:    u8   = 0b11110000;

/// If the CPU enters the `Halt` state then any additional ticks will result in
/// the program exhibiting undefined behavior.
///
#[deriving(PartialEq,Show)]
pub enum CpuState {
	Continue,
	Halt,
}

/// The P150 virtual machine
/// Represents all information the CPU needs to continue executing a
/// program stored in its main memory.
pub struct P150Cpu {
	ip:  u8,
	ir: u16,

	reg: [u8, ..16],
	mem: [u8, ..256],
}

impl P150Cpu {
	/// Initializes the P150 CPU
	///
	/// NOTE: This implementation 0s memory; but this is not guaranteed
	/// by the machine specification.
	///
	/// Programs MUST start at memory address 0x00
	pub fn new() -> P150Cpu {
		P150Cpu {
			ip:  0x00,
			ir:  0x0000,

			reg: [0u8, ..16],
			mem: [0u8, ..256],
		}
	}

	pub fn js_dump(&self) -> json::Json {
		let mut dict = HashMap::new();

		dict.insert(format!("ip"), self.ip.to_json());
		dict.insert(format!("ir"), self.ir.to_json());
		dict.insert(format!("reg"), self.reg.to_json());
		dict.insert(format!("mem"), self.mem.to_json());

		return dict.to_json();
	}

	/// Prints the current machine state to the console window
	/// This includes the IP, IR, and all registers.
	/// (Registers will be formatted as 2s complement numbers.)
	pub fn dump(&self) {
		println!("IP: 0x{:02X}, IR: 0x{:04X}", self.ip, self.ir);

		println!("---\nRegisters\n---")
		for (addr, cell) in self.reg.iter().enumerate() {
			println!("{:01X}: {}", addr, cell)
		}

		println!("---")

		debug!("Memory")
		for (addr, cell) in self.mem.iter().enumerate() {
			debug!("{:02X}: {}", addr, cell)
		}
	}

	#[cfg(test)]
	fn get_reg(&self) -> &[u8] { self.reg }

	/// Read an array of instructions into main memory
	/// This reads two bytes at a time from the `memory` array
	/// and loads them into the P150s RAM bank, starting from address 0.
	pub fn init_mem(&mut self, memory: &[u16]) {
		assert!(memory.len() < (256 / 2)); // program cannot be larger than memory
		let mut next_cell = 0x00;

		// zero memory
		self.mem = [0, ..256];
		for op in memory.iter() {
			let byte_1 = (*op >> 8) as u8;
			let byte_2 = *op as u8;

			self.mem[next_cell]     = byte_1;
			self.mem[next_cell + 1] = byte_2;
			next_cell += 2
		}
	}

	/// Runs the entire fetch, execute, decode cycle against the current IP
	pub fn tick(&mut self) -> CpuState {
		self.fetch();

		// decode & execute
		let op = (self.ir >> 12) as u8;
		match op {
			0x0   => { // MLOAD
				let rloc_o0 = lo_nibble((self.ir >> 8) as u8);
				let mloc_i0 = self.ir as u8;

				self.reg[rloc_o0 as uint] = self.mem[mloc_i0 as uint];
				Continue
			},

			0x1   => { // RSET
				let rloc = lo_nibble((self.ir >> 8) as u8);  // lower nibble of first byte
				let rval = self.ir as u8;                    // value is entire second byte

				self.reg[rloc as uint] = rval;               // store value in register
				Continue
			},

			0x2   => { // MSTOR
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let mloc_o0 = self.ir as u8;

				self.mem[mloc_o0 as uint] = self.reg[rloc_i0 as uint];
				Continue
			},

			0x3   => { // RMOV
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let rloc_o0 = hi_nibble(self.ir as u8);

				debug!("moving from {:02X} to {:02X}", rloc_i0, rloc_o0)
				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint];
				Continue
			},

			0x4   => { // ADDB
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);   // first input: lower nibble of first byte
				let rloc_i1 = hi_nibble(self.ir as u8);          // second input: upper nibble of second byte
				let rloc_o0 = lo_nibble(self.ir as u8);          // output: lower nibble of second byte

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] + self.reg[rloc_i1 as uint];
				Continue
			},

			0x6   => { // OR
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let rloc_i1 = hi_nibble(self.ir as u8);
				let rloc_o0 = lo_nibble(self.ir as u8);

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] | self.reg[rloc_i1 as uint];
				Continue
			},

			0x7   => { // AND
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let rloc_i1 = hi_nibble(self.ir as u8);
				let rloc_o0 = lo_nibble(self.ir as u8);

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] & self.reg[rloc_i1 as uint];
				Continue
			},

			0x8   => { // XOR
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let rloc_i1 = hi_nibble(self.ir as u8);
				let rloc_o0 = lo_nibble(self.ir as u8);

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] ^ self.reg[rloc_i1 as uint];
				Continue
			},

			0x9   => { // ROT
				// LHS shifts <width> bits off the (left) end of the bitstring
				// RHS shifts the bitstring to the right until only the bits which fell off remain.
				//   LHS is the remaining MSB bits; RHS is the remaining LSB bits
				//   ∴ LHS <OR> RHS provides a rotated bitstring
				//
				let rloc_i0   = lo_nibble((self.ir >> 8) as u8) as uint;          // register is first nibble ...
				let swidth    = (hi_nibble(self.ir as u8) & 0b0000_0111) as uint; // last three bytes of second nibble ...
				self.reg[rloc_i0 as uint] = (self.reg[rloc_i0] << swidth) | (self.reg[rloc_i0] >> (BYTE_WIDTH - swidth));

				Continue
			},

			0xA   => { // JMPEQ
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let next_ip = self.ir as u8;

				if self.reg[rloc_i0 as uint] == self.reg[0] { self.ip = next_ip }
				Continue
			},

			0xB   => { Halt },
			_     => { debug!("halt, cpu on fire: {}", op); Halt },
		}
	}

	/// Load the instruction at `IP` and advance the pointer by two bytes.
	/// The instruction is packed into a single `u16` and stored in the instruction register.
	fn fetch(&mut self) {
		// fetch two bytes from PC
		let byte_1 = self.mem[(self.ip+0) as uint];
		let byte_2 = self.mem[(self.ip+1) as uint];

		self.ir  = (byte_1 as u16 << 8) | (byte_2 as u16); // load byets into IR
		self.ip += 2;                                      // increment instruction pointer

		debug!("IR set to 0x{:04X} ({:02X},{:02X})", self.ir, byte_1, byte_2)
	}
}

/// Take the lower nibble of a byte
fn lo_nibble(byte: u8) -> u8 {
	(byte & U4_LOW)
}

/// Take the upper nibble of a byte and shift it
/// towards the least significant bits.
fn hi_nibble(byte: u8) -> u8 {
	(byte & U4_HIGH) >> 4
}

#[test]
fn test_hammer_time() {
	// cpu should stop after 1 tick of this program
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0xB000]);

	assert_eq!(cpu.tick(), Halt)
}

#[test]
fn test_registers() {
	// cpu should set, move registers accordingly
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1110, 0x3130, 0xB000]);
	boot(&mut cpu);

	assert_eq!(cpu.get_reg()[0x3], 16)
}

#[test]
fn test_memory() {
	// memory sets and memory stores should read back successfully
	// uninitialized registers should not match initialized registers
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1120, 0x1330, 0x2140, 0x0240, 0xB000]);
	boot(&mut cpu);

	assert!(cpu.get_reg()[0x1] == cpu.get_reg()[0x2]);
	assert!(cpu.get_reg()[0x1] != cpu.get_reg()[0x3]);
}

#[test]
fn test_bin() {
	// tests the various binary operations against their rustc counterparts.
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1121, 0x1222, 0x6123, 0x7124, 0x8125, 0xB000]);
	boot(&mut cpu);

	assert!(cpu.get_reg()[0x3] == (0x21 | 0x22));
	assert!(cpu.get_reg()[0x4] == (0x21 & 0x22));
	assert!(cpu.get_reg()[0x5] == (0x21 ^ 0x22));
}

#[test]
fn test_math() {
	// tests basic 2s comp. addition
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1120, 0x120A, 0x4123, 0xB000]);
	boot(&mut cpu);

	assert_eq!(cpu.get_reg()[0x3], cpu.get_reg()[0x1] + cpu.get_reg()[0x2]);
	assert_eq!(cpu.get_reg()[0x3], 0x20 + 0x0A);
}

#[test]
fn test_branch() {
	// checks that the program branches; skipping a halt and setting a status register
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1021, 0x1121, 0xA108, 0xB000, 0x122A, 0xB000]);
	boot(&mut cpu);

	assert_eq!(cpu.get_reg()[0x2], 0x2A)
}

#[test]
fn test_shift() {
	// checks that the program rotates a single nibble 4 places
	// this should move a single hex digit from the lhs to the rhs.
	//
	// NOTE: shifting 12 bits (12 - 8) and 4 bits should be equivalent.
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x10B0, 0x11B0, 0x90C0, 0x9140, 0xB000]);
	boot(&mut cpu);

	assert_eq!(cpu.get_reg()[0x0], 0x0B);
	assert_eq!(cpu.get_reg()[0x1], 0x0B);
}

#[cfg(test)]
fn boot(cpu: &mut P150Cpu) {
	loop {
		if cpu.tick() == Halt { break; }
	}
}

<commit_msg>ADDB should consider each operand as a signed (2s comp, 8-bit) integer.<commit_after>use std::collections::HashMap;
use serialize::json;
use serialize::json::{ToJson};

// masks for pulling nibbles out of bytes
const BYTE_WIDTH: uint = 8;
const U4_LOW:     u8   = 0b00001111;
const U4_HIGH:    u8   = 0b11110000;

/// If the CPU enters the `Halt` state then any additional ticks will result in
/// the program exhibiting undefined behavior.
///
#[deriving(PartialEq,Show)]
pub enum CpuState {
	Continue,
	Halt,
}

/// The P150 virtual machine
/// Represents all information the CPU needs to continue executing a
/// program stored in its main memory.
pub struct P150Cpu {
	ip:  u8,
	ir: u16,

	reg: [u8, ..16],
	mem: [u8, ..256],
}

impl P150Cpu {
	/// Initializes the P150 CPU
	///
	/// NOTE: This implementation 0s memory; but this is not guaranteed
	/// by the machine specification.
	///
	/// Programs MUST start at memory address 0x00
	pub fn new() -> P150Cpu {
		P150Cpu {
			ip:  0x00,
			ir:  0x0000,

			reg: [0u8, ..16],
			mem: [0u8, ..256],
		}
	}

	pub fn js_dump(&self) -> json::Json {
		let mut dict = HashMap::new();

		dict.insert(format!("ip"), self.ip.to_json());
		dict.insert(format!("ir"), self.ir.to_json());
		dict.insert(format!("reg"), self.reg.to_json());
		dict.insert(format!("mem"), self.mem.to_json());

		return dict.to_json();
	}

	/// Prints the current machine state to the console window
	/// This includes the IP, IR, and all registers.
	/// (Registers will be formatted as 2s complement numbers.)
	pub fn dump(&self) {
		println!("IP: 0x{:02X}, IR: 0x{:04X}", self.ip, self.ir);

		println!("---\nRegisters\n---")
		for (addr, cell) in self.reg.iter().enumerate() {
			println!("{:01X}: {}", addr, cell)
		}

		println!("---")

		debug!("Memory")
		for (addr, cell) in self.mem.iter().enumerate() {
			debug!("{:02X}: {}", addr, cell)
		}
	}

	#[cfg(test)]
	fn get_reg(&self) -> &[u8] { self.reg }

	/// Read an array of instructions into main memory
	/// This reads two bytes at a time from the `memory` array
	/// and loads them into the P150s RAM bank, starting from address 0.
	pub fn init_mem(&mut self, memory: &[u16]) {
		assert!(memory.len() < (256 / 2)); // program cannot be larger than memory
		let mut next_cell = 0x00;

		// zero memory
		self.mem = [0, ..256];
		for op in memory.iter() {
			let byte_1 = (*op >> 8) as u8;
			let byte_2 = *op as u8;

			self.mem[next_cell]     = byte_1;
			self.mem[next_cell + 1] = byte_2;
			next_cell += 2
		}
	}

	/// Runs the entire fetch, execute, decode cycle against the current IP
	pub fn tick(&mut self) -> CpuState {
		self.fetch();

		// decode & execute
		let op = (self.ir >> 12) as u8;
		match op {
			0x0   => { // MLOAD
				let rloc_o0 = lo_nibble((self.ir >> 8) as u8);
				let mloc_i0 = self.ir as u8;

				self.reg[rloc_o0 as uint] = self.mem[mloc_i0 as uint];
				Continue
			},

			0x1   => { // RSET
				let rloc = lo_nibble((self.ir >> 8) as u8);  // lower nibble of first byte
				let rval = self.ir as u8;                    // value is entire second byte

				self.reg[rloc as uint] = rval;               // store value in register
				Continue
			},

			0x2   => { // MSTOR
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let mloc_o0 = self.ir as u8;

				self.mem[mloc_o0 as uint] = self.reg[rloc_i0 as uint];
				Continue
			},

			0x3   => { // RMOV
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let rloc_o0 = hi_nibble(self.ir as u8);

				debug!("moving from {:02X} to {:02X}", rloc_i0, rloc_o0)
				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint];
				Continue
			},

			0x4   => { // ADDB
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);   // first input: lower nibble of first byte
				let rloc_i1 = hi_nibble(self.ir as u8);          // second input: upper nibble of second byte
				let rloc_o0 = lo_nibble(self.ir as u8);          // output: lower nibble of second byte

				self.reg[rloc_o0 as uint] =
					((self.reg[rloc_i0 as uint] as i8) + (self.reg[rloc_i1 as uint]as i8)) as u8;
				Continue
			},

			0x6   => { // OR
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let rloc_i1 = hi_nibble(self.ir as u8);
				let rloc_o0 = lo_nibble(self.ir as u8);

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] | self.reg[rloc_i1 as uint];
				Continue
			},

			0x7   => { // AND
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let rloc_i1 = hi_nibble(self.ir as u8);
				let rloc_o0 = lo_nibble(self.ir as u8);

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] & self.reg[rloc_i1 as uint];
				Continue
			},

			0x8   => { // XOR
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let rloc_i1 = hi_nibble(self.ir as u8);
				let rloc_o0 = lo_nibble(self.ir as u8);

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] ^ self.reg[rloc_i1 as uint];
				Continue
			},

			0x9   => { // ROT
				// LHS shifts <width> bits off the (left) end of the bitstring
				// RHS shifts the bitstring to the right until only the bits which fell off remain.
				//   LHS is the remaining MSB bits; RHS is the remaining LSB bits
				//   ∴ LHS <OR> RHS provides a rotated bitstring
				//
				let rloc_i0   = lo_nibble((self.ir >> 8) as u8) as uint;          // register is first nibble ...
				let swidth    = (hi_nibble(self.ir as u8) & 0b0000_0111) as uint; // last three bytes of second nibble ...
				self.reg[rloc_i0 as uint] = (self.reg[rloc_i0] << swidth) | (self.reg[rloc_i0] >> (BYTE_WIDTH - swidth));

				Continue
			},

			0xA   => { // JMPEQ
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let next_ip = self.ir as u8;

				if self.reg[rloc_i0 as uint] == self.reg[0] { self.ip = next_ip }
				Continue
			},

			0xB   => { Halt },
			_     => { debug!("halt, cpu on fire: {}", op); Halt },
		}
	}

	/// Load the instruction at `IP` and advance the pointer by two bytes.
	/// The instruction is packed into a single `u16` and stored in the instruction register.
	fn fetch(&mut self) {
		// fetch two bytes from PC
		let byte_1 = self.mem[(self.ip+0) as uint];
		let byte_2 = self.mem[(self.ip+1) as uint];

		self.ir  = (byte_1 as u16 << 8) | (byte_2 as u16); // load byets into IR
		self.ip += 2;                                      // increment instruction pointer

		debug!("IR set to 0x{:04X} ({:02X},{:02X})", self.ir, byte_1, byte_2)
	}
}

/// Take the lower nibble of a byte
fn lo_nibble(byte: u8) -> u8 {
	(byte & U4_LOW)
}

/// Take the upper nibble of a byte and shift it
/// towards the least significant bits.
fn hi_nibble(byte: u8) -> u8 {
	(byte & U4_HIGH) >> 4
}

#[test]
fn test_hammer_time() {
	// cpu should stop after 1 tick of this program
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0xB000]);

	assert_eq!(cpu.tick(), Halt)
}

#[test]
fn test_registers() {
	// cpu should set, move registers accordingly
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1110, 0x3130, 0xB000]);
	boot(&mut cpu);

	assert_eq!(cpu.get_reg()[0x3], 16)
}

#[test]
fn test_memory() {
	// memory sets and memory stores should read back successfully
	// uninitialized registers should not match initialized registers
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1120, 0x1330, 0x2140, 0x0240, 0xB000]);
	boot(&mut cpu);

	assert!(cpu.get_reg()[0x1] == cpu.get_reg()[0x2]);
	assert!(cpu.get_reg()[0x1] != cpu.get_reg()[0x3]);
}

#[test]
fn test_bin() {
	// tests the various binary operations against their rustc counterparts.
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1121, 0x1222, 0x6123, 0x7124, 0x8125, 0xB000]);
	boot(&mut cpu);

	assert!(cpu.get_reg()[0x3] == (0x21 | 0x22));
	assert!(cpu.get_reg()[0x4] == (0x21 & 0x22));
	assert!(cpu.get_reg()[0x5] == (0x21 ^ 0x22));
}

#[test]
fn test_math() {
	// tests basic 2s comp. addition
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1120, 0x120A, 0x4123, 0xB000]);
	boot(&mut cpu);

	assert_eq!(cpu.get_reg()[0x3], cpu.get_reg()[0x1] + cpu.get_reg()[0x2]);
	assert_eq!(cpu.get_reg()[0x3], 0x20 + 0x0A);
}

#[test]
fn test_branch() {
	// checks that the program branches; skipping a halt and setting a status register
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1021, 0x1121, 0xA108, 0xB000, 0x122A, 0xB000]);
	boot(&mut cpu);

	assert_eq!(cpu.get_reg()[0x2], 0x2A)
}

#[test]
fn test_shift() {
	// checks that the program rotates a single nibble 4 places
	// this should move a single hex digit from the lhs to the rhs.
	//
	// NOTE: shifting 12 bits (12 - 8) and 4 bits should be equivalent.
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x10B0, 0x11B0, 0x90C0, 0x9140, 0xB000]);
	boot(&mut cpu);

	assert_eq!(cpu.get_reg()[0x0], 0x0B);
	assert_eq!(cpu.get_reg()[0x1], 0x0B);
}

#[cfg(test)]
fn boot(cpu: &mut P150Cpu) {
	loop {
		if cpu.tick() == Halt { break; }
	}
}

<|endoftext|>


<commit_before>use std;

pub type Bits<T> = SubByteIter<BitParams, T>;
pub type Dibits<T> = SubByteIter<DibitParams, T>;

pub trait IterateParams {
    type IterType;

    fn bits() -> u8;
    fn wrap(x: u8) -> Self::IterType;

    fn shift() -> u8 { Self::bits() }
    fn iterations() -> u8 { 8 / Self::bits() }

    fn validate() {
        assert!(Self::bits().is_power_of_two());
    }
}

pub struct Bit(u8);

impl Bit {
    pub fn new(bits: u8) -> Bit {
        assert!(bits & 0b11111110 == 0);
        Bit(bits)
    }

    pub fn bits(&self) -> u8 { self.0 }
}

pub struct BitParams;

impl IterateParams for BitParams {
    type IterType = Bit;
    fn bits() -> u8 { 1 }
    fn wrap(x: u8) -> Bit { Bit::new(x) }
}

#[derive(Debug)]
pub struct Dibit(u8);

impl Dibit {
    pub fn new(bits: u8) -> Dibit {
        assert!(bits & 0b11111100 == 0);
        Dibit(bits)
    }

    pub fn bits(&self) -> u8 { self.0 }
}

pub struct DibitParams;

impl IterateParams for DibitParams {
    type IterType = Dibit;
    fn bits() -> u8 { 2 }
    fn wrap(x: u8) -> Dibit { Dibit::new(x) }
}

pub struct SubByteIter<P, T>
    where P: IterateParams, T: Iterator<Item = u8>
{
    params: std::marker::PhantomData<P>,
    /// The source of bits.
    src: T,
    /// The current index into the current byte.
    idx: u8,
    /// The current byte in the source.
    byte: u8,
}

impl<P, T> SubByteIter<P, T>
    where P: IterateParams, T: Iterator<Item = u8>
{
    /// Construct a new `SubByteIter<T>`.
    pub fn new(src: T) -> SubByteIter<P, T> {
        SubByteIter {
            params: std::marker::PhantomData,
            src: src,
            byte: 0,
            idx: 0,
        }
    }
}

impl<P, T> Iterator for SubByteIter<P, T>
    where P: IterateParams, T: Iterator<Item = u8>
{
    type Item = P::IterType;

    fn next(&mut self) -> Option<Self::Item> {
        if self.idx == 0 {
            self.byte = match self.src.next() {
                Some(b) => b,
                None => return None,
            };
        }

        // Store the current byte for later.
        let byte = self.byte;

        // Strip off the MSBs for the next iteration.
        self.byte <<= P::shift();

        // Move to the next item and reset after all have been visited.
        self.idx += 1;
        self.idx %= P::iterations();

        // Yield the MSBs.
        Some(P::wrap(byte >> (8 - P::shift())))
    }
}

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

    #[test]
    fn validate_params() {
        BitParams::validate();
        DibitParams::validate();
    }

    #[test]
    fn test_bits() {
        const BITS: &'static [u8] = &[
            0b00011011,
            0b11001100,
        ];

        {
            let mut d = Dibits::new(BITS.iter().cloned());

            assert!(d.next().unwrap().0 == 0b00);
            assert!(d.next().unwrap().0 == 0b01);
            assert!(d.next().unwrap().0 == 0b10);
            assert!(d.next().unwrap().0 == 0b11);
            assert!(d.next().unwrap().0 == 0b11);
            assert!(d.next().unwrap().0 == 0b00);
            assert!(d.next().unwrap().0 == 0b11);
            assert!(d.next().unwrap().0 == 0b00);
            assert!(d.next().is_none());
        }

        {
            let mut b = Bits::new(BITS.iter().cloned());

            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 0);
        }
    }
}
<commit_msg>Remove redundant shift() method<commit_after>use std;

pub type Bits<T> = SubByteIter<BitParams, T>;
pub type Dibits<T> = SubByteIter<DibitParams, T>;

pub trait IterateParams {
    type IterType;

    fn bits() -> u8;
    fn wrap(x: u8) -> Self::IterType;

    fn iterations() -> u8 { 8 / Self::bits() }

    fn validate() {
        assert!(Self::bits().is_power_of_two());
    }
}

pub struct Bit(u8);

impl Bit {
    pub fn new(bits: u8) -> Bit {
        assert!(bits & 0b11111110 == 0);
        Bit(bits)
    }

    pub fn bits(&self) -> u8 { self.0 }
}

pub struct BitParams;

impl IterateParams for BitParams {
    type IterType = Bit;
    fn bits() -> u8 { 1 }
    fn wrap(x: u8) -> Bit { Bit::new(x) }
}

#[derive(Debug)]
pub struct Dibit(u8);

impl Dibit {
    pub fn new(bits: u8) -> Dibit {
        assert!(bits & 0b11111100 == 0);
        Dibit(bits)
    }

    pub fn bits(&self) -> u8 { self.0 }
}

pub struct DibitParams;

impl IterateParams for DibitParams {
    type IterType = Dibit;
    fn bits() -> u8 { 2 }
    fn wrap(x: u8) -> Dibit { Dibit::new(x) }
}

pub struct SubByteIter<P, T>
    where P: IterateParams, T: Iterator<Item = u8>
{
    params: std::marker::PhantomData<P>,
    /// The source of bits.
    src: T,
    /// The current index into the current byte.
    idx: u8,
    /// The current byte in the source.
    byte: u8,
}

impl<P, T> SubByteIter<P, T>
    where P: IterateParams, T: Iterator<Item = u8>
{
    /// Construct a new `SubByteIter<T>`.
    pub fn new(src: T) -> SubByteIter<P, T> {
        SubByteIter {
            params: std::marker::PhantomData,
            src: src,
            byte: 0,
            idx: 0,
        }
    }
}

impl<P, T> Iterator for SubByteIter<P, T>
    where P: IterateParams, T: Iterator<Item = u8>
{
    type Item = P::IterType;

    fn next(&mut self) -> Option<Self::Item> {
        if self.idx == 0 {
            self.byte = match self.src.next() {
                Some(b) => b,
                None => return None,
            };
        }

        // Store the current byte for later.
        let byte = self.byte;

        // Strip off the MSBs for the next iteration.
        self.byte <<= P::bits();

        // Move to the next item and reset after all have been visited.
        self.idx += 1;
        self.idx %= P::iterations();

        // Yield the MSBs.
        Some(P::wrap(byte >> (8 - P::bits())))
    }
}

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

    #[test]
    fn validate_params() {
        BitParams::validate();
        DibitParams::validate();
    }

    #[test]
    fn test_bits() {
        const BITS: &'static [u8] = &[
            0b00011011,
            0b11001100,
        ];

        {
            let mut d = Dibits::new(BITS.iter().cloned());

            assert!(d.next().unwrap().0 == 0b00);
            assert!(d.next().unwrap().0 == 0b01);
            assert!(d.next().unwrap().0 == 0b10);
            assert!(d.next().unwrap().0 == 0b11);
            assert!(d.next().unwrap().0 == 0b11);
            assert!(d.next().unwrap().0 == 0b00);
            assert!(d.next().unwrap().0 == 0b11);
            assert!(d.next().unwrap().0 == 0b00);
            assert!(d.next().is_none());
        }

        {
            let mut b = Bits::new(BITS.iter().cloned());

            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 0);
        }
    }
}
<|endoftext|>


<commit_before>use crate::{Rect, Box2D, Box3D, Vector2D, Vector3D, size2, point2, point3};
use crate::approxord::{min, max};
use core::ops::Deref;
use core::ops::{Add, Sub};
use core::cmp::{PartialEq};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct NonEmpty<T>(pub(crate) T);

impl<T> Deref for NonEmpty<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.0
    }
}

impl<T> NonEmpty<T> {
    #[inline]
    pub fn get(&self) -> &T {
        &self.0
    }
}

impl<T, U> NonEmpty<Rect<T, U>>
where
    T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
{
    #[inline]
    pub fn union(&self, other: &NonEmpty<Rect<T, U>>) -> NonEmpty<Rect<T, U>> {
        let origin = point2(
            min(self.min_x(), other.min_x()),
            min(self.min_y(), other.min_y()),
        );

        let lower_right_x = max(self.max_x(), other.max_x());
        let lower_right_y = max(self.max_y(), other.max_y());

        NonEmpty(Rect {
            origin,
            size: size2(
                lower_right_x - origin.x,
                lower_right_y - origin.y,
            ),
        })
    }

    #[inline]
    pub fn contains_rect(&self, rect: &Self) -> bool {
        self.min_x() <= rect.min_x()
            && rect.max_x() <= self.max_x()
            && self.min_y() <= rect.min_y()
            && rect.max_y() <= self.max_y()
    }

    #[inline]
    pub fn translate(&self, by: Vector2D<T, U>) -> Self {
        NonEmpty(self.0.translate(by))
    }
}

impl<T, U> NonEmpty<Box2D<T, U>>
where
    T: Copy + PartialOrd,
{
    #[inline]
    pub fn union(&self, other: &NonEmpty<Box2D<T, U>>) -> NonEmpty<Box2D<T, U>> {
        NonEmpty(Box2D {
            min: point2(
                min(self.min.x, other.min.x),
                min(self.min.y, other.min.y),
            ),
            max: point2(
                max(self.max.x, other.max.x),
                max(self.max.y, other.max.y),
            ),
        })
    }

    /// Returns true if this box contains the interior of the other box.
    #[inline]
    pub fn contains_box(&self, other: &Self) -> bool {
        self.min.x <= other.min.x
            && other.max.x <= self.max.x
            && self.min.y <= other.min.y
            && other.max.y <= self.max.y
    }
}

impl<T, U> NonEmpty<Box2D<T, U>>
where
    T: Copy + Add<T, Output = T>,
{
    #[inline]
    pub fn translate(&self, by: Vector2D<T, U>) -> Self {
        NonEmpty(self.0.translate(by))
    }
}

impl<T, U> NonEmpty<Box3D<T, U>>
where
    T: Copy + PartialOrd,
{
    #[inline]
    pub fn union(&self, other: &NonEmpty<Box3D<T, U>>) -> NonEmpty<Box3D<T, U>> {
        NonEmpty(Box3D {
            min: point3(
                min(self.min.x, other.min.x),
                min(self.min.y, other.min.y),
                min(self.min.z, other.min.z),
            ),
            max: point3(
                max(self.max.x, other.max.x),
                max(self.max.y, other.max.y),
                max(self.max.z, other.max.z),
            ),
        })
    }

    /// Returns true if this box contains the interior of the other box.
    #[inline]
    pub fn contains_box(&self, other: &Self) -> bool {
        self.min.x <= other.min.x
            && other.max.x <= self.max.x
            && self.min.y <= other.min.y
            && other.max.y <= self.max.y
            && self.min.z <= other.min.z
            && other.max.z <= self.max.z
    }
}

impl<T, U> NonEmpty<Box3D<T, U>>
where
    T: Copy + Add<T, Output = T>,
{
    #[inline]
    pub fn translate(&self, by: Vector3D<T, U>) -> Self {
        NonEmpty(self.0.translate(by))
    }
}

#[test]
fn empty_nonempty() {
    use crate::default;

    // zero-width
    let box1: default::Box2D<i32> = Box2D {
        min: point2(-10, 2),
        max: point2(-10, 12),
    };
    // zero-height
    let box2: default::Box2D<i32> = Box2D {
        min: point2(0, 11),
        max: point2(2, 11),
    };
    // negative width
    let box3: default::Box2D<i32> = Box2D {
        min: point2(1, 11),
        max: point2(0, 12),
    };
    // negative height
    let box4: default::Box2D<i32> = Box2D {
        min: point2(0, 11),
        max: point2(5, 10),
    };

    assert!(box1.to_non_empty().is_none());
    assert!(box2.to_non_empty().is_none());
    assert!(box3.to_non_empty().is_none());
    assert!(box4.to_non_empty().is_none());
}

#[test]
fn nonempty_union() {
    use crate::default;

    let box1: default::Box2D<i32> = Box2D {
        min: point2(-10, 2),
        max: point2(15, 12),
    };
    let box2 = Box2D {
        min: point2(-2, -5),
        max: point2(10, 5),
    };

    assert_eq!(box1.union(&box2), *box1.to_non_empty().unwrap().union(&box2.to_non_empty().unwrap()));

    let box3: default::Box3D<i32> = Box3D {
        min: point3(1, -10, 2),
        max: point3(6, 15, 12),
    };
    let box4 = Box3D {
        min: point3(0, -2, -5),
        max: point3(7, 10, 5),
    };

    assert_eq!(box3.union(&box4), *box3.to_non_empty().unwrap().union(&box4.to_non_empty().unwrap()));

    let rect1: default::Rect<i32> = Rect {
        origin: point2(1, 2),
        size: size2(3, 4),
    };
    let rect2 = Rect {
        origin: point2(-1, 5),
        size: size2(1, 10),
    };

    assert_eq!(rect1.union(&rect2), *rect1.to_non_empty().unwrap().union(&rect2.to_non_empty().unwrap()));
}

#[test]
fn nonempty_contains() {
    use crate::default;
    use crate::{vec2, vec3};

    let r: NonEmpty<default::Rect<i32>> = Rect {
        origin: point2(-20, 15),
        size: size2(100, 200),
    }.to_non_empty().unwrap();

    assert!(r.contains_rect(&r));
    assert!(!r.contains_rect(&r.translate(vec2(1, 0))));
    assert!(!r.contains_rect(&r.translate(vec2(-1, 0))));
    assert!(!r.contains_rect(&r.translate(vec2(0, 1))));
    assert!(!r.contains_rect(&r.translate(vec2(0, -1))));

    let b: NonEmpty<default::Box2D<i32>> = Box2D {
        min: point2(-10, 5),
        max: point2(30, 100),
    }.to_non_empty().unwrap();

    assert!(b.contains_box(&b));
    assert!(!b.contains_box(&b.translate(vec2(1, 0))));
    assert!(!b.contains_box(&b.translate(vec2(-1, 0))));
    assert!(!b.contains_box(&b.translate(vec2(0, 1))));
    assert!(!b.contains_box(&b.translate(vec2(0, -1))));

    let b: NonEmpty<default::Box3D<i32>> = Box3D {
        min: point3(-1, -10, 5),
        max: point3(10, 30, 100),
    }.to_non_empty().unwrap();

    assert!(b.contains_box(&b));
    assert!(!b.contains_box(&b.translate(vec3(0, 1, 0))));
    assert!(!b.contains_box(&b.translate(vec3(0, -1, 0))));
    assert!(!b.contains_box(&b.translate(vec3(0, 0, 1))));
    assert!(!b.contains_box(&b.translate(vec3(0, 0, -1))));
    assert!(!b.contains_box(&b.translate(vec3(1, 1, 0))));
    assert!(!b.contains_box(&b.translate(vec3(1, -1, 0))));
    assert!(!b.contains_box(&b.translate(vec3(1, 0, 1))));
    assert!(!b.contains_box(&b.translate(vec3(1, 0, -1))));
    assert!(!b.contains_box(&b.translate(vec3(-1, 1, 0))));
    assert!(!b.contains_box(&b.translate(vec3(-1, -1, 0))));
    assert!(!b.contains_box(&b.translate(vec3(-1, 0, 1))));
    assert!(!b.contains_box(&b.translate(vec3(-1, 0, -1))));
}
<commit_msg>BBs: reuse some methods in NonEmpty implementation<commit_after>use crate::{Rect, Box2D, Box3D, Vector2D, Vector3D};
use core::ops::Deref;
use core::ops::{Add, Sub};
use core::cmp::{PartialEq};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct NonEmpty<T>(pub(crate) T);

impl<T> Deref for NonEmpty<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.0
    }
}

impl<T> NonEmpty<T> {
    #[inline]
    pub fn get(&self) -> &T {
        &self.0
    }
}

impl<T, U> NonEmpty<Rect<T, U>>
where
    T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
{
    #[inline]
    pub fn union(&self, other: &Self) -> Self {
        NonEmpty(self.0.to_box2d().union(&other.0.to_box2d()).to_rect())
    }

    #[inline]
    pub fn contains_rect(&self, rect: &Self) -> bool {
        self.min_x() <= rect.min_x()
            && rect.max_x() <= self.max_x()
            && self.min_y() <= rect.min_y()
            && rect.max_y() <= self.max_y()
    }

    #[inline]
    pub fn translate(&self, by: Vector2D<T, U>) -> Self {
        NonEmpty(self.0.translate(by))
    }
}

impl<T, U> NonEmpty<Box2D<T, U>>
where
    T: Copy + PartialOrd,
{
    #[inline]
    pub fn union(&self, other: &Self) -> Self {
        NonEmpty(self.0.union(&other.0))
    }

    /// Returns true if this box contains the interior of the other box.
    #[inline]
    pub fn contains_box(&self, other: &Self) -> bool {
        self.min.x <= other.min.x
            && other.max.x <= self.max.x
            && self.min.y <= other.min.y
            && other.max.y <= self.max.y
    }
}

impl<T, U> NonEmpty<Box2D<T, U>>
where
    T: Copy + Add<T, Output = T>,
{
    #[inline]
    pub fn translate(&self, by: Vector2D<T, U>) -> Self {
        NonEmpty(self.0.translate(by))
    }
}

impl<T, U> NonEmpty<Box3D<T, U>>
where
    T: Copy + PartialOrd,
{
    #[inline]
    pub fn union(&self, other: &Self) -> Self {
        NonEmpty(self.0.union(&other.0))
    }

    /// Returns true if this box contains the interior of the other box.
    #[inline]
    pub fn contains_box(&self, other: &Self) -> bool {
        self.min.x <= other.min.x
            && other.max.x <= self.max.x
            && self.min.y <= other.min.y
            && other.max.y <= self.max.y
            && self.min.z <= other.min.z
            && other.max.z <= self.max.z
    }
}

impl<T, U> NonEmpty<Box3D<T, U>>
where
    T: Copy + Add<T, Output = T>,
{
    #[inline]
    pub fn translate(&self, by: Vector3D<T, U>) -> Self {
        NonEmpty(self.0.translate(by))
    }
}

#[test]
fn empty_nonempty() {
    use crate::default;
    use crate::point2;

    // zero-width
    let box1: default::Box2D<i32> = Box2D {
        min: point2(-10, 2),
        max: point2(-10, 12),
    };
    // zero-height
    let box2: default::Box2D<i32> = Box2D {
        min: point2(0, 11),
        max: point2(2, 11),
    };
    // negative width
    let box3: default::Box2D<i32> = Box2D {
        min: point2(1, 11),
        max: point2(0, 12),
    };
    // negative height
    let box4: default::Box2D<i32> = Box2D {
        min: point2(0, 11),
        max: point2(5, 10),
    };

    assert!(box1.to_non_empty().is_none());
    assert!(box2.to_non_empty().is_none());
    assert!(box3.to_non_empty().is_none());
    assert!(box4.to_non_empty().is_none());
}

#[test]
fn nonempty_union() {
    use crate::default;
    use crate::{point2, point3, size2};

    let box1: default::Box2D<i32> = Box2D {
        min: point2(-10, 2),
        max: point2(15, 12),
    };
    let box2 = Box2D {
        min: point2(-2, -5),
        max: point2(10, 5),
    };

    assert_eq!(box1.union(&box2), *box1.to_non_empty().unwrap().union(&box2.to_non_empty().unwrap()));

    let box3: default::Box3D<i32> = Box3D {
        min: point3(1, -10, 2),
        max: point3(6, 15, 12),
    };
    let box4 = Box3D {
        min: point3(0, -2, -5),
        max: point3(7, 10, 5),
    };

    assert_eq!(box3.union(&box4), *box3.to_non_empty().unwrap().union(&box4.to_non_empty().unwrap()));

    let rect1: default::Rect<i32> = Rect {
        origin: point2(1, 2),
        size: size2(3, 4),
    };
    let rect2 = Rect {
        origin: point2(-1, 5),
        size: size2(1, 10),
    };

    assert_eq!(rect1.union(&rect2), *rect1.to_non_empty().unwrap().union(&rect2.to_non_empty().unwrap()));
}

#[test]
fn nonempty_contains() {
    use crate::default;
    use crate::{point2, point3, size2, vec2, vec3};

    let r: NonEmpty<default::Rect<i32>> = Rect {
        origin: point2(-20, 15),
        size: size2(100, 200),
    }.to_non_empty().unwrap();

    assert!(r.contains_rect(&r));
    assert!(!r.contains_rect(&r.translate(vec2(1, 0))));
    assert!(!r.contains_rect(&r.translate(vec2(-1, 0))));
    assert!(!r.contains_rect(&r.translate(vec2(0, 1))));
    assert!(!r.contains_rect(&r.translate(vec2(0, -1))));

    let b: NonEmpty<default::Box2D<i32>> = Box2D {
        min: point2(-10, 5),
        max: point2(30, 100),
    }.to_non_empty().unwrap();

    assert!(b.contains_box(&b));
    assert!(!b.contains_box(&b.translate(vec2(1, 0))));
    assert!(!b.contains_box(&b.translate(vec2(-1, 0))));
    assert!(!b.contains_box(&b.translate(vec2(0, 1))));
    assert!(!b.contains_box(&b.translate(vec2(0, -1))));

    let b: NonEmpty<default::Box3D<i32>> = Box3D {
        min: point3(-1, -10, 5),
        max: point3(10, 30, 100),
    }.to_non_empty().unwrap();

    assert!(b.contains_box(&b));
    assert!(!b.contains_box(&b.translate(vec3(0, 1, 0))));
    assert!(!b.contains_box(&b.translate(vec3(0, -1, 0))));
    assert!(!b.contains_box(&b.translate(vec3(0, 0, 1))));
    assert!(!b.contains_box(&b.translate(vec3(0, 0, -1))));
    assert!(!b.contains_box(&b.translate(vec3(1, 1, 0))));
    assert!(!b.contains_box(&b.translate(vec3(1, -1, 0))));
    assert!(!b.contains_box(&b.translate(vec3(1, 0, 1))));
    assert!(!b.contains_box(&b.translate(vec3(1, 0, -1))));
    assert!(!b.contains_box(&b.translate(vec3(-1, 1, 0))));
    assert!(!b.contains_box(&b.translate(vec3(-1, -1, 0))));
    assert!(!b.contains_box(&b.translate(vec3(-1, 0, 1))));
    assert!(!b.contains_box(&b.translate(vec3(-1, 0, -1))));
}
<|endoftext|>


<commit_before>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// 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.

//! Provides interfaces for interacting with packets and headers

#![macro_use]

use std::ops::{Deref, DerefMut, Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo};

/// Represents a generic network packet
pub trait Packet {
    /// Retreive the underlying buffer for the packet
    fn packet(&self) -> &[u8];

    /// Retreive the payload for the packet
    fn payload(&self) -> &[u8];
}

/// Represents a generic, mutable, network packet
pub trait MutablePacket: Packet {
    /// Retreive the underlying, mutable, buffer for the packet
    fn packet_mut(&mut self) -> &mut [u8];

    /// Retreive the mutable payload for the packet
    fn payload_mut(&mut self) -> &mut [u8];

    /// Initialize this packet by cloning another
    fn clone_from<T: Packet>(&mut self, other: &T) {
        use std::ptr;

        assert!(self.packet().len() >= other.packet().len());
        unsafe {
            ptr::copy_nonoverlapping(other.packet().as_ptr(),
                                     self.packet_mut().as_mut_ptr(),
                                     other.packet().len());
        }
    }
}

/// Used to convert on-the-wire packets to their #[packet] equivalent
pub trait FromPacket: Packet {
    /// The type of the packet to convert from
    type T;

    /// Converts a wire-format packet to #[packet] struct format
    fn from_packet(&self) -> Self::T;
}

/// Used to find the calculated size of the packet. This is used for occasions where the underlying
/// buffer is not the same length as the packet itself.
pub trait PacketSize: Packet {
    /// Get the calculated size of the packet
    fn packet_size(&self) -> usize;
}

macro_rules! impl_index {
    ($t:ident, $index_t:ty, $output_t:ty) => {
        impl<'p> Index<$index_t> for $t<'p> {
            type Output = $output_t;

            fn index(&self, index: $index_t) -> &$output_t {
                &self.as_slice().index(index)
            }
        }
    };
}

macro_rules! impl_index_mut {
    ($t:ident, $index_t:ty, $output_t:ty) => {
        impl<'p> IndexMut<$index_t> for $t<'p> {
            fn index_mut(&mut self, index: $index_t) -> &mut $output_t {
                self.as_mut_slice().index_mut(index)
            }
        }
    };
}

#[derive(PartialEq)]
enum PacketData<'p> {
    Owned(Vec<u8>),
    Borrowed(&'p [u8]),
}

impl<'p> PacketData<'p> {
    fn as_slice(&self) -> &[u8] {
        match self {
            &PacketData::Owned(ref data) => data.deref(),
            &PacketData::Borrowed(ref data) => data,
        }
    }

    fn to_immutable(self) -> PacketData<'p> {
        self
    }

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

impl_index!(PacketData, usize, u8);
impl_index!(PacketData, Range<usize>, [u8]);
impl_index!(PacketData, RangeTo<usize>, [u8]);
impl_index!(PacketData, RangeFrom<usize>, [u8]);
impl_index!(PacketData, RangeFull, [u8]);

#[derive(PartialEq)]
enum MutPacketData<'p> {
    Owned(Vec<u8>),
    Borrowed(&'p mut [u8]),
}

impl<'p> MutPacketData<'p> {
    fn as_slice(&self) -> &[u8] {
        match self {
            &MutPacketData::Owned(ref data) => data.deref(),
            &MutPacketData::Borrowed(ref data) => data,
        }
    }

    fn as_mut_slice(&mut self) -> &mut [u8] {
        match self {
            &mut MutPacketData::Owned(ref mut data) => data.deref_mut(),
            &mut MutPacketData::Borrowed(ref mut data) => data,
        }
    }

    fn to_immutable(self) -> PacketData<'p> {
        match self {
            MutPacketData::Owned(data) => PacketData::Owned(data),
            MutPacketData::Borrowed(data) => PacketData::Borrowed(data),
        }
    }

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

impl_index!(MutPacketData, usize, u8);
impl_index!(MutPacketData, Range<usize>, [u8]);
impl_index!(MutPacketData, RangeTo<usize>, [u8]);
impl_index!(MutPacketData, RangeFrom<usize>, [u8]);
impl_index!(MutPacketData, RangeFull, [u8]);

impl_index_mut!(MutPacketData, usize, u8);
impl_index_mut!(MutPacketData, Range<usize>, [u8]);
impl_index_mut!(MutPacketData, RangeTo<usize>, [u8]);
impl_index_mut!(MutPacketData, RangeFrom<usize>, [u8]);
impl_index_mut!(MutPacketData, RangeFull, [u8]);

/// Used to convert a type to primitive values representing it
pub trait PrimitiveValues {
    /// A tuple of types, to represent the current value
    type T;

    /// Convert a value to primitive types representing it
    fn to_primitive_values(&self) -> Self::T;
}

impl PrimitiveValues for ::std::net::Ipv4Addr {
    type T = (u8, u8, u8, u8);
    fn to_primitive_values(&self) -> (u8, u8, u8, u8) {
        let octets = self.octets();

        (octets[0], octets[1], octets[2], octets[3])
    }
}

impl PrimitiveValues for ::std::net::Ipv6Addr {
    type T = (u16, u16, u16, u16, u16, u16, u16, u16);
    fn to_primitive_values(&self) -> (u16, u16, u16, u16, u16, u16, u16, u16) {
        let segments = self.segments();

        (segments[0],
         segments[1],
         segments[2],
         segments[3],
         segments[4],
         segments[5],
         segments[6],
         segments[7])
    }
}

pub mod ethernet;
pub mod gre;
pub mod ip;
pub mod ipv4;
pub mod ipv6;
pub mod udp;
pub mod tcp;
pub mod arp;
pub mod icmp;
pub mod vlan;
<commit_msg>Make PacketData public<commit_after>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// 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.

//! Provides interfaces for interacting with packets and headers
#![allow(missing_docs)]
#![macro_use]

use std::ops::{Deref, DerefMut, Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo};

/// Represents a generic network packet
pub trait Packet {
    /// Retreive the underlying buffer for the packet
    fn packet(&self) -> &[u8];

    /// Retreive the payload for the packet
    fn payload(&self) -> &[u8];
}

/// Represents a generic, mutable, network packet
pub trait MutablePacket: Packet {
    /// Retreive the underlying, mutable, buffer for the packet
    fn packet_mut(&mut self) -> &mut [u8];

    /// Retreive the mutable payload for the packet
    fn payload_mut(&mut self) -> &mut [u8];

    /// Initialize this packet by cloning another
    fn clone_from<T: Packet>(&mut self, other: &T) {
        use std::ptr;

        assert!(self.packet().len() >= other.packet().len());
        unsafe {
            ptr::copy_nonoverlapping(other.packet().as_ptr(),
                                     self.packet_mut().as_mut_ptr(),
                                     other.packet().len());
        }
    }
}

/// Used to convert on-the-wire packets to their #[packet] equivalent
pub trait FromPacket: Packet {
    /// The type of the packet to convert from
    type T;

    /// Converts a wire-format packet to #[packet] struct format
    fn from_packet(&self) -> Self::T;
}

/// Used to find the calculated size of the packet. This is used for occasions where the underlying
/// buffer is not the same length as the packet itself.
pub trait PacketSize: Packet {
    /// Get the calculated size of the packet
    fn packet_size(&self) -> usize;
}

macro_rules! impl_index {
    ($t:ident, $index_t:ty, $output_t:ty) => {
        impl<'p> Index<$index_t> for $t<'p> {
            type Output = $output_t;

            fn index(&self, index: $index_t) -> &$output_t {
                &self.as_slice().index(index)
            }
        }
    };
}

macro_rules! impl_index_mut {
    ($t:ident, $index_t:ty, $output_t:ty) => {
        impl<'p> IndexMut<$index_t> for $t<'p> {
            fn index_mut(&mut self, index: $index_t) -> &mut $output_t {
                self.as_mut_slice().index_mut(index)
            }
        }
    };
}

#[derive(PartialEq)]
pub enum PacketData<'p> {
    /// Packet owns its contents
    Owned(Vec<u8>),
    /// Packet borrows its contents
    Borrowed(&'p [u8]),
}

impl<'p> PacketData<'p> {
    pub fn as_slice(&self) -> &[u8] {
        match self {
            &PacketData::Owned(ref data) => data.deref(),
            &PacketData::Borrowed(ref data) => data,
        }
    }

    pub fn to_immutable(self) -> PacketData<'p> {
        self
    }

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

impl_index!(PacketData, usize, u8);
impl_index!(PacketData, Range<usize>, [u8]);
impl_index!(PacketData, RangeTo<usize>, [u8]);
impl_index!(PacketData, RangeFrom<usize>, [u8]);
impl_index!(PacketData, RangeFull, [u8]);

#[derive(PartialEq)]
pub enum MutPacketData<'p> {
    Owned(Vec<u8>),
    Borrowed(&'p mut [u8]),
}

impl<'p> MutPacketData<'p> {
    pub fn as_slice(&self) -> &[u8] {
        match self {
            &MutPacketData::Owned(ref data) => data.deref(),
            &MutPacketData::Borrowed(ref data) => data,
        }
    }

    pub fn as_mut_slice(&mut self) -> &mut [u8] {
        match self {
            &mut MutPacketData::Owned(ref mut data) => data.deref_mut(),
            &mut MutPacketData::Borrowed(ref mut data) => data,
        }
    }

    pub fn to_immutable(self) -> PacketData<'p> {
        match self {
            MutPacketData::Owned(data) => PacketData::Owned(data),
            MutPacketData::Borrowed(data) => PacketData::Borrowed(data),
        }
    }

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

impl_index!(MutPacketData, usize, u8);
impl_index!(MutPacketData, Range<usize>, [u8]);
impl_index!(MutPacketData, RangeTo<usize>, [u8]);
impl_index!(MutPacketData, RangeFrom<usize>, [u8]);
impl_index!(MutPacketData, RangeFull, [u8]);

impl_index_mut!(MutPacketData, usize, u8);
impl_index_mut!(MutPacketData, Range<usize>, [u8]);
impl_index_mut!(MutPacketData, RangeTo<usize>, [u8]);
impl_index_mut!(MutPacketData, RangeFrom<usize>, [u8]);
impl_index_mut!(MutPacketData, RangeFull, [u8]);

/// Used to convert a type to primitive values representing it
pub trait PrimitiveValues {
    /// A tuple of types, to represent the current value
    type T;

    /// Convert a value to primitive types representing it
    fn to_primitive_values(&self) -> Self::T;
}

impl PrimitiveValues for ::std::net::Ipv4Addr {
    type T = (u8, u8, u8, u8);
    fn to_primitive_values(&self) -> (u8, u8, u8, u8) {
        let octets = self.octets();

        (octets[0], octets[1], octets[2], octets[3])
    }
}

impl PrimitiveValues for ::std::net::Ipv6Addr {
    type T = (u16, u16, u16, u16, u16, u16, u16, u16);
    fn to_primitive_values(&self) -> (u16, u16, u16, u16, u16, u16, u16, u16) {
        let segments = self.segments();

        (segments[0],
         segments[1],
         segments[2],
         segments[3],
         segments[4],
         segments[5],
         segments[6],
         segments[7])
    }
}

pub mod ethernet;
pub mod gre;
pub mod ip;
pub mod ipv4;
pub mod ipv6;
pub mod udp;
pub mod tcp;
pub mod arp;
pub mod icmp;
pub mod vlan;
<|endoftext|>


<commit_before>use config;
use config::action::message::MessageActionBuilder;
use conditions::ConditionsBuilder;
use Correlator;
use dispatcher::ResponseHandler;
use message::{
    MessageBuilder
};
use Response;

use uuid::Uuid;
use serde_json::from_str;
use std::rc::Rc;
use std::cell::RefCell;
use std::thread;

use reactor::EventHandler;
use action::MessageResponse;

const JSON_CONFIG: &'static str = r#"
      [
        {
          "name": "CONTEXT_NAME_1",
          "uuid": "185e96da-c00e-454b-b4fe-9d0a14a86335",
          "conditions": {
            "timeout": 100,
            "patterns": [
              "p1",
              "p2",
              "p3"
            ],
            "first_opens": true
          },
          "actions": [
            {
              "message": {
                  "uuid": "uuid1"
              }
            }
          ]
        },
        {
          "name": "CONTEXT_NAME_2",
          "uuid": "285e96da-c00e-454b-b4fe-9d0a14a86335",
          "conditions": {
            "timeout": 10000,
            "max_size": 5
          },
          "actions": [
            {
              "message": {
                  "uuid": "uuid1"
              }
            },
            {
              "message": {
                  "uuid": "uuid2"
              }
            }
          ]
        },
        {
          "name": "CONTEXT_NAME_3",
          "uuid": "385e96da-c00e-454b-b4fe-9d0a14a86335",
          "conditions": {
            "timeout": 100,
            "patterns": [
              "p1"
            ]
          },
          "actions": [
            {
              "message": {
                  "uuid": "uuid2"
              }
            }
          ]
        }
      ]
    "#;

struct MessageEventHandler {
    responses: Rc<RefCell<Vec<MessageResponse>>>
}

impl EventHandler<Response> for MessageEventHandler {
    fn handle_event(&mut self, event: Response) {
        if let Response::Message(event) = event {
            self.responses.borrow_mut().push(event);
        }
    }
    fn handler(&self) -> ResponseHandler {
        ResponseHandler::Message
    }
}

#[test]
fn test_given_manually_built_correlator_when_it_closes_a_context_then_the_actions_are_executed() {
    let uuid1 = "1b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let uuid2 = "2b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let uuid3 = "3b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let patterns = vec![
        uuid1.clone(),
        uuid2.clone(),
        uuid3.clone(),
    ];
    let condition = ConditionsBuilder::new(100).patterns(patterns)
                                                .first_opens(true)
                                                .last_closes(true)
                                                .build();
    let actions = vec![ MessageActionBuilder::new("uuid").build().into() ];
    let contexts = vec!{
        config::ContextBuilder::new(Uuid::new_v4(), condition.clone()).actions(actions.clone()).build(),
        config::ContextBuilder::new(Uuid::new_v4(), condition.clone()).actions(actions.clone()).build(),
        config::ContextBuilder::new(Uuid::new_v4(), condition.clone()).actions(actions.clone()).build(),
    };
    let responses = Rc::new(RefCell::new(Vec::new()));
    let message_event_handler = Box::new(MessageEventHandler{responses: responses.clone()});
    let mut correlator = Correlator::new(contexts);
    correlator.register_handler(message_event_handler);
    let _ = correlator.push_message(MessageBuilder::new(&uuid1).build());
    thread::sleep_ms(20);
    let _ = correlator.push_message(MessageBuilder::new(&uuid2).build());
    thread::sleep_ms(80);
    let _ = correlator.push_message(MessageBuilder::new(&uuid3).build());
    let _ = correlator.stop();
    assert_eq!(3, responses.borrow().len());
}

#[test]
fn test_given_correlator_when_it_is_built_from_json_then_we_get_the_expected_correlator() {
    let result = from_str::<Vec<config::Context>>(JSON_CONFIG);
    let expected_name = "CONTEXT_NAME_1".to_string();
    let expected_uuid = "185e96da-c00e-454b-b4fe-9d0a14a86335".to_string();
    println!("{:?}", &result);
    let mut contexts = result.ok().expect("Failed to deserialize a config::Context from JSON");
    for i in &contexts {
        assert_eq!(true, i.name.is_some());
    }
    let context = contexts.remove(0);
    assert_eq!(Some(&expected_name), context.name.as_ref());
    assert_eq!(&expected_uuid, &context.uuid.to_hyphenated_string());
}

#[test]
fn test_given_correlator_when_it_is_built_from_json_then_it_produces_the_expected_number_of_messages() {
    let uuid1 = "1b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let uuid2 = "2b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let uuid3 = "3b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let result = from_str::<Vec<config::Context>>(JSON_CONFIG);
    println!("{:?}", &result);
    let contexts = result.ok().expect("Failed to deserialize a config::Context from JSON");
    let responses = Rc::new(RefCell::new(Vec::new()));
    let message_event_handler = Box::new(MessageEventHandler{responses: responses.clone()});
    let mut correlator = Correlator::new(contexts);
    correlator.register_handler(message_event_handler);
    let _ = correlator.push_message(MessageBuilder::new(&uuid1).name(Some("p1")).build());
    thread::sleep_ms(20);
    let _ = correlator.push_message(MessageBuilder::new(&uuid2).name(Some("p2")).build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3).name(Some("p3")).build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3).name(Some("p3")).build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3).name(Some("p3")).build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3).name(Some("p3")).build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3).name(Some("p3")).build());
    thread::sleep_ms(200);
    let _ = correlator.stop();
    println!("{:?}", &responses.borrow());
    assert_eq!(4, responses.borrow().len());
}
<commit_msg>Correlator: use test_utils module<commit_after>use config;
use config::action::message::MessageActionBuilder;
use conditions::ConditionsBuilder;
use Correlator;
use message::{
    MessageBuilder
};

use uuid::Uuid;
use serde_json::from_str;
use std::rc::Rc;
use std::cell::RefCell;
use std::thread;

use test_utils::correlator::MessageEventHandler;

const JSON_CONFIG: &'static str = r#"
      [
        {
          "name": "CONTEXT_NAME_1",
          "uuid": "185e96da-c00e-454b-b4fe-9d0a14a86335",
          "conditions": {
            "timeout": 100,
            "patterns": [
              "p1",
              "p2",
              "p3"
            ],
            "first_opens": true
          },
          "actions": [
            {
              "message": {
                  "uuid": "uuid1"
              }
            }
          ]
        },
        {
          "name": "CONTEXT_NAME_2",
          "uuid": "285e96da-c00e-454b-b4fe-9d0a14a86335",
          "conditions": {
            "timeout": 10000,
            "max_size": 5
          },
          "actions": [
            {
              "message": {
                  "uuid": "uuid1"
              }
            },
            {
              "message": {
                  "uuid": "uuid2"
              }
            }
          ]
        },
        {
          "name": "CONTEXT_NAME_3",
          "uuid": "385e96da-c00e-454b-b4fe-9d0a14a86335",
          "conditions": {
            "timeout": 100,
            "patterns": [
              "p1"
            ]
          },
          "actions": [
            {
              "message": {
                  "uuid": "uuid2"
              }
            }
          ]
        }
      ]
    "#;

#[test]
fn test_given_manually_built_correlator_when_it_closes_a_context_then_the_actions_are_executed() {
    let uuid1 = "1b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let uuid2 = "2b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let uuid3 = "3b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let patterns = vec![
        uuid1.clone(),
        uuid2.clone(),
        uuid3.clone(),
    ];
    let condition = ConditionsBuilder::new(100).patterns(patterns)
                                                .first_opens(true)
                                                .last_closes(true)
                                                .build();
    let actions = vec![ MessageActionBuilder::new("uuid").build().into() ];
    let contexts = vec!{
        config::ContextBuilder::new(Uuid::new_v4(), condition.clone()).actions(actions.clone()).build(),
        config::ContextBuilder::new(Uuid::new_v4(), condition.clone()).actions(actions.clone()).build(),
        config::ContextBuilder::new(Uuid::new_v4(), condition.clone()).actions(actions.clone()).build(),
    };
    let responses = Rc::new(RefCell::new(Vec::new()));
    let message_event_handler = Box::new(MessageEventHandler{responses: responses.clone()});
    let mut correlator = Correlator::new(contexts);
    correlator.register_handler(message_event_handler);
    let _ = correlator.push_message(MessageBuilder::new(&uuid1).build());
    thread::sleep_ms(20);
    let _ = correlator.push_message(MessageBuilder::new(&uuid2).build());
    thread::sleep_ms(80);
    let _ = correlator.push_message(MessageBuilder::new(&uuid3).build());
    let _ = correlator.stop();
    assert_eq!(3, responses.borrow().len());
}

#[test]
fn test_given_correlator_when_it_is_built_from_json_then_we_get_the_expected_correlator() {
    let result = from_str::<Vec<config::Context>>(JSON_CONFIG);
    let expected_name = "CONTEXT_NAME_1".to_string();
    let expected_uuid = "185e96da-c00e-454b-b4fe-9d0a14a86335".to_string();
    println!("{:?}", &result);
    let mut contexts = result.ok().expect("Failed to deserialize a config::Context from JSON");
    for i in &contexts {
        assert_eq!(true, i.name.is_some());
    }
    let context = contexts.remove(0);
    assert_eq!(Some(&expected_name), context.name.as_ref());
    assert_eq!(&expected_uuid, &context.uuid.to_hyphenated_string());
}

#[test]
fn test_given_correlator_when_it_is_built_from_json_then_it_produces_the_expected_number_of_messages() {
    let uuid1 = "1b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let uuid2 = "2b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let uuid3 = "3b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let result = from_str::<Vec<config::Context>>(JSON_CONFIG);
    println!("{:?}", &result);
    let contexts = result.ok().expect("Failed to deserialize a config::Context from JSON");
    let responses = Rc::new(RefCell::new(Vec::new()));
    let message_event_handler = Box::new(MessageEventHandler{responses: responses.clone()});
    let mut correlator = Correlator::new(contexts);
    correlator.register_handler(message_event_handler);
    let _ = correlator.push_message(MessageBuilder::new(&uuid1).name(Some("p1")).build());
    thread::sleep_ms(20);
    let _ = correlator.push_message(MessageBuilder::new(&uuid2).name(Some("p2")).build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3).name(Some("p3")).build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3).name(Some("p3")).build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3).name(Some("p3")).build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3).name(Some("p3")).build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3).name(Some("p3")).build());
    thread::sleep_ms(200);
    let _ = correlator.stop();
    println!("{:?}", &responses.borrow());
    assert_eq!(4, responses.borrow().len());
}
<|endoftext|>