<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! Functions for mapping sets of symbol ranges onto other sets of symbol ranges.
//!
//! The most important thing that this does is deal with changing a set of overlapping symbol ranges into a set
//! of non-overlapping ranges. This is needed because the DFA compiler assumes that symbols are unique. The
//! function `Ndfa::fix_overlapping_ranges` in particular makes use of this to generate an NDFA suitable as input
//! to the DFA compiler.
//!
//! # Example
//!
//! ```
//! # use ndfa::*;
//! let map = SymbolMap::new();
//!
//! map.add_range(&SymbolRange::new(0, 10));
//! map.add_range(&SymbolRange::new(5, 15));
//!
//! let without_overlaps = map.to_non_overlapping_map();
//!
//! let ranges = without_overlaps.find_overlapping_ranges(&SymbolRange::new(0, 10)); // 0-4, 5-10
//! ```
//!

use std::cmp::Ordering;

use super::symbol_range::*;
use super::countable::*;

///
/// A symbol map maps from one set of symbol ranges to another
///
pub struct SymbolMap<Symbol: Ord+Clone+Countable> {
    // Ranges in this symbol map
    ranges: Vec<SymbolRange<Symbol>>,
}

impl<Symbol: Ord+Clone+Countable> SymbolMap<Symbol> {
    ///
    /// Creates a new symbol map
    ///
    pub fn new() -> SymbolMap<Symbol> {
        SymbolMap { ranges: vec![] }
    }

    ///
    /// Orders two symbols (makes unordered symbols equal)
    ///
    #[inline]
    fn order_symbols(a: &Symbol, b: &Symbol) -> Ordering {
        a.cmp(b)
    }

    ///
    /// Orders two symbol ranges
    ///
    #[inline]
    fn order_ranges(a: &SymbolRange<Symbol>, b: &SymbolRange<Symbol>) -> Ordering {
        let ordering = SymbolMap::order_symbols(&a.lowest, &b.lowest);

        if ordering == Ordering::Equal {
            SymbolMap::order_symbols(&a.highest, &b.highest)
        } else {
            ordering
        }
    }

    ///
    /// Adds a range to those that are known about by this object
    ///
    pub fn add_range(&mut self, range: &SymbolRange<Symbol>) {
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Insert the range if it is not already in the map
        if let Err(insertion_pos) = existing {
            self.ranges.insert(insertion_pos, range.clone());
        }
    }

    ///
    /// Finds the ranges in this map that overlap the target ranges
    ///
    pub fn find_overlapping_ranges(&self, range: &SymbolRange<Symbol>) -> Vec<&SymbolRange<Symbol>> {
        let mut result = vec![];

        // Find the first range that matches (or the insertion position, which should be the first range wit a lowest value higher than the target range)
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Start returning values from here
        let mut pos = match existing {
            Ok(found_position) => found_position,
            Err(insert_position) => insert_position
        };

        // Move backwards if the previous position overlaps this one
        if pos > 0 && self.ranges[pos-1].highest >= range.lowest {
            pos -= 1;
        }

        // TODO: can we construct a set of ranges such that one is missed here? Think maybe we can
        while pos < self.ranges.len() && self.ranges[pos].lowest <= range.highest {
            result.push(&self.ranges[pos]);
            pos += 1;
        }

        result
    }

    ///
    /// Creates a non-overlapping range from an overlapping one
    ///
    pub fn to_non_overlapping_map(&self) -> SymbolMap<Symbol> {
        // Stack, popping the lowest ordered ranges first
        let mut to_process = self.ranges.clone();
        to_process.reverse();

        let mut result = vec![];

        while let Some(might_overlap) = to_process.pop() {
            if let Some(overlap_with) = to_process.pop() {
                // Stack has two ranges on top. They might overlap
                if !might_overlap.overlaps(&overlap_with) {
                    // Doesn't overlap: can just push might_overlap and continue
                    result.push(might_overlap);
                    to_process.push(overlap_with);
                } else {
                    // Got an overlap
                    if might_overlap == overlap_with {
                        // Ranges are the same, just discard one
                        to_process.push(overlap_with);
                    } else if might_overlap.lowest == overlap_with.lowest {
                        // Ranges start at the same location. We need to divide them in case more than two ranges are overlapping
                        let (smaller_range, larger_range) = (might_overlap, overlap_with);      // Because of the sort order

                        // Chop out the smaller range from the larger range, then insert into the stack in order
                        let larger_range_without_smaller_range = SymbolRange::new(smaller_range.highest.next(), larger_range.highest.clone());

                        if let Err(insertion_pos) = to_process.binary_search_by(|test_range| { SymbolMap::order_ranges(&larger_range_without_smaller_range, test_range) }) {
                            to_process.insert(insertion_pos, larger_range_without_smaller_range);
                        }

                        to_process.push(smaller_range);
                    } else {
                        // There's a range from the lowest of the first range to the lowest of the second ranges
                        result.push(SymbolRange::new(might_overlap.lowest.clone(), overlap_with.lowest.prev()));

                        // Chop out the bit we just pushed from might_overlap and push back both ranges
                        // Maintain sort order depending on highest (as lowest for both ranges will be equal)
                        if overlap_with.highest > might_overlap.highest {
                            to_process.push(overlap_with.clone());
                            to_process.push(SymbolRange::new(overlap_with.lowest, might_overlap.highest));
                        } else {
                            to_process.push(SymbolRange::new(overlap_with.lowest.clone(), might_overlap.highest));
                            to_process.push(overlap_with);
                        }
                    }
                }
            } else {
                // Last range should never overlap
                result.push(might_overlap);
            }
        }

        // Ranges should already be sorted as we worked from left to right
        SymbolMap { ranges: result }
    }
}

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

    #[test]
    fn can_lookup_overlapping_ranges() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let bottom = map.find_overlapping_ranges(&SymbolRange::new(0, 1));
        let all    = map.find_overlapping_ranges(&SymbolRange::new(1, 3));
        let top    = map.find_overlapping_ranges(&SymbolRange::new(6, 6));

        assert!(bottom == vec![&SymbolRange::new(0, 4)]);
        assert!(all == vec![&SymbolRange::new(0, 4), &SymbolRange::new(2, 5), &SymbolRange::new(3, 6)]);
        assert!(top == vec![&SymbolRange::new(3, 6)]);
    }

    #[test]
    fn can_lookup_mid_range() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(5, 10));
        map.add_range(&SymbolRange::new(11, 15));

        let mid = map.find_overlapping_ranges(&SymbolRange::new(1, 3));

        assert!(mid == vec![&SymbolRange::new(0, 4)]);
    }

    #[test]
    fn works_with_duplicate_lower_values() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 2));
        map.add_range(&SymbolRange::new(0, 3));

        let all    = map.find_overlapping_ranges(&SymbolRange::new(0, 1));

        assert!(all == vec![&SymbolRange::new(0, 2), &SymbolRange::new(0, 3)]);
    }

    #[test]
    fn can_get_non_overlapping_map() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 1), &SymbolRange::new(2, 2), &SymbolRange::new(3, 4), &SymbolRange::new(5, 5), &SymbolRange::new(6, 6)]);
    }

    #[test]
    fn can_get_non_overlapping_map_with_single_symbols() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 5));
        map.add_range(&SymbolRange::new(2, 2));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 1), &SymbolRange::new(2, 2), &SymbolRange::new(3, 5), &SymbolRange::new(6, 6)]);
    }

    #[test]
    fn can_deal_with_duplicate_symbols() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 5));
        map.add_range(&SymbolRange::new(2, 2));
        map.add_range(&SymbolRange::new(3, 6));

        map.add_range(&SymbolRange::new(0, 5));
        map.add_range(&SymbolRange::new(2, 2));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 1), &SymbolRange::new(2, 2), &SymbolRange::new(3, 5), &SymbolRange::new(6, 6)]);
    }

    #[test]
    fn generate_correctly_for_single_symbol() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 0));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 10));

        assert!(all == vec![&SymbolRange::new(0, 0)]);
    }

    #[test]
    fn generate_correctly_for_two_single_symbols() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 0));
        map.add_range(&SymbolRange::new(1, 1));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 10));

        assert!(all == vec![&SymbolRange::new(0, 0), &SymbolRange::new(1, 1)]);
    }

    #[test]
    fn generate_correctly_for_non_overlapping_ranges() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 1));
        map.add_range(&SymbolRange::new(2, 4));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 10));

        assert!(all == vec![&SymbolRange::new(0, 1), &SymbolRange::new(2, 4)]);
    }

    #[test]
    fn generate_correctly_for_single_overlap() {
        let mut map = SymbolMap::new();

        // Here the symbol '5' is in both ranges, so we should generate it as a seperate range in the non-overlapping version
        map.add_range(&SymbolRange::new(0, 5));
        map.add_range(&SymbolRange::new(5, 10));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 10));

        assert!(all == vec![&SymbolRange::new(0, 4), &SymbolRange::new(5,5), &SymbolRange::new(6, 10)]);
    }

    #[test]
    fn can_get_non_overlapping_map_with_single_symbols_at_start() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 0));
        map.add_range(&SymbolRange::new(0, 1));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 0), &SymbolRange::new(1, 1)]);
    }

    #[test]
    fn can_get_non_overlapping_map_with_single_symbols_at_start_and_gap() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 0));
        map.add_range(&SymbolRange::new(0, 1));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 0), &SymbolRange::new(1, 1), &SymbolRange::new(3, 6)]);
    }
}
<commit_msg>Fix doc comment<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! Functions for mapping sets of symbol ranges onto other sets of symbol ranges.
//!
//! The most important thing that this does is deal with changing a set of overlapping symbol ranges into a set
//! of non-overlapping ranges. This is needed because the DFA compiler assumes that symbols are unique. The
//! function `Ndfa::fix_overlapping_ranges` in particular makes use of this to generate an NDFA suitable as input
//! to the DFA compiler.
//!
//! # Example
//!
//! ```
//! # use ndfa::*;
//! # use ndfa::overlapping_symbols::*;
//! let mut map = SymbolMap::new();
//!
//! map.add_range(&SymbolRange::new(0, 10));
//! map.add_range(&SymbolRange::new(5, 15));
//!
//! let without_overlaps = map.to_non_overlapping_map();
//!
//! let ranges = without_overlaps.find_overlapping_ranges(&SymbolRange::new(0, 10)); // 0-4, 5-10
//! ```
//!

use std::cmp::Ordering;

use super::symbol_range::*;
use super::countable::*;

///
/// A symbol map maps from one set of symbol ranges to another
///
pub struct SymbolMap<Symbol: Ord+Clone+Countable> {
    // Ranges in this symbol map
    ranges: Vec<SymbolRange<Symbol>>,
}

impl<Symbol: Ord+Clone+Countable> SymbolMap<Symbol> {
    ///
    /// Creates a new symbol map
    ///
    pub fn new() -> SymbolMap<Symbol> {
        SymbolMap { ranges: vec![] }
    }

    ///
    /// Orders two symbols (makes unordered symbols equal)
    ///
    #[inline]
    fn order_symbols(a: &Symbol, b: &Symbol) -> Ordering {
        a.cmp(b)
    }

    ///
    /// Orders two symbol ranges
    ///
    #[inline]
    fn order_ranges(a: &SymbolRange<Symbol>, b: &SymbolRange<Symbol>) -> Ordering {
        let ordering = SymbolMap::order_symbols(&a.lowest, &b.lowest);

        if ordering == Ordering::Equal {
            SymbolMap::order_symbols(&a.highest, &b.highest)
        } else {
            ordering
        }
    }

    ///
    /// Adds a range to those that are known about by this object
    ///
    pub fn add_range(&mut self, range: &SymbolRange<Symbol>) {
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Insert the range if it is not already in the map
        if let Err(insertion_pos) = existing {
            self.ranges.insert(insertion_pos, range.clone());
        }
    }

    ///
    /// Finds the ranges in this map that overlap the target ranges
    ///
    pub fn find_overlapping_ranges(&self, range: &SymbolRange<Symbol>) -> Vec<&SymbolRange<Symbol>> {
        let mut result = vec![];

        // Find the first range that matches (or the insertion position, which should be the first range wit a lowest value higher than the target range)
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Start returning values from here
        let mut pos = match existing {
            Ok(found_position) => found_position,
            Err(insert_position) => insert_position
        };

        // Move backwards if the previous position overlaps this one
        if pos > 0 && self.ranges[pos-1].highest >= range.lowest {
            pos -= 1;
        }

        // TODO: can we construct a set of ranges such that one is missed here? Think maybe we can
        while pos < self.ranges.len() && self.ranges[pos].lowest <= range.highest {
            result.push(&self.ranges[pos]);
            pos += 1;
        }

        result
    }

    ///
    /// Creates a non-overlapping range from an overlapping one
    ///
    pub fn to_non_overlapping_map(&self) -> SymbolMap<Symbol> {
        // Stack, popping the lowest ordered ranges first
        let mut to_process = self.ranges.clone();
        to_process.reverse();

        let mut result = vec![];

        while let Some(might_overlap) = to_process.pop() {
            if let Some(overlap_with) = to_process.pop() {
                // Stack has two ranges on top. They might overlap
                if !might_overlap.overlaps(&overlap_with) {
                    // Doesn't overlap: can just push might_overlap and continue
                    result.push(might_overlap);
                    to_process.push(overlap_with);
                } else {
                    // Got an overlap
                    if might_overlap == overlap_with {
                        // Ranges are the same, just discard one
                        to_process.push(overlap_with);
                    } else if might_overlap.lowest == overlap_with.lowest {
                        // Ranges start at the same location. We need to divide them in case more than two ranges are overlapping
                        let (smaller_range, larger_range) = (might_overlap, overlap_with);      // Because of the sort order

                        // Chop out the smaller range from the larger range, then insert into the stack in order
                        let larger_range_without_smaller_range = SymbolRange::new(smaller_range.highest.next(), larger_range.highest.clone());

                        if let Err(insertion_pos) = to_process.binary_search_by(|test_range| { SymbolMap::order_ranges(&larger_range_without_smaller_range, test_range) }) {
                            to_process.insert(insertion_pos, larger_range_without_smaller_range);
                        }

                        to_process.push(smaller_range);
                    } else {
                        // There's a range from the lowest of the first range to the lowest of the second ranges
                        result.push(SymbolRange::new(might_overlap.lowest.clone(), overlap_with.lowest.prev()));

                        // Chop out the bit we just pushed from might_overlap and push back both ranges
                        // Maintain sort order depending on highest (as lowest for both ranges will be equal)
                        if overlap_with.highest > might_overlap.highest {
                            to_process.push(overlap_with.clone());
                            to_process.push(SymbolRange::new(overlap_with.lowest, might_overlap.highest));
                        } else {
                            to_process.push(SymbolRange::new(overlap_with.lowest.clone(), might_overlap.highest));
                            to_process.push(overlap_with);
                        }
                    }
                }
            } else {
                // Last range should never overlap
                result.push(might_overlap);
            }
        }

        // Ranges should already be sorted as we worked from left to right
        SymbolMap { ranges: result }
    }
}

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

    #[test]
    fn can_lookup_overlapping_ranges() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let bottom = map.find_overlapping_ranges(&SymbolRange::new(0, 1));
        let all    = map.find_overlapping_ranges(&SymbolRange::new(1, 3));
        let top    = map.find_overlapping_ranges(&SymbolRange::new(6, 6));

        assert!(bottom == vec![&SymbolRange::new(0, 4)]);
        assert!(all == vec![&SymbolRange::new(0, 4), &SymbolRange::new(2, 5), &SymbolRange::new(3, 6)]);
        assert!(top == vec![&SymbolRange::new(3, 6)]);
    }

    #[test]
    fn can_lookup_mid_range() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(5, 10));
        map.add_range(&SymbolRange::new(11, 15));

        let mid = map.find_overlapping_ranges(&SymbolRange::new(1, 3));

        assert!(mid == vec![&SymbolRange::new(0, 4)]);
    }

    #[test]
    fn works_with_duplicate_lower_values() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 2));
        map.add_range(&SymbolRange::new(0, 3));

        let all    = map.find_overlapping_ranges(&SymbolRange::new(0, 1));

        assert!(all == vec![&SymbolRange::new(0, 2), &SymbolRange::new(0, 3)]);
    }

    #[test]
    fn can_get_non_overlapping_map() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 1), &SymbolRange::new(2, 2), &SymbolRange::new(3, 4), &SymbolRange::new(5, 5), &SymbolRange::new(6, 6)]);
    }

    #[test]
    fn can_get_non_overlapping_map_with_single_symbols() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 5));
        map.add_range(&SymbolRange::new(2, 2));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 1), &SymbolRange::new(2, 2), &SymbolRange::new(3, 5), &SymbolRange::new(6, 6)]);
    }

    #[test]
    fn can_deal_with_duplicate_symbols() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 5));
        map.add_range(&SymbolRange::new(2, 2));
        map.add_range(&SymbolRange::new(3, 6));

        map.add_range(&SymbolRange::new(0, 5));
        map.add_range(&SymbolRange::new(2, 2));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 1), &SymbolRange::new(2, 2), &SymbolRange::new(3, 5), &SymbolRange::new(6, 6)]);
    }

    #[test]
    fn generate_correctly_for_single_symbol() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 0));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 10));

        assert!(all == vec![&SymbolRange::new(0, 0)]);
    }

    #[test]
    fn generate_correctly_for_two_single_symbols() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 0));
        map.add_range(&SymbolRange::new(1, 1));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 10));

        assert!(all == vec![&SymbolRange::new(0, 0), &SymbolRange::new(1, 1)]);
    }

    #[test]
    fn generate_correctly_for_non_overlapping_ranges() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 1));
        map.add_range(&SymbolRange::new(2, 4));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 10));

        assert!(all == vec![&SymbolRange::new(0, 1), &SymbolRange::new(2, 4)]);
    }

    #[test]
    fn generate_correctly_for_single_overlap() {
        let mut map = SymbolMap::new();

        // Here the symbol '5' is in both ranges, so we should generate it as a seperate range in the non-overlapping version
        map.add_range(&SymbolRange::new(0, 5));
        map.add_range(&SymbolRange::new(5, 10));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 10));

        assert!(all == vec![&SymbolRange::new(0, 4), &SymbolRange::new(5,5), &SymbolRange::new(6, 10)]);
    }

    #[test]
    fn can_get_non_overlapping_map_with_single_symbols_at_start() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 0));
        map.add_range(&SymbolRange::new(0, 1));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 0), &SymbolRange::new(1, 1)]);
    }

    #[test]
    fn can_get_non_overlapping_map_with_single_symbols_at_start_and_gap() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 0));
        map.add_range(&SymbolRange::new(0, 1));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 0), &SymbolRange::new(1, 1), &SymbolRange::new(3, 6)]);
    }
}
<|endoftext|>


<commit_before>use crate::Msg;
use seed::prelude::*;
use web_sys::{HtmlInputElement};

fn trial_divide(n: u64, max: u64) -> u64 {
    // Trial divides the positive integer n by the primes from 2 to max
    // Returns the first prime divisor found, or 0 if none found
    // Note: if n < max^2 is a prime, then n will be returned.
    if n % 2 == 0 {
        2
    } else if n % 3 == 0 {
        3
    } else {
        // No need to go past the square root of our number
        let sqrt: u64 = (n as f64).sqrt().floor() as u64;
        let stop = if sqrt > max { max } else { sqrt };
        // Okay, lets "wheel factor" alternately adding 2 and 4
        let mut di = 2;
        let mut i = 5;
        while i <= stop {
            if n % i == 0 {
                return i;
            }
            i += di;
            di = 6 - di;
        }
        if n >= max * max {
            0
        } else {
            n
        }
    }
}

// modadd(a,b,N) finds a+b (mod N) where a, b, and N can be
// up to (2^53-1)/2.  Might up this to 2^53-1 eventually...
fn modadd(a: u64, b: u64, n: u64) -> u64 {
    // When the integers a, b satisfy a+b > 2^53-1, then (a+b)%N is wrong
    // so we add this routine to allow us to reach a, b = 2^53-1.
    if a + b > 9007199254740991 {
        // Could reduce a and b (mod N) here, but assuming that has already been done
        // won't hurt if not... subtract 2^52 from one, 2^52-1 from the other and the
        // add it back modulo N (MaxInt+1)
        let t = ((a - 4503599627370496) + (b - 4503599627370495)) % n;
        return t + (9007199254740991 % n);
    }
    // Usual case: a + b is not too large:
    (a + b) % n
}

fn modmult(mut a: u64, mut b: u64, n: u64) -> u64 {
    if a > n {
        a = a % n;
    }
    if b > n {
        b = b % n;
    }
    if a * b <= 9007199254740991 {
        return (a * b) % n;
    } else {
        if b > a {
            return modmult(b.clone(), a, n);
        }

        // Right to left binary multiplication
        let mut t = 0;
        let mut f = a;
        while b > 1 {
            if (b & 1) == 1 {
                t = modadd(t, f, n);
            }
            //TODO: bitshift might be cleaner and faster
            b = (b as f64 / 2.0).floor() as u64;
            f = modadd(f, f, n);
        }
        t = modadd(t, f, n);
        return t;
    }
}

// modpow(a,exp,N) finds a^exp (mod N) where a, b, and N are
// limited by modmult
fn modpow(a: u64, mut exp: u64, n: u64) -> u64 {
    if exp == 0 {
        return 1;
    }

    // Right to left binary exponentiation
    let mut t = 1;
    let mut f = a;
    while exp > 1 {
        if (exp & 1) == 1 {
            // if exponent is odd
            t = modmult(t, f, n);
        }
        exp = (exp as f64 / 2.0).floor() as u64;
        f = modmult(f, f, n);
    }
    t = modmult(t, f, n);
    return t;
}

// sprp(N,a) checks if N (odd!) is a strong probable prime base a
// (returns true or false)
fn sprp(n: u64, a: u64) -> bool {
    let mut d = n - 1;
    let mut s = 1; // Assumes n is odd!
    loop {
        if d % 2 == 1 {
            break;
        }
        d /= 2;
        s += 1;
    }
    // Now n-1 = d*2^s with d odd
    let mut b = modpow(a, d, n);
    if b == 1 {
        return true;
    }
    if b + 1 == n {
        return true;
    }
    while s > 1 {
        b = modmult(b, b, n);
        if b + 1 == n {
            return true;
        }
        s = s - 1;
    }
    return false;
}

pub struct Check {
    pub is_prime: bool,
    pub result: String,
}

pub fn check(input: String) -> Check {
    let trial_limit = 1300; // Should be bigger, like 10000
    let n: u64 = input.parse::<u64>().unwrap();
    let result;
    let mut is_prime = false;

    if n > 9007199254740991 {
        result = "Sorry, this routine will only handle integers below 9007199254740991.".to_owned();
    } else if n == 1 {
        result = "The number 1 is neither prime or composite (it is the multiplicative identity)."
            .to_owned();
    } else if n < 1 {
        result =
            "We usually restrict the terms prime and composite to positive integers".to_owned();
    } else {
        // Okay, n is of a resonable size, lets trial divide
        let i = trial_divide(n, trial_limit);
        if i > 0 && i != n {
            result = format!("{} is not a prime! It is {} * {}", n, i, n / i);
        } else if n < trial_limit * trial_limit {
            result = format!("{} is a (proven) prime!", n);
            is_prime = true;
        } else if sprp(n, 2)
            && sprp(n, 3)
            && sprp(n, 5)
            && sprp(n, 7)
            && sprp(n, 11)
            && sprp(n, 13)
            && sprp(n, 17)
        {
            // Some of these tests are unnecessary for small numbers, but for
            // small numbers they are quick anyway.
            if n < 341550071728321 {
                result = format!("{} is a (proven) prime.", n);
                is_prime = true;
            } else if n == 341550071728321 {
                result = format!("{} is not a prime! It is 10670053 * 32010157.", n);
            } else {
                result = format!(
                    "{} is probably a prime (it is a sprp bases 2, 3, 5, 7, 11, 13 and  17).",
                    n
                );
                is_prime = true;
            };
        } else {
            result = format!(
                "{} is (proven) composite (failed sprp test base {}).",
                n, 17
            );
        };
    };

    return Check{is_prime, result};
}

pub fn listy(start_number: u64, number_of_primes: u64) -> String {
    let mut i = 0;
    let mut j = start_number;
    let mut list: String = "".to_string();
    while i < number_of_primes {
        let result = check(j.to_string());
        if result.is_prime == true {
            list = list + &result.result + "\n";
            i += 1;
        }
        j += 1;
    }
    list
}

pub fn go_crunch() -> () {
    let window = web_sys::window().expect("no global `window` exists");
    let document = window.document().expect("should have a document on window");

    let el_input_value = document
        .get_element_by_id("input")
        .unwrap()
        .dyn_into::<HtmlInputElement>()
        .unwrap()
        .value();
    let el_output_textarea = document
        .get_element_by_id("prime_check_output")
        .expect("missing output textarea");
    el_output_textarea.set_inner_html(&check(el_input_value).result);
    ()
}

pub fn go_list() {
    let window = web_sys::window().expect("no global `window` exists");
    let document = window.document().expect("should have a document on window");

    let el_start_value = document
        .get_element_by_id("start")
        .unwrap()
        .dyn_into::<HtmlInputElement>()
        .unwrap()
        .value();
    let el_primes_value = document
        .get_element_by_id("primes")
        .unwrap()
        .dyn_into::<HtmlInputElement>()
        .unwrap()
        .value();
    let el_output_textarea = document
        .get_element_by_id("prime_check_list_output")
        .expect("missing output textarea");
    el_output_textarea.set_inner_html(&listy(
        el_start_value.parse::<u64>().unwrap(),
        el_primes_value.parse::<u64>().unwrap(),
    ));
    ()
}

pub fn render() -> Node<Msg> {
    div![
        h1!["Primality Test, Calculate Primes"],
        br![],
        br![],
        br![],
        table![
            attrs! {At::Class => "text", At::Width => "300", At::Style => "border:1px solid #444; background-color:#e0faed"},
            tr![td![
                attrs! {At::Style => "padding: 10px"},
                form![
                    attrs! {At::Id => "primetest", At::OnSubmit => "return false"},
                    "Tool is limited to checking numbers upto 16 digits.",
                    br![],
                    br![],
                    "Is ",
                    input![
                        attrs! {At::Type => "number", At::Size => "19", At::Id => "input", At::Value => "31", At::MaxLength => "16"}
                    ],
                    " prime? ",
                    button![
                        "Check!",
                        mouse_ev("mouseup", move |_event| Msg::PrimalityChecker(go_crunch()))
                    ],
                    br![],
                    br![],
                    textarea![
                        attrs! {At::Id => "prime_check_output", At::Cols => 60, At::Rows => 2, At::Disabled => "disabled"}
                    ]
                ]
            ]]
        ],
        br![],
        br![],
        table![
            attrs! {At::Class => "text", At::Width => "300", At::Style => "border:1px solid #444; background-color:#e0faed"},
            tr![td![
                attrs! {At::Style => "padding: 10px"},
                form![
                    attrs! {At::Id => "primelist", At::OnSubmit => "return false"},
                    "This tool is limited to checking numbers upto 15 digits.",
                    br![],
                    br![],
                    "This will show ",
                    input![
                        attrs! {At::Type => "number", At::Size => "4", At::Id => "primes", At::Value => "5", At::MaxLength => "2"}
                    ],
                    " prime numbers after ",
                    input![
                        attrs! {At::Type => "number", At::Size => "19", At::Id => "start", At::Value => "31", At::MaxLength => "15"}
                    ],
                    " ",
                    button![
                        "Go!",
                        mouse_ev("mouseup", move |_event| Msg::PrimalityChecker(go_list()))
                    ],
                    br![],
                    br![],
                    textarea![
                        attrs! {At::Id => "prime_check_list_output", At::Cols => 60, At::Rows => 10, At::Disabled => "disabled"}
                    ]
                ]
            ]]
        ]
    ]
}

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

    #[test]
    fn trial_divide_test() {
        assert_eq!(trial_divide(2, 2), 2);
        assert_eq!(trial_divide(3, 4), 3);
        assert_eq!(trial_divide(30, 10000), 2);
        assert_eq!(trial_divide(7777771, 10000), 29);
        assert_eq!(trial_divide(7777771111111111, 10000), 11);
        //in the case of a prime
        assert_eq!(trial_divide(777777111111113, 10000), 0);
    }

    #[test]
    fn sprp_test() {
        assert_eq!(sprp(27, 5), false);
        assert_eq!(sprp(31, 7), true);
        assert_eq!(sprp(217, 7), false);
        assert_eq!(sprp(19, 13), true);
    }

    #[test]
    fn mod_pow_test() {
        assert_eq!(modpow(6,3,11), 7);
        assert_eq!(modpow(113,7,11), 9);
    }

    #[test]
    fn mod_mult_test() {
        assert_eq!(modmult(3,3,4), 1);
        assert_eq!(modmult(110,4,7), 6);
    }
}
<commit_msg>form -> div<commit_after>use crate::Msg;
use seed::prelude::*;
use web_sys::{HtmlInputElement};

fn trial_divide(n: u64, max: u64) -> u64 {
    // Trial divides the positive integer n by the primes from 2 to max
    // Returns the first prime divisor found, or 0 if none found
    // Note: if n < max^2 is a prime, then n will be returned.
    if n % 2 == 0 {
        2
    } else if n % 3 == 0 {
        3
    } else {
        // No need to go past the square root of our number
        let sqrt: u64 = (n as f64).sqrt().floor() as u64;
        let stop = if sqrt > max { max } else { sqrt };
        // Okay, lets "wheel factor" alternately adding 2 and 4
        let mut di = 2;
        let mut i = 5;
        while i <= stop {
            if n % i == 0 {
                return i;
            }
            i += di;
            di = 6 - di;
        }
        if n >= max * max {
            0
        } else {
            n
        }
    }
}

// modadd(a,b,N) finds a+b (mod N) where a, b, and N can be
// up to (2^53-1)/2.  Might up this to 2^53-1 eventually...
fn modadd(a: u64, b: u64, n: u64) -> u64 {
    // When the integers a, b satisfy a+b > 2^53-1, then (a+b)%N is wrong
    // so we add this routine to allow us to reach a, b = 2^53-1.
    if a + b > 9007199254740991 {
        // Could reduce a and b (mod N) here, but assuming that has already been done
        // won't hurt if not... subtract 2^52 from one, 2^52-1 from the other and the
        // add it back modulo N (MaxInt+1)
        let t = ((a - 4503599627370496) + (b - 4503599627370495)) % n;
        return t + (9007199254740991 % n);
    }
    // Usual case: a + b is not too large:
    (a + b) % n
}

fn modmult(mut a: u64, mut b: u64, n: u64) -> u64 {
    if a > n {
        a = a % n;
    }
    if b > n {
        b = b % n;
    }
    if a * b <= 9007199254740991 {
        return (a * b) % n;
    } else {
        if b > a {
            return modmult(b.clone(), a, n);
        }

        // Right to left binary multiplication
        let mut t = 0;
        let mut f = a;
        while b > 1 {
            if (b & 1) == 1 {
                t = modadd(t, f, n);
            }
            //TODO: bitshift might be cleaner and faster
            b = (b as f64 / 2.0).floor() as u64;
            f = modadd(f, f, n);
        }
        t = modadd(t, f, n);
        return t;
    }
}

// modpow(a,exp,N) finds a^exp (mod N) where a, b, and N are
// limited by modmult
fn modpow(a: u64, mut exp: u64, n: u64) -> u64 {
    if exp == 0 {
        return 1;
    }

    // Right to left binary exponentiation
    let mut t = 1;
    let mut f = a;
    while exp > 1 {
        if (exp & 1) == 1 {
            // if exponent is odd
            t = modmult(t, f, n);
        }
        exp = (exp as f64 / 2.0).floor() as u64;
        f = modmult(f, f, n);
    }
    t = modmult(t, f, n);
    return t;
}

// sprp(N,a) checks if N (odd!) is a strong probable prime base a
// (returns true or false)
fn sprp(n: u64, a: u64) -> bool {
    let mut d = n - 1;
    let mut s = 1; // Assumes n is odd!
    loop {
        if d % 2 == 1 {
            break;
        }
        d /= 2;
        s += 1;
    }
    // Now n-1 = d*2^s with d odd
    let mut b = modpow(a, d, n);
    if b == 1 {
        return true;
    }
    if b + 1 == n {
        return true;
    }
    while s > 1 {
        b = modmult(b, b, n);
        if b + 1 == n {
            return true;
        }
        s = s - 1;
    }
    return false;
}

pub struct Check {
    pub is_prime: bool,
    pub result: String,
}

pub fn check(input: String) -> Check {
    let trial_limit = 1300; // Should be bigger, like 10000
    let n: u64 = input.parse::<u64>().unwrap();
    let result;
    let mut is_prime = false;

    if n > 9007199254740991 {
        result = "Sorry, this routine will only handle integers below 9007199254740991.".to_owned();
    } else if n == 1 {
        result = "The number 1 is neither prime or composite (it is the multiplicative identity)."
            .to_owned();
    } else if n < 1 {
        result =
            "We usually restrict the terms prime and composite to positive integers".to_owned();
    } else {
        // Okay, n is of a resonable size, lets trial divide
        let i = trial_divide(n, trial_limit);
        if i > 0 && i != n {
            result = format!("{} is not a prime! It is {} * {}", n, i, n / i);
        } else if n < trial_limit * trial_limit {
            result = format!("{} is a (proven) prime!", n);
            is_prime = true;
        } else if sprp(n, 2)
            && sprp(n, 3)
            && sprp(n, 5)
            && sprp(n, 7)
            && sprp(n, 11)
            && sprp(n, 13)
            && sprp(n, 17)
        {
            // Some of these tests are unnecessary for small numbers, but for
            // small numbers they are quick anyway.
            if n < 341550071728321 {
                result = format!("{} is a (proven) prime.", n);
                is_prime = true;
            } else if n == 341550071728321 {
                result = format!("{} is not a prime! It is 10670053 * 32010157.", n);
            } else {
                result = format!(
                    "{} is probably a prime (it is a sprp bases 2, 3, 5, 7, 11, 13 and  17).",
                    n
                );
                is_prime = true;
            };
        } else {
            result = format!(
                "{} is (proven) composite (failed sprp test base {}).",
                n, 17
            );
        };
    };

    return Check{is_prime, result};
}

pub fn listy(start_number: u64, number_of_primes: u64) -> String {
    let mut i = 0;
    let mut j = start_number;
    let mut list: String = "".to_string();
    while i < number_of_primes {
        let result = check(j.to_string());
        if result.is_prime == true {
            list = list + &result.result + "\n";
            i += 1;
        }
        j += 1;
    }
    list
}

pub fn go_crunch() -> () {
    let window = web_sys::window().expect("no global `window` exists");
    let document = window.document().expect("should have a document on window");

    let el_input_value = document
        .get_element_by_id("input")
        .unwrap()
        .dyn_into::<HtmlInputElement>()
        .unwrap()
        .value();
    let el_output_textarea = document
        .get_element_by_id("prime_check_output")
        .expect("missing output textarea");
    el_output_textarea.set_inner_html(&check(el_input_value).result);
    ()
}

pub fn go_list() {
    let window = web_sys::window().expect("no global `window` exists");
    let document = window.document().expect("should have a document on window");

    let el_start_value = document
        .get_element_by_id("start")
        .unwrap()
        .dyn_into::<HtmlInputElement>()
        .unwrap()
        .value();
    let el_primes_value = document
        .get_element_by_id("primes")
        .unwrap()
        .dyn_into::<HtmlInputElement>()
        .unwrap()
        .value();
    let el_output_textarea = document
        .get_element_by_id("prime_check_list_output")
        .expect("missing output textarea");
    el_output_textarea.set_inner_html(&listy(
        el_start_value.parse::<u64>().unwrap(),
        el_primes_value.parse::<u64>().unwrap(),
    ));
    ()
}

pub fn render() -> Node<Msg> {
    div![
        h1!["Primality Test, Calculate Primes"],
        br![],
        br![],
        br![],
        table![
            attrs! {At::Class => "text", At::Width => "300", At::Style => "border:1px solid #444; background-color:#e0faed"},
            tr![td![
                attrs! {At::Style => "padding: 10px"},
                div![
                    attrs! {At::Id => "primetest"},
                    "Tool is limited to checking numbers upto 16 digits.",
                    br![],
                    br![],
                    "Is ",
                    input![
                        attrs! {At::Type => "number", At::Size => "19", At::Id => "input", At::Value => "31", At::MaxLength => "16"}
                    ],
                    " prime? ",
                    button![
                        "Check!",
                        mouse_ev("mouseup", move |_event| Msg::PrimalityChecker(go_crunch()))
                    ],
                    br![],
                    br![],
                    textarea![
                        attrs! {At::Id => "prime_check_output", At::Cols => 60, At::Rows => 2, At::Disabled => "disabled"}
                    ]
                ]
            ]]
        ],
        br![],
        br![],
        table![
            attrs! {At::Class => "text", At::Width => "300", At::Style => "border:1px solid #444; background-color:#e0faed"},
            tr![td![
                attrs! {At::Style => "padding: 10px"},
                div![
                    attrs! {At::Id => "primelist"},
                    "This tool is limited to checking numbers upto 15 digits.",
                    br![],
                    br![],
                    "This will show ",
                    input![
                        attrs! {At::Type => "number", At::Size => "4", At::Id => "primes", At::Value => "5", At::MaxLength => "2"}
                    ],
                    " prime numbers after ",
                    input![
                        attrs! {At::Type => "number", At::Size => "19", At::Id => "start", At::Value => "31", At::MaxLength => "15"}
                    ],
                    " ",
                    button![
                        "Go!",
                        mouse_ev("mouseup", move |_event| Msg::PrimalityChecker(go_list()))
                    ],
                    br![],
                    br![],
                    textarea![
                        attrs! {At::Id => "prime_check_list_output", At::Cols => 60, At::Rows => 10, At::Disabled => "disabled"}
                    ]
                ]
            ]]
        ]
    ]
}

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

    #[test]
    fn trial_divide_test() {
        assert_eq!(trial_divide(2, 2), 2);
        assert_eq!(trial_divide(3, 4), 3);
        assert_eq!(trial_divide(30, 10000), 2);
        assert_eq!(trial_divide(7777771, 10000), 29);
        assert_eq!(trial_divide(7777771111111111, 10000), 11);
        //in the case of a prime
        assert_eq!(trial_divide(777777111111113, 10000), 0);
    }

    #[test]
    fn sprp_test() {
        assert_eq!(sprp(27, 5), false);
        assert_eq!(sprp(31, 7), true);
        assert_eq!(sprp(217, 7), false);
        assert_eq!(sprp(19, 13), true);
    }

    #[test]
    fn mod_pow_test() {
        assert_eq!(modpow(6,3,11), 7);
        assert_eq!(modpow(113,7,11), 9);
    }

    #[test]
    fn mod_mult_test() {
        assert_eq!(modmult(3,3,4), 1);
        assert_eq!(modmult(110,4,7), 6);
    }
}
<|endoftext|>


<commit_before>#![cfg(feature = "compiletest")]

use compiletest_rs as compiletest;

#[test]
fn ui() {
    let config = compiletest::Config {
        mode: compiletest::common::Mode::Ui,
        src_base: std::path::PathBuf::from("tests/ui"),
        target_rustcflags: Some(String::from("\
            --edition=2018 \
            -L deps/target/debug/deps \
            -Z unstable-options \
            --extern serde_derive \
        ")),
        ..Default::default()
    };

    compiletest::run_tests(&config);
}
<commit_msg>Format with rustfmt 2018-12-10<commit_after>#![cfg(feature = "compiletest")]

use compiletest_rs as compiletest;

#[test]
fn ui() {
    let config = compiletest::Config {
        mode: compiletest::common::Mode::Ui,
        src_base: std::path::PathBuf::from("tests/ui"),
        target_rustcflags: Some(String::from(
            "\
             --edition=2018 \
             -L deps/target/debug/deps \
             -Z unstable-options \
             --extern serde_derive \
             ",
        )),
        ..Default::default()
    };

    compiletest::run_tests(&config);
}
<|endoftext|>


<commit_before>#![allow(unused_variables,unused_must_use)]
extern crate sozu_lib as sozu;
#[macro_use] extern crate sozu_command_lib as sozu_command;
extern crate time;
extern crate tiny_http;
extern crate ureq;

use std::thread;
use sozu_command::proxy;
use sozu_command::channel::Channel;
use sozu_command::proxy::LoadBalancingParams;
use sozu_command::logging::{Logger,LoggerBackend};
use tiny_http::{Server, Response};
use std::{
    io::{stdout, Read, Write},
    net::{TcpListener,TcpStream,ToSocketAddrs},
    time::Duration,
    str
};

#[test]
fn test() {
    Logger::init("EXAMPLE".to_string(), "debug", LoggerBackend::Stdout(stdout()), None);

    info!("starting up");

    let config = proxy::HttpListener {
        front: "127.0.0.1:8080".parse().expect("could not parse address"),
        ..Default::default()
    };

    let (mut command, channel) = Channel::generate(1000, 10000).expect("should create a channel");

    let jg = thread::spawn(move || {
        Logger::init("SOZU".to_string(), "info", LoggerBackend::Stdout(stdout()), None);
        let max_buffers = 20;
        let buffer_size = 16384;
        sozu::http::start(config, channel, max_buffers, buffer_size);
    });

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_Status"),
        order: proxy::ProxyRequestData::Status
    });

    // wait for sozu to start and answer
    info!("Status -> {:?}", command.read_message());

    let agent = ureq::AgentBuilder::new()
        .resolver(|addr: &str| match addr {
            "example.com:8080" => Ok(vec![([127,0,0,1], 8080).into()]),
            addr => addr.to_socket_addrs().map(Iterator::collect),
        })
    .build();

    info!("expecting 404");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(404, res) => {
                assert_eq!(res.header("connection"), Some("close"));
            },
            e => panic!("invalid response: {:?}", e),
        };

    let http_front = proxy::HttpFront {
        app_id:     String::from("test"),
        address:    "127.0.0.1:8080".parse().unwrap(),
        hostname:   String::from("example.com"),
        path_begin: String::from("/"),
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_ABCD"),
        order: proxy::ProxyRequestData::AddHttpFront(http_front)
    });
    println!("HTTP -> {:?}", command.read_message());

    info!("expecting 503");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(503, res) => {
                assert_eq!(res.header("connection"), Some("close"));
            },
            e => panic!("invalid response: {:?}", e),
        };

    let http_backend = proxy::Backend {
        app_id:                    String::from("test"),
        backend_id:                String::from("test-0"),
        address:                   "127.0.0.1:1024".parse().unwrap(),
        load_balancing_parameters: Some(LoadBalancingParams::default()),
        sticky_id:                 None,
        backup:                    None,
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH"),
        order: proxy::ProxyRequestData::AddBackend(http_backend)
    });

    println!("HTTP -> {:?}", command.read_message());

    info!("sending invalid request, expecting 400");
    let mut client = TcpStream::connect(("127.0.0.1", 8080)).expect("could not parse address");
    // 1 seconds of timeout
    client.set_read_timeout(Some(Duration::new(1,0)));

    let w = client.write(&b"HELLO\r\n\r\n"[..]);
    println!("http client write: {:?}", w);

    let expected_answer = "HTTP/1.1 400 Bad Request\r\nCache-Control: no-cache\r\nConnection: close\r\n\r\n";
    let mut buffer = [0;4096];
    let mut index = 0;

    let r = client.read(&mut buffer[..]);
    println!("http client read: {:?}", r);
    match r {
        Err(e)      => assert!(false, "client request should not fail. Error: {:?}",e),
        Ok(sz) => {
            index += sz;
            let answer = str::from_utf8(&buffer[..index]).expect("could not make string from buffer");
            println!("Response: {}", answer);
        }
    }

    let answer = str::from_utf8(&buffer[..index]).expect("could not make string from buffer");
    println!("Response: {}", answer);
    assert_eq!(answer, expected_answer);

    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:1024").expect("could not parse address");
        let mut stream = listener.incoming().next().unwrap().unwrap();
        let response = b"TEST\r\n\r\n";
        stream.write(&response[..]).unwrap();
    });

    info!("expecting 502");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(502, res) => {
                assert_eq!(res.status_text(), "Bad Gateway");
            },
            e => panic!("invalid response: {:?}", e),
        };

    start_server(1024);

    info!("expecting 200");
    let res = agent
        .get("http://example.com:8080/")
        .call().unwrap();
    assert_eq!(res.status(), 200);

    //let _ = jg.join();
    info!("good bye");
}

fn start_server(port: u16) {
    thread::spawn(move|| {
        let server = Server::http(&format!("127.0.0.1:{}", port)).expect("could not create server");
        info!("starting web server in port {}", port);

        for request in server.incoming_requests() {
            println!("backend web server got request -> method: {:?}, url: {:?}, headers: {:?}",
                     request.method(),
                     request.url(),
                     request.headers()
                    );

            let response = Response::from_string("hello world");
            request.respond(response).unwrap();
            println!("backend web server sent response");
            println!("server session stopped");
        }

        println!("server on port {} closed", port);
    });
}
<commit_msg>change the test port<commit_after>#![allow(unused_variables,unused_must_use)]
extern crate sozu_lib as sozu;
#[macro_use] extern crate sozu_command_lib as sozu_command;
extern crate time;
extern crate tiny_http;
extern crate ureq;

use std::thread;
use sozu_command::proxy;
use sozu_command::channel::Channel;
use sozu_command::proxy::LoadBalancingParams;
use sozu_command::logging::{Logger,LoggerBackend};
use tiny_http::{Server, Response};
use std::{
    io::{stdout, Read, Write},
    net::{TcpListener,TcpStream,ToSocketAddrs},
    time::Duration,
    str
};

#[test]
fn test() {
    Logger::init("EXAMPLE".to_string(), "debug", LoggerBackend::Stdout(stdout()), None);

    info!("starting up");

    let config = proxy::HttpListener {
        front: "127.0.0.1:8080".parse().expect("could not parse address"),
        ..Default::default()
    };

    let (mut command, channel) = Channel::generate(1000, 10000).expect("should create a channel");

    let jg = thread::spawn(move || {
        Logger::init("SOZU".to_string(), "info", LoggerBackend::Stdout(stdout()), None);
        let max_buffers = 20;
        let buffer_size = 16384;
        sozu::http::start(config, channel, max_buffers, buffer_size);
    });

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_Status"),
        order: proxy::ProxyRequestData::Status
    });

    // wait for sozu to start and answer
    info!("Status -> {:?}", command.read_message());

    let agent = ureq::AgentBuilder::new()
        .resolver(|addr: &str| match addr {
            "example.com:8080" => Ok(vec![([127,0,0,1], 8080).into()]),
            addr => addr.to_socket_addrs().map(Iterator::collect),
        })
    .build();

    info!("expecting 404");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(404, res) => {
                assert_eq!(res.header("connection"), Some("close"));
            },
            e => panic!("invalid response: {:?}", e),
        };

    let http_front = proxy::HttpFront {
        app_id:     String::from("test"),
        address:    "127.0.0.1:8080".parse().unwrap(),
        hostname:   String::from("example.com"),
        path_begin: String::from("/"),
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_ABCD"),
        order: proxy::ProxyRequestData::AddHttpFront(http_front)
    });
    println!("HTTP -> {:?}", command.read_message());

    info!("expecting 503");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(503, res) => {
                assert_eq!(res.header("connection"), Some("close"));
            },
            e => panic!("invalid response: {:?}", e),
        };

    let http_backend = proxy::Backend {
        app_id:                    String::from("test"),
        backend_id:                String::from("test-0"),
        address:                   "127.0.0.1:2048".parse().unwrap(),
        load_balancing_parameters: Some(LoadBalancingParams::default()),
        sticky_id:                 None,
        backup:                    None,
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH"),
        order: proxy::ProxyRequestData::AddBackend(http_backend)
    });

    println!("HTTP -> {:?}", command.read_message());

    info!("sending invalid request, expecting 400");
    let mut client = TcpStream::connect(("127.0.0.1", 8080)).expect("could not parse address");
    // 1 seconds of timeout
    client.set_read_timeout(Some(Duration::new(1,0)));

    let w = client.write(&b"HELLO\r\n\r\n"[..]);
    println!("http client write: {:?}", w);

    let expected_answer = "HTTP/1.1 400 Bad Request\r\nCache-Control: no-cache\r\nConnection: close\r\n\r\n";
    let mut buffer = [0;4096];
    let mut index = 0;

    let r = client.read(&mut buffer[..]);
    println!("http client read: {:?}", r);
    match r {
        Err(e)      => assert!(false, "client request should not fail. Error: {:?}",e),
        Ok(sz) => {
            index += sz;
            let answer = str::from_utf8(&buffer[..index]).expect("could not make string from buffer");
            println!("Response: {}", answer);
        }
    }

    let answer = str::from_utf8(&buffer[..index]).expect("could not make string from buffer");
    println!("Response: {}", answer);
    assert_eq!(answer, expected_answer);

    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        let mut stream = listener.incoming().next().unwrap().unwrap();
        let response = b"TEST\r\n\r\n";
        stream.write(&response[..]).unwrap();
    });

    info!("expecting 502");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(502, res) => {
                assert_eq!(res.status_text(), "Bad Gateway");
            },
            e => panic!("invalid response: {:?}", e),
        };

    start_server(2048);

    info!("expecting 200");
    let res = agent
        .get("http://example.com:8080/")
        .call().unwrap();
    assert_eq!(res.status(), 200);

    //let _ = jg.join();
    info!("good bye");
}

fn start_server(port: u16) {
    thread::spawn(move|| {
        let server = Server::http(&format!("127.0.0.1:{}", port)).expect("could not create server");
        info!("starting web server in port {}", port);

        for request in server.incoming_requests() {
            println!("backend web server got request -> method: {:?}, url: {:?}, headers: {:?}",
                     request.method(),
                     request.url(),
                     request.headers()
                    );

            let response = Response::from_string("hello world");
            request.respond(response).unwrap();
            println!("backend web server sent response");
            println!("server session stopped");
        }

        println!("server on port {} closed", port);
    });
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate regex;

static VISIBLE_ALIAS_HELP: &'static str = "clap-test 2.6

USAGE:
    clap-test [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    help    Prints this message or the help of the given subcommand(s)
    test    Some help [aliases: dongle, done]";

static INVISIBLE_ALIAS_HELP: &'static str = "clap-test 2.6

USAGE:
    clap-test [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    help    Prints this message or the help of the given subcommand(s)
    test    Some help";

#[cfg(feature = "suggestions")]
static DYM: &'static str = "error: The subcommand 'subcm' wasn't recognized
\tDid you mean 'subcmd'?

If you believe you received this message in error, try re-running with 'clap-test -- subcm'

USAGE:
    clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND]

For more information try --help";

#[cfg(feature = "suggestions")]
static DYM2: &'static str = "error: Found argument '--subcm' which wasn't expected, or isn't valid in this context
\tDid you mean to put '--subcmdarg' after the subcommand 'subcmd'?

USAGE:
    clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND]

For more information try --help";

#[cfg(test)]
mod tests {
    include!("../clap-test.rs");
    use clap;
    use clap::{App, Arg, SubCommand, ErrorKind, AppSettings};

    fn setup_app_with_globals_and_subcommands<'a, 'b>() -> clap::App<'a, 'b> {
        let global_arg = Arg::with_name("GLOBAL_ARG")
            .long("global-arg")
            .help(
                "Specifies something needed by the subcommands",
            )
            .global(true)
            .takes_value(true);

        let double_sub_command = SubCommand::with_name("outer")
            .subcommand(SubCommand::with_name("run"));

        App::new("globals")
            .setting(AppSettings::PropagateGlobalValuesDown)
            .arg(global_arg)
            .subcommand(double_sub_command)
    }

    fn test_arg_vector(arg_vector : Vec<&str>) {
        let matches = setup_app_with_globals_and_subcommands().get_matches_from(
            arg_vector
        );

        let sub_match = matches.subcommand_matches("outer").expect("could not access subcommand");

        assert_eq!(sub_match.value_of("GLOBAL_ARG").expect("subcommand could not access global arg"),
                    "some_value", "subcommand did not have expected value for global arg");

        let sub_sub_match = sub_match.subcommand_matches("run").expect("could not access inner sub");

        assert_eq!(sub_sub_match.value_of("GLOBAL_ARG").expect("inner subcommand could not access global arg"),
                "some_value", "inner subcommand did not have expected value for global arg");
    }

    #[test]
    fn subcommand_can_access_global_arg_if_global_arg_is_last() {
        test_arg_vector(vec!["globals", "outer", "run", "--global-arg", "some_value"]);
    }

    #[test]
    fn subcommand_can_access_global_arg_if_global_arg_is_first() {
        test_arg_vector(vec!["globals", "--global-arg", "some_value", "outer", "run"]);
    }

    #[test]
    fn subcommand_can_access_global_arg_if_global_arg_is_in_the_middle() {
        test_arg_vector(vec!["globals", "outer",  "--global-arg", "some_value" ,"run"]);
    }

}

<commit_msg>clean up tests and make them ore thorough<commit_after>extern crate clap;
extern crate regex;

static VISIBLE_ALIAS_HELP: &'static str = "clap-test 2.6

USAGE:
    clap-test [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    help    Prints this message or the help of the given subcommand(s)
    test    Some help [aliases: dongle, done]";

static INVISIBLE_ALIAS_HELP: &'static str = "clap-test 2.6

USAGE:
    clap-test [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    help    Prints this message or the help of the given subcommand(s)
    test    Some help";

#[cfg(feature = "suggestions")]
static DYM: &'static str = "error: The subcommand 'subcm' wasn't recognized
\tDid you mean 'subcmd'?

If you believe you received this message in error, try re-running with 'clap-test -- subcm'

USAGE:
    clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND]

For more information try --help";

#[cfg(feature = "suggestions")]
static DYM2: &'static str = "error: Found argument '--subcm' which wasn't expected, or isn't valid in this context
\tDid you mean to put '--subcmdarg' after the subcommand 'subcmd'?

USAGE:
    clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND]

For more information try --help";

#[cfg(test)]
mod tests {
    include!("../clap-test.rs");
    use clap;
    use clap::{App, Arg, SubCommand, ErrorKind, AppSettings};

    fn setup_app_with_globals_and_subcommands<'a, 'b>() -> clap::App<'a, 'b> {
        let global_arg = Arg::with_name("GLOBAL_ARG")
            .long("global-arg")
            .help(
                "Specifies something needed by the subcommands",
            )
            .global(true)
            .takes_value(true);

        let double_sub_command = SubCommand::with_name("outer")
            .subcommand(SubCommand::with_name("run"));

        App::new("myprog")
            .setting(AppSettings::PropagateGlobalValuesDown)
            .arg(global_arg)
            .subcommand(double_sub_command)
    }

    fn first_subcommand_can_access_global(arg_vector : Vec<&str>) {
        let matches = setup_app_with_globals_and_subcommands().get_matches_from(
            arg_vector
        );

        let sub_match = matches.subcommand_matches("outer").expect("could not access subcommand");

        assert_eq!(sub_match.value_of("GLOBAL_ARG").expect("subcommand could not access global arg"),
                    "some_value", "subcommand did not have expected value for global arg");

    }

    fn second_subcommand_can_access_global(arg_vector : Vec<&str>) {
        let matches = setup_app_with_globals_and_subcommands().get_matches_from(
            arg_vector
        );

        let sub_match = matches.subcommand_matches("outer").expect("could not access subcommand");
        let sub_sub_match = sub_match.subcommand_matches("run").expect("could not access inner sub");

        assert_eq!(sub_sub_match.value_of("GLOBAL_ARG").expect("inner subcommand could not access global arg"),
                "some_value", "inner subcommand did not have expected value for global arg");
    }

    #[test]
    fn subcommand_can_access_global_arg_if_global_arg_is_first() {
        // calls propagate zero times, works
        first_subcommand_can_access_global(vec!["myprog", "--global-arg", "some_value", "outer", "run"]);
    }

    #[test]
    fn subcommand_can_access_global_arg_if_global_arg_is_in_the_middle() {
        // calls propagate twice, doesn't work
        first_subcommand_can_access_global(vec!["myprog", "outer",  "--global-arg", "some_value" ,"run"]);
    }

    #[test]
    fn subcommand_can_access_global_arg_if_global_arg_is_last() {
        // calls propagate twice, doesn't work
        first_subcommand_can_access_global(vec!["myprog", "outer", "run", "--global-arg", "some_value"]);
    }

    #[test]
    fn second_subcommand_can_access_global_arg_if_global_arg_is_first() {
        second_subcommand_can_access_global(vec!["myprog", "--global-arg", "some_value", "outer", "run"]);
    }

    #[test]
    fn second_subcommand_can_access_global_arg_if_global_arg_is_in_the_middle() {
        second_subcommand_can_access_global(vec!["myprog", "outer",  "--global-arg", "some_value" ,"run"]);
    }

    #[test]
    fn second_subcommand_can_access_global_arg_if_global_arg_is_last() {
        second_subcommand_can_access_global(vec!["myprog", "outer", "run", "--global-arg", "some_value"]);
    }
}

<|endoftext|>


<commit_before>extern crate piston;
extern crate image;
extern crate graphics;
extern crate sdl2_window;
extern crate opengl_graphics;

use opengl_graphics::{ GlGraphics, OpenGL, Texture };
use sdl2_window::Sdl2Window;
use image::GenericImage;
use piston::input::{ Button, MouseButton };
use piston::window::{ WindowSettings, Size };
use piston::event::*;

fn main() {
    let opengl = OpenGL::_3_2;
    let (width, height) = (300, 300);
    let window = Sdl2Window::new(
        opengl,
        WindowSettings::new(
            "piston-example-paint".to_string(),
            Size { width: width, height: height }
        )
        .exit_on_esc(true)
    );

    let mut image = image::ImageBuffer::new(width, height);
    let mut draw = false;
    let mut texture = Texture::from_image(&image);
    let ref mut gl = GlGraphics::new(opengl);
    for e in window.events() {
        use piston::event::*;

        if let Some(args) = e.render_args() {
            gl.draw([0, 0, args.width as i32, args.height as i32], |c, gl| {
                graphics::clear([1.0; 4], gl);
                graphics::image(&texture, c.transform, gl);
            });
        };
        if let Some(button) = e.press_args() {
            if button == Button::Mouse(MouseButton::Left) {
                draw = true
            }
        };
        if let Some(button) = e.release_args() {
            if button == Button::Mouse(MouseButton::Left) {
                draw = false
            }
        };
        if draw {
            if let Some(pos) = e.mouse_cursor_args() {
                let (x, y) = (pos[0] as u32, pos[1] as u32);
                if x < width && y < height {
                    image.put_pixel(x, y, image::Rgba([0, 0, 0, 255]));
                    texture.update(&image);
                }
            };
        }
    }
}

<commit_msg>Upgraded "paint" example<commit_after>extern crate piston;
extern crate image;
extern crate graphics;
extern crate sdl2_window;
extern crate opengl_graphics;

use opengl_graphics::{ GlGraphics, OpenGL, Texture };
use sdl2_window::Sdl2Window;
use image::GenericImage;
use piston::input::{ Button, MouseButton };
use piston::window::{ WindowSettings, Size };
use piston::event::*;

fn main() {
    let opengl = OpenGL::_3_2;
    let (width, height) = (300, 300);
    let window = Sdl2Window::new(
        opengl,
        WindowSettings::new(
            "piston-example-paint".to_string(),
            Size { width: width, height: height }
        )
        .exit_on_esc(true)
    );

    let mut image = image::ImageBuffer::new(width, height);
    let mut draw = false;
    let mut texture = Texture::from_image(&image);
    let ref mut gl = GlGraphics::new(opengl);
    for e in window.events() {
        use piston::event::*;

        if let Some(args) = e.render_args() {
            gl.draw(args.viewport(), |c, gl| {
                graphics::clear([1.0; 4], gl);
                graphics::image(&texture, c.transform, gl);
            });
        };
        if let Some(button) = e.press_args() {
            if button == Button::Mouse(MouseButton::Left) {
                draw = true
            }
        };
        if let Some(button) = e.release_args() {
            if button == Button::Mouse(MouseButton::Left) {
                draw = false
            }
        };
        if draw {
            if let Some(pos) = e.mouse_cursor_args() {
                let (x, y) = (pos[0] as u32, pos[1] as u32);
                if x < width && y < height {
                    image.put_pixel(x, y, image::Rgba([0, 0, 0, 255]));
                    texture.update(&image);
                }
            };
        }
    }
}

<|endoftext|>


<commit_before>use crate::error::{Result, ResultExt};
use crate::{Duration, RosMsg, Time};
use lazy_static::lazy_static;
use regex::RegexBuilder;
use ros_message::{DataType, FieldCase, FieldInfo, MessagePath, MessageValue, Msg, Value};
use std::collections::HashMap;
use std::convert::TryInto;
use std::io;

#[derive(Clone, Debug)]
pub struct DynamicMsg {
    msg: Msg,
    dependencies: HashMap<MessagePath, Msg>,
}

fn get_field<'a>(value: &'a MessageValue, name: &str) -> io::Result<&'a Value> {
    value.get(name).ok_or_else(|| {
        io::Error::new(
            io::ErrorKind::Other,
            format!("Missing field `{}` in value", name),
        )
    })
}

impl DynamicMsg {
    pub fn new(message_type: &str, message_definition: &str) -> Result<Self> {
        lazy_static! {
            static ref RE_DESCRIPTOR_MESSAGES_SPLITTER: regex::Regex = RegexBuilder::new("^=+$")
                .multi_line(true)
                .build()
                .expect("Invalid regex `^=+$`");
        }
        let mut message_bodies = RE_DESCRIPTOR_MESSAGES_SPLITTER.split(message_definition);
        let message_src = message_bodies.next().chain_err(|| {
            format!(
                "Message definition for {} is missing main message body",
                message_type,
            )
        })?;
        let msg = Self::parse_msg(message_type, message_src)?;
        let mut dependencies = HashMap::new();
        for message_body in message_bodies {
            let dependency = Self::parse_dependency(message_body)?;
            dependencies.insert(dependency.path().clone(), dependency);
        }

        Ok(DynamicMsg { msg, dependencies })
    }

    pub fn from_headers(headers: HashMap<String, String>) -> Result<Self> {
        let message_type = headers.get("type").chain_err(|| "Missing header `type`")?;
        let message_definition = headers
            .get("message_definition")
            .chain_err(|| "Missing header `message_definition`")?;
        Self::new(message_type, message_definition)
    }

    fn parse_msg(message_type: &str, message_src: &str) -> Result<Msg> {
        let message_path = message_type
            .try_into()
            .chain_err(|| format!("Message type {} is invalid", message_type))?;
        Msg::new(message_path, message_src)
            .chain_err(|| format!("Failed to parse message {}", message_type))
    }

    fn parse_dependency(message_body: &str) -> Result<Msg> {
        lazy_static! {
            static ref RE_DESCRIPTOR_MSG_TYPE: regex::Regex =
                regex::Regex::new(r#"^\s*MSG:\s*(\S+)\s*$"#).unwrap();
        }
        let message_body = message_body.trim();
        let (message_type_line, message_src) = message_body
            .split_once('\n')
            .chain_err(|| "Message dependency is missing type declaration")?;
        let cap = RE_DESCRIPTOR_MSG_TYPE
            .captures(message_type_line)
            .chain_err(|| format!("Failed to parse message type line `{}`", message_type_line))?;
        let message_type = cap
            .get(1)
            .chain_err(|| format!("Failed to parse message type line `{}`", message_type_line))?;
        Self::parse_msg(message_type.as_str(), message_src)
    }

    pub fn encode(&self, value: &MessageValue, mut w: impl io::Write) -> io::Result<()> {
        self.encode_message(&self.msg, value, &mut w)
    }

    pub fn decode(&self, mut r: impl io::Read) -> io::Result<MessageValue> {
        self.decode_message(&self.msg, &mut r)
    }

    fn get_dependency(&self, path: &MessagePath) -> io::Result<&Msg> {
        self.dependencies.get(path).ok_or_else(|| {
            io::Error::new(
                io::ErrorKind::Other,
                format!("Missing message dependency: {}", path),
            )
        })
    }

    fn encode_message(
        &self,
        msg: &Msg,
        value: &MessageValue,
        w: &mut impl io::Write,
    ) -> io::Result<()> {
        for field in msg.fields() {
            match field.case() {
                FieldCase::Const(_) => continue,
                FieldCase::Unit => {
                    let field_value = get_field(value, field.name())?;
                    self.encode_field(field, field_value, w)?;
                }
                FieldCase::Vector => {
                    let field_value = get_field(value, field.name())?;
                    self.encode_field_array(field, field_value, None, w)?;
                }
                FieldCase::Array(l) => {
                    let field_value = get_field(value, field.name())?;
                    self.encode_field_array(field, field_value, Some(*l), w)?;
                }
            }
        }
        Ok(())
    }

    fn encode_field(
        &self,
        field: &FieldInfo,
        value: &Value,
        w: &mut impl std::io::Write,
    ) -> io::Result<()> {
        match (field.datatype(), value) {
            (DataType::Bool, Value::Bool(v)) => v.encode(w),
            (DataType::I8(_), Value::I8(v)) => v.encode(w),
            (DataType::I16, Value::I16(v)) => v.encode(w),
            (DataType::I32, Value::I32(v)) => v.encode(w),
            (DataType::I64, Value::I64(v)) => v.encode(w),
            (DataType::U8(_), Value::U8(v)) => v.encode(w),
            (DataType::U16, Value::U16(v)) => v.encode(w),
            (DataType::U32, Value::U32(v)) => v.encode(w),
            (DataType::U64, Value::U64(v)) => v.encode(w),
            (DataType::F32, Value::F32(v)) => v.encode(w),
            (DataType::F64, Value::F64(v)) => v.encode(w),
            (DataType::String, Value::String(v)) => v.encode(w),
            (DataType::Time, Value::Time(time)) => time.encode(w),
            (DataType::Duration, Value::Duration(duration)) => duration.encode(w),
            (DataType::LocalStruct(name), Value::Message(v)) => {
                let path = MessagePath::new(self.msg.path().package(), name)
                    .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
                let dependency = self.get_dependency(&path)?;
                self.encode_message(dependency, v, w)
            }
            (DataType::RemoteStruct(path), Value::Message(v)) => {
                let dependency = self.get_dependency(path)?;
                self.encode_message(dependency, v, w)
            }
            _ => Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "Passed in dynamic data value does not match message format",
            )),
        }
    }

    fn encode_field_array(
        &self,
        field: &FieldInfo,
        value: &Value,
        array_length: Option<usize>,
        w: &mut impl std::io::Write,
    ) -> io::Result<()> {
        let value = match value {
            Value::Array(v) => v,
            Value::Bool(_)
            | Value::I8(_)
            | Value::I16(_)
            | Value::I32(_)
            | Value::I64(_)
            | Value::U8(_)
            | Value::U16(_)
            | Value::U32(_)
            | Value::U64(_)
            | Value::F32(_)
            | Value::F64(_)
            | Value::String(_)
            | Value::Time { .. }
            | Value::Duration { .. }
            | Value::Message(_) => {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    "Passed in dynamic message field is not an array",
                ));
            }
        };
        match array_length {
            Some(array_length) => {
                if array_length != value.len() {
                    return Err(io::Error::new(
                        io::ErrorKind::InvalidData,
                        "Passed in dynamic message array field has wrong length",
                    ));
                }
            }
            None => {
                (value.len() as u32).encode(w.by_ref())?;
            }
        }
        for value in value {
            self.encode_field(field, value, w.by_ref())?;
        }
        Ok(())
    }

    fn decode_message(&self, msg: &Msg, r: &mut impl io::Read) -> io::Result<MessageValue> {
        let mut output = MessageValue::new();
        for field in msg.fields() {
            let value = match field.case() {
                FieldCase::Const(_) => continue,
                FieldCase::Unit => self.decode_field(field, r)?,
                FieldCase::Vector => self.decode_field_array(field, None, r)?,
                FieldCase::Array(l) => self.decode_field_array(field, Some(*l), r)?,
            };
            output.insert(field.name().into(), value);
        }
        Ok(output)
    }

    fn decode_field(&self, field: &FieldInfo, r: &mut impl io::Read) -> io::Result<Value> {
        Ok(match field.datatype() {
            DataType::Bool => bool::decode(r)?.into(),
            DataType::I8(_) => i8::decode(r)?.into(),
            DataType::I16 => i16::decode(r)?.into(),
            DataType::I32 => i32::decode(r)?.into(),
            DataType::I64 => i64::decode(r)?.into(),
            DataType::U8(_) => u8::decode(r)?.into(),
            DataType::U16 => u16::decode(r)?.into(),
            DataType::U32 => u32::decode(r)?.into(),
            DataType::U64 => u64::decode(r)?.into(),
            DataType::F32 => f32::decode(r)?.into(),
            DataType::F64 => f64::decode(r)?.into(),
            DataType::String => String::decode(r)?.into(),
            DataType::Time => Time::decode(r)?.into(),
            DataType::Duration => Duration::decode(r)?.into(),
            DataType::LocalStruct(name) => {
                let path = MessagePath::new(self.msg.path().package(), name)
                    .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
                let dependency = self.get_dependency(&path)?;
                self.decode_message(dependency, r)?.into()
            }
            DataType::RemoteStruct(path) => {
                let dependency = self.get_dependency(path)?;
                self.decode_message(dependency, r)?.into()
            }
        })
    }

    fn decode_field_array(
        &self,
        field: &FieldInfo,
        array_length: Option<usize>,
        r: &mut impl io::Read,
    ) -> io::Result<Value> {
        let array_length = match array_length {
            Some(v) => v,
            None => u32::decode(r.by_ref())? as usize,
        };
        // TODO: optimize by checking data type only once
        (0..array_length)
            .map(|_| self.decode_field(field, r))
            .collect()
    }
}
<commit_msg>Add getters to dynamic message<commit_after>use crate::error::{Result, ResultExt};
use crate::{Duration, RosMsg, Time};
use lazy_static::lazy_static;
use regex::RegexBuilder;
use ros_message::{DataType, FieldCase, FieldInfo, MessagePath, MessageValue, Msg, Value};
use std::collections::HashMap;
use std::convert::TryInto;
use std::io;

#[derive(Clone, Debug)]
pub struct DynamicMsg {
    msg: Msg,
    dependencies: HashMap<MessagePath, Msg>,
}

fn get_field<'a>(value: &'a MessageValue, name: &str) -> io::Result<&'a Value> {
    value.get(name).ok_or_else(|| {
        io::Error::new(
            io::ErrorKind::Other,
            format!("Missing field `{}` in value", name),
        )
    })
}

impl DynamicMsg {
    pub fn new(message_type: &str, message_definition: &str) -> Result<Self> {
        lazy_static! {
            static ref RE_DESCRIPTOR_MESSAGES_SPLITTER: regex::Regex = RegexBuilder::new("^=+$")
                .multi_line(true)
                .build()
                .expect("Invalid regex `^=+$`");
        }
        let mut message_bodies = RE_DESCRIPTOR_MESSAGES_SPLITTER.split(message_definition);
        let message_src = message_bodies.next().chain_err(|| {
            format!(
                "Message definition for {} is missing main message body",
                message_type,
            )
        })?;
        let msg = Self::parse_msg(message_type, message_src)?;
        let mut dependencies = HashMap::new();
        for message_body in message_bodies {
            let dependency = Self::parse_dependency(message_body)?;
            dependencies.insert(dependency.path().clone(), dependency);
        }

        Ok(DynamicMsg { msg, dependencies })
    }

    pub fn msg(&self) -> &Msg {
        &self.msg
    }

    pub fn dependency(&self, path: &MessagePath) -> Option<&Msg> {
        self.dependencies.get(path)
    }

    pub fn from_headers(headers: HashMap<String, String>) -> Result<Self> {
        let message_type = headers.get("type").chain_err(|| "Missing header `type`")?;
        let message_definition = headers
            .get("message_definition")
            .chain_err(|| "Missing header `message_definition`")?;
        Self::new(message_type, message_definition)
    }

    fn parse_msg(message_type: &str, message_src: &str) -> Result<Msg> {
        let message_path = message_type
            .try_into()
            .chain_err(|| format!("Message type {} is invalid", message_type))?;
        Msg::new(message_path, message_src)
            .chain_err(|| format!("Failed to parse message {}", message_type))
    }

    fn parse_dependency(message_body: &str) -> Result<Msg> {
        lazy_static! {
            static ref RE_DESCRIPTOR_MSG_TYPE: regex::Regex =
                regex::Regex::new(r#"^\s*MSG:\s*(\S+)\s*$"#).unwrap();
        }
        let message_body = message_body.trim();
        let (message_type_line, message_src) = message_body
            .split_once('\n')
            .chain_err(|| "Message dependency is missing type declaration")?;
        let cap = RE_DESCRIPTOR_MSG_TYPE
            .captures(message_type_line)
            .chain_err(|| format!("Failed to parse message type line `{}`", message_type_line))?;
        let message_type = cap
            .get(1)
            .chain_err(|| format!("Failed to parse message type line `{}`", message_type_line))?;
        Self::parse_msg(message_type.as_str(), message_src)
    }

    pub fn encode(&self, value: &MessageValue, mut w: impl io::Write) -> io::Result<()> {
        self.encode_message(&self.msg, value, &mut w)
    }

    pub fn decode(&self, mut r: impl io::Read) -> io::Result<MessageValue> {
        self.decode_message(&self.msg, &mut r)
    }

    fn get_dependency(&self, path: &MessagePath) -> io::Result<&Msg> {
        self.dependencies.get(path).ok_or_else(|| {
            io::Error::new(
                io::ErrorKind::Other,
                format!("Missing message dependency: {}", path),
            )
        })
    }

    fn encode_message(
        &self,
        msg: &Msg,
        value: &MessageValue,
        w: &mut impl io::Write,
    ) -> io::Result<()> {
        for field in msg.fields() {
            match field.case() {
                FieldCase::Const(_) => continue,
                FieldCase::Unit => {
                    let field_value = get_field(value, field.name())?;
                    self.encode_field(field, field_value, w)?;
                }
                FieldCase::Vector => {
                    let field_value = get_field(value, field.name())?;
                    self.encode_field_array(field, field_value, None, w)?;
                }
                FieldCase::Array(l) => {
                    let field_value = get_field(value, field.name())?;
                    self.encode_field_array(field, field_value, Some(*l), w)?;
                }
            }
        }
        Ok(())
    }

    fn encode_field(
        &self,
        field: &FieldInfo,
        value: &Value,
        w: &mut impl std::io::Write,
    ) -> io::Result<()> {
        match (field.datatype(), value) {
            (DataType::Bool, Value::Bool(v)) => v.encode(w),
            (DataType::I8(_), Value::I8(v)) => v.encode(w),
            (DataType::I16, Value::I16(v)) => v.encode(w),
            (DataType::I32, Value::I32(v)) => v.encode(w),
            (DataType::I64, Value::I64(v)) => v.encode(w),
            (DataType::U8(_), Value::U8(v)) => v.encode(w),
            (DataType::U16, Value::U16(v)) => v.encode(w),
            (DataType::U32, Value::U32(v)) => v.encode(w),
            (DataType::U64, Value::U64(v)) => v.encode(w),
            (DataType::F32, Value::F32(v)) => v.encode(w),
            (DataType::F64, Value::F64(v)) => v.encode(w),
            (DataType::String, Value::String(v)) => v.encode(w),
            (DataType::Time, Value::Time(time)) => time.encode(w),
            (DataType::Duration, Value::Duration(duration)) => duration.encode(w),
            (DataType::LocalStruct(name), Value::Message(v)) => {
                let path = MessagePath::new(self.msg.path().package(), name)
                    .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
                let dependency = self.get_dependency(&path)?;
                self.encode_message(dependency, v, w)
            }
            (DataType::RemoteStruct(path), Value::Message(v)) => {
                let dependency = self.get_dependency(path)?;
                self.encode_message(dependency, v, w)
            }
            _ => Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "Passed in dynamic data value does not match message format",
            )),
        }
    }

    fn encode_field_array(
        &self,
        field: &FieldInfo,
        value: &Value,
        array_length: Option<usize>,
        w: &mut impl std::io::Write,
    ) -> io::Result<()> {
        let value = match value {
            Value::Array(v) => v,
            Value::Bool(_)
            | Value::I8(_)
            | Value::I16(_)
            | Value::I32(_)
            | Value::I64(_)
            | Value::U8(_)
            | Value::U16(_)
            | Value::U32(_)
            | Value::U64(_)
            | Value::F32(_)
            | Value::F64(_)
            | Value::String(_)
            | Value::Time { .. }
            | Value::Duration { .. }
            | Value::Message(_) => {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    "Passed in dynamic message field is not an array",
                ));
            }
        };
        match array_length {
            Some(array_length) => {
                if array_length != value.len() {
                    return Err(io::Error::new(
                        io::ErrorKind::InvalidData,
                        "Passed in dynamic message array field has wrong length",
                    ));
                }
            }
            None => {
                (value.len() as u32).encode(w.by_ref())?;
            }
        }
        for value in value {
            self.encode_field(field, value, w.by_ref())?;
        }
        Ok(())
    }

    fn decode_message(&self, msg: &Msg, r: &mut impl io::Read) -> io::Result<MessageValue> {
        let mut output = MessageValue::new();
        for field in msg.fields() {
            let value = match field.case() {
                FieldCase::Const(_) => continue,
                FieldCase::Unit => self.decode_field(field, r)?,
                FieldCase::Vector => self.decode_field_array(field, None, r)?,
                FieldCase::Array(l) => self.decode_field_array(field, Some(*l), r)?,
            };
            output.insert(field.name().into(), value);
        }
        Ok(output)
    }

    fn decode_field(&self, field: &FieldInfo, r: &mut impl io::Read) -> io::Result<Value> {
        Ok(match field.datatype() {
            DataType::Bool => bool::decode(r)?.into(),
            DataType::I8(_) => i8::decode(r)?.into(),
            DataType::I16 => i16::decode(r)?.into(),
            DataType::I32 => i32::decode(r)?.into(),
            DataType::I64 => i64::decode(r)?.into(),
            DataType::U8(_) => u8::decode(r)?.into(),
            DataType::U16 => u16::decode(r)?.into(),
            DataType::U32 => u32::decode(r)?.into(),
            DataType::U64 => u64::decode(r)?.into(),
            DataType::F32 => f32::decode(r)?.into(),
            DataType::F64 => f64::decode(r)?.into(),
            DataType::String => String::decode(r)?.into(),
            DataType::Time => Time::decode(r)?.into(),
            DataType::Duration => Duration::decode(r)?.into(),
            DataType::LocalStruct(name) => {
                let path = MessagePath::new(self.msg.path().package(), name)
                    .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
                let dependency = self.get_dependency(&path)?;
                self.decode_message(dependency, r)?.into()
            }
            DataType::RemoteStruct(path) => {
                let dependency = self.get_dependency(path)?;
                self.decode_message(dependency, r)?.into()
            }
        })
    }

    fn decode_field_array(
        &self,
        field: &FieldInfo,
        array_length: Option<usize>,
        r: &mut impl io::Read,
    ) -> io::Result<Value> {
        let array_length = match array_length {
            Some(v) => v,
            None => u32::decode(r.by_ref())? as usize,
        };
        // TODO: optimize by checking data type only once
        (0..array_length)
            .map(|_| self.decode_field(field, r))
            .collect()
    }
}
<|endoftext|>