<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.
//

use std::cmp::Ordering;

use super::symbol_range::*;

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

impl<Symbol: PartialOrd+Clone> 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 {
        if let Some(order) = a.partial_cmp(b) {
            order
        } else {
            Ordering::Equal
        }
    }

    ///
    /// 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
        };

        // 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> {
        // Create a vector of all the range symbols
        let mut range_symbols: Vec<Symbol> = self.ranges.iter()
            .map(|r| r.lowest.clone())
            .chain(self.ranges.iter().map(|r| r.highest.clone()))
            .collect();

        // Sort and dedupe (we'll get pairs of ranges)
        range_symbols.sort_by(SymbolMap::order_symbols);
        range_symbols.dedup();

        // Generate a new symbol map with these ranges
        // They'll overlap with the last value, which should be OK if following the rules for adjacent ranges in symbol_range.rs
        let mut result = vec![];
        for index in 0..range_symbols.len()-1 {
            result.push(SymbolRange::new(range_symbols[index].clone(), range_symbols[index+1].clone()));
        }

        // We already sorted everything, so bypass the usual 'add' method (which sorts as it goes)
        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));

        println!("All is: {:?}", all);

        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(6, 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 bottom = map.find_overlapping_ranges(&SymbolRange::new(1, 3));

        assert!(bottom == 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));

        println!("With duplicate lower values is: {:?}", all);

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

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

        // By the adjacency rule for symbol ranges (in symbol_range.rs), '4' here is only in the upper range
        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(4, 8));

        let top = map.find_overlapping_ranges(&SymbolRange::new(4, 4));

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

    #[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, 2), &SymbolRange::new(2, 3), &SymbolRange::new(3, 4), &SymbolRange::new(4, 5), &SymbolRange::new(5, 6)]);
    }
}
<commit_msg>The insertion pos can be after the first match, so move it backwards if necessary<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.
//

use std::cmp::Ordering;

use super::symbol_range::*;

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

impl<Symbol: PartialOrd+Clone> 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 {
        if let Some(order) = a.partial_cmp(b) {
            order
        } else {
            Ordering::Equal
        }
    }

    ///
    /// 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
        // NOT if only by the highest value; see the adjacency rule in symbol_range.rs
        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> {
        // Create a vector of all the range symbols
        let mut range_symbols: Vec<Symbol> = self.ranges.iter()
            .map(|r| r.lowest.clone())
            .chain(self.ranges.iter().map(|r| r.highest.clone()))
            .collect();

        // Sort and dedupe (we'll get pairs of ranges)
        range_symbols.sort_by(SymbolMap::order_symbols);
        range_symbols.dedup();

        // Generate a new symbol map with these ranges
        // They'll overlap with the last value, which should be OK if following the rules for adjacent ranges in symbol_range.rs
        let mut result = vec![];
        for index in 0..range_symbols.len()-1 {
            result.push(SymbolRange::new(range_symbols[index].clone(), range_symbols[index+1].clone()));
        }

        // We already sorted everything, so bypass the usual 'add' method (which sorts as it goes)
        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));

        println!("All is: {:?}", all);

        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(6, 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 bottom = map.find_overlapping_ranges(&SymbolRange::new(1, 3));

        assert!(bottom == 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));

        println!("With duplicate lower values is: {:?}", all);

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

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

        // By the adjacency rule for symbol ranges (in symbol_range.rs), '4' here is only in the upper range
        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(4, 8));

        let top = map.find_overlapping_ranges(&SymbolRange::new(4, 4));

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

    #[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, 2), &SymbolRange::new(2, 3), &SymbolRange::new(3, 4), &SymbolRange::new(4, 5), &SymbolRange::new(5, 6)]);
    }
}
<|endoftext|>


<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.
//

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: PartialOrd+Clone+Countable> {
    // Ranges in this symbol map
    ranges: Vec<SymbolRange<Symbol>>,
}

impl<Symbol: PartialOrd+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 {
        if let Some(order) = a.partial_cmp(b) {
            order
        } else {
            Ordering::Equal
        }
    }

    ///
    /// 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
                        to_process.push(overlap_with.clone());
                        to_process.push(SymbolRange::new(overlap_with.lowest, might_overlap.highest));
                    }
                }
            } 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 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));
        println!("{:?}", all);

        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 issue caused by sort order when untangling overlapping ranges<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.
//

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: PartialOrd+Clone+Countable> {
    // Ranges in this symbol map
    ranges: Vec<SymbolRange<Symbol>>,
}

impl<Symbol: PartialOrd+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 {
        if let Some(order) = a.partial_cmp(b) {
            order
        } else {
            Ordering::Equal
        }
    }

    ///
    /// 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 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>//
//   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.
//

//!
//! A DFA that matches transitions against symbol ranges.
//!

use super::dfa_builder::*;
use super::pattern_matcher::*;
use super::symbol_range::*;
use super::state_machine::*;

///
/// DFA that decides on transitions based on non-overlapping, sorted lists of input symbols
///
#[derive(Debug)]
pub struct SymbolRangeDfa<InputSymbol: Ord, OutputSymbol> {
    //
    // Indexes of where each state starts in the transition table (it ends at the start of the next state)
    //
    states: Vec<usize>,

    //
    // The transitions making up this DFA
    //
    transitions: Vec<(SymbolRange<InputSymbol>, StateId)>,

    //
    // The accepting symbol for each state
    //
    accept: Vec<Option<OutputSymbol>>
}

///
/// DFA builder that creates RangeDfas
///
pub struct SymbolRangeDfaBuilder<InputSymbol: Ord, OutputSymbol> {
    states: Vec<usize>,
    transitions: Vec<(SymbolRange<InputSymbol>, StateId)>,
    accept: Vec<Option<OutputSymbol>>
}

impl<InputSymbol: Ord, OutputSymbol> SymbolRangeDfaBuilder<InputSymbol, OutputSymbol> {
    pub fn new() -> SymbolRangeDfaBuilder<InputSymbol, OutputSymbol> {
        SymbolRangeDfaBuilder { states: vec![], transitions: vec![], accept: vec![] }
    }
}

impl<InputSymbol: Ord, OutputSymbol> DfaBuilder<SymbolRange<InputSymbol>, OutputSymbol, SymbolRangeDfa<InputSymbol, OutputSymbol>> for SymbolRangeDfaBuilder<InputSymbol, OutputSymbol> {
    fn start_state(&mut self) {
        // Begin the next state
        self.states.push(self.transitions.len());
        self.accept.push(None);
    }

    fn transition(&mut self, symbol: SymbolRange<InputSymbol>, target_state: StateId) {
        self.transitions.push((symbol, target_state));
    }

    fn accept(&mut self, symbol: OutputSymbol) {
        self.accept.pop();
        self.accept.push(Some(symbol));
    }

    fn build(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        // Turn into a RangeDfa
        let mut result = SymbolRangeDfa { states: self.states, transitions: self.transitions, accept: self.accept };

        // 'Cap' the last state so we don't need to special-case it later
        // ie, we can always find the index of the last symbol by looking at the next state and don't need to handle the final state differently
        result.states.push(result.transitions.len());

        result
    }
}

impl<InputSymbol: Ord+Clone, OutputSymbol> StateMachine<SymbolRange<InputSymbol>, OutputSymbol> for SymbolRangeDfa<InputSymbol, OutputSymbol> {
    ///
    /// Returns the number of states in this state machine
    ///
    /// Note that if state x exists then state x-1 is also expected to exist provided x > 0. This means that this returns the
    /// first unused state in this state machine.
    ///
    fn count_states(&self) -> StateId {
        (self.states.len()-1) as StateId
    }

    ///
    /// Returns the transitions for a particular symbol
    ///
    fn get_transitions_for_state(&self, state: StateId) -> Vec<(SymbolRange<InputSymbol>, StateId)> {
        let mut result = vec![];

        let start_index = self.states[state as usize];
        let end_index   = self.states[(state+1) as usize];

        for transit_index in start_index..end_index {
            let (ref range, target_state) = self.transitions[transit_index];

            result.push((range.clone(), target_state));
        }

        result
    }

    ///
    /// If a state is an accepting state, then this returns the output symbol that should be produced if this is the longest match
    ///
    fn output_symbol_for_state(&self, state: StateId) -> Option<&OutputSymbol> {
        self.accept[state as usize].as_ref()
    }
}

///
/// A state of a symbol range state machine
///
#[derive(Clone)]
pub struct SymbolRangeState<'a, InputSymbol: Ord+'a, OutputSymbol: 'a> {
    // The current state of the state machine
    state: StateId,

    // The number of symbols that have been processed so far
    count: usize,

    // If something other than none, the most recent accepting state
    accept: Option<(usize, &'a OutputSymbol)>,

    // The state machine this is running
    state_machine: &'a SymbolRangeDfa<InputSymbol, OutputSymbol>
}

impl<InputSymbol: Ord, OutputSymbol> SymbolRangeDfa<InputSymbol, OutputSymbol> {
    ///
    /// Returns a `MatchAction` for the initial state of the DFA
    ///
    pub fn start<'a>(&'a self) -> MatchAction<'a, OutputSymbol, SymbolRangeState<'a, InputSymbol, OutputSymbol>> {
        // TODO: if state 0 is accepting, then this will erroneously not move straight to the accepting state
        if let Some(ref outputsymbol) = self.accept[0] {
            More(SymbolRangeState { state: 0, count: 0, accept: Some((0, outputsymbol)), state_machine: self })
        } else {
            More(SymbolRangeState { state: 0, count: 0, accept: None, state_machine: self })
        }
    }
}

impl<'a, InputSymbol: Ord+'a, OutputSymbol: 'a> MatchingState<'a, InputSymbol, OutputSymbol> for SymbolRangeState<'a, InputSymbol, OutputSymbol> {
    fn next(self, symbol: InputSymbol) -> MatchAction<'a, OutputSymbol, Self> {
        // The transition range is defined by the current state
        let start_transition    = self.state_machine.states[self.state as usize];
        let end_transition      = self.state_machine.states[self.state as usize+1];

        // See if there is an input symbol matching this transition
        // TODO: consider binary searching for states with large numbers of transitions? (Do these occur regularly in patterns that people use?)
        for transit in start_transition..end_transition {
            // Test this transition
            let (ref range, new_state) = self.state_machine.transitions[transit];

            if range.includes(&symbol) {
                // Found a transition to a new state: result will be `More(new state)`
                let new_count = self.count+1;

                // If the new state is an accepting state, then remember it in case we reach a rejecting state later
                let new_accept = if let Some(ref output) = self.state_machine.accept[new_state as usize] {
                    Some((new_count, output))
                } else {
                    self.accept
                };

                // Action is 'More'
                // TODO: might be an option to return Accept or Reject here if the new state has no transitions
                // (Possible performance advantage, but depends on the regex and input conditions)
                return More(SymbolRangeState { state: new_state, count: new_count, accept: new_accept, state_machine: self.state_machine });
            }
        }

        // No matches: finish the state machine
        self.finish()
    }

    fn finish(self) -> MatchAction<'a, OutputSymbol, Self> {
        if let Some(accept_state) = self.accept {
            // We found an accepting state earlier on, so return that
            let (length, symbol) = accept_state;
            Accept(length, symbol)
        } else {
            // No accepting state was found while this state machine was running
            Reject
        }
    }
}

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

    #[test]
    fn can_build_state_machine() {
        let mut builder = SymbolRangeDfaBuilder::new();

        // State 0: '0', move to state 1
        builder.start_state();
        builder.transition(SymbolRange::new(0, 0), 1);

        // State 1: accept, output symbol "Success"
        builder.start_state();
        builder.accept("Success");

        // Create the state machine
        let state_machine = builder.build();

        assert!(state_machine.count_states() == 2);
        assert!(state_machine.output_symbol_for_state(0) == None);
        assert!(state_machine.output_symbol_for_state(1) == Some(&"Success"));
        assert!(state_machine.get_transitions_for_state(0) == vec![(SymbolRange::new(0,0), 1)]);
    }

    #[test]
    fn can_accept_single_symbol() {
        let mut builder = SymbolRangeDfaBuilder::new();

        // State 0: '0', move to state 1
        builder.start_state();
        builder.transition(SymbolRange::new(0, 0), 1);

        // State 1: accept, output symbol "Success"
        builder.start_state();
        builder.accept("Success");

        // Create the state machine
        let state_machine = builder.build();

        // Run the first state
        let mut action = state_machine.start();

        if let More(next_state) = action {
            action = next_state.next(0);
        }

        if let More(next_state) = action {
            action = next_state.next(0);

            // Should have reached an accepting state (read one character)
            if let Accept(count, symbol) = action {
                // One symbol accepted
                assert!(count == 1);

                // Output symbol correct
                assert!(symbol == &"Success");
            } else {
                // Should have accepted here (the second '0' is rejected)
                assert!(false);
            }
        } else {
            // State machine did not accept the character
            assert!(false);
        }
    }
}
<commit_msg>Can make this clonable<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.
//

//!
//! A DFA that matches transitions against symbol ranges.
//!

use super::dfa_builder::*;
use super::pattern_matcher::*;
use super::symbol_range::*;
use super::state_machine::*;

///
/// DFA that decides on transitions based on non-overlapping, sorted lists of input symbols
///
#[derive(Debug, Clone)]
pub struct SymbolRangeDfa<InputSymbol: Ord, OutputSymbol> {
    //
    // Indexes of where each state starts in the transition table (it ends at the start of the next state)
    //
    states: Vec<usize>,

    //
    // The transitions making up this DFA
    //
    transitions: Vec<(SymbolRange<InputSymbol>, StateId)>,

    //
    // The accepting symbol for each state
    //
    accept: Vec<Option<OutputSymbol>>
}

///
/// DFA builder that creates RangeDfas
///
pub struct SymbolRangeDfaBuilder<InputSymbol: Ord, OutputSymbol> {
    states: Vec<usize>,
    transitions: Vec<(SymbolRange<InputSymbol>, StateId)>,
    accept: Vec<Option<OutputSymbol>>
}

impl<InputSymbol: Ord, OutputSymbol> SymbolRangeDfaBuilder<InputSymbol, OutputSymbol> {
    pub fn new() -> SymbolRangeDfaBuilder<InputSymbol, OutputSymbol> {
        SymbolRangeDfaBuilder { states: vec![], transitions: vec![], accept: vec![] }
    }
}

impl<InputSymbol: Ord, OutputSymbol> DfaBuilder<SymbolRange<InputSymbol>, OutputSymbol, SymbolRangeDfa<InputSymbol, OutputSymbol>> for SymbolRangeDfaBuilder<InputSymbol, OutputSymbol> {
    fn start_state(&mut self) {
        // Begin the next state
        self.states.push(self.transitions.len());
        self.accept.push(None);
    }

    fn transition(&mut self, symbol: SymbolRange<InputSymbol>, target_state: StateId) {
        self.transitions.push((symbol, target_state));
    }

    fn accept(&mut self, symbol: OutputSymbol) {
        self.accept.pop();
        self.accept.push(Some(symbol));
    }

    fn build(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        // Turn into a RangeDfa
        let mut result = SymbolRangeDfa { states: self.states, transitions: self.transitions, accept: self.accept };

        // 'Cap' the last state so we don't need to special-case it later
        // ie, we can always find the index of the last symbol by looking at the next state and don't need to handle the final state differently
        result.states.push(result.transitions.len());

        result
    }
}

impl<InputSymbol: Ord+Clone, OutputSymbol> StateMachine<SymbolRange<InputSymbol>, OutputSymbol> for SymbolRangeDfa<InputSymbol, OutputSymbol> {
    ///
    /// Returns the number of states in this state machine
    ///
    /// Note that if state x exists then state x-1 is also expected to exist provided x > 0. This means that this returns the
    /// first unused state in this state machine.
    ///
    fn count_states(&self) -> StateId {
        (self.states.len()-1) as StateId
    }

    ///
    /// Returns the transitions for a particular symbol
    ///
    fn get_transitions_for_state(&self, state: StateId) -> Vec<(SymbolRange<InputSymbol>, StateId)> {
        let mut result = vec![];

        let start_index = self.states[state as usize];
        let end_index   = self.states[(state+1) as usize];

        for transit_index in start_index..end_index {
            let (ref range, target_state) = self.transitions[transit_index];

            result.push((range.clone(), target_state));
        }

        result
    }

    ///
    /// If a state is an accepting state, then this returns the output symbol that should be produced if this is the longest match
    ///
    fn output_symbol_for_state(&self, state: StateId) -> Option<&OutputSymbol> {
        self.accept[state as usize].as_ref()
    }
}

///
/// A state of a symbol range state machine
///
#[derive(Clone)]
pub struct SymbolRangeState<'a, InputSymbol: Ord+'a, OutputSymbol: 'a> {
    // The current state of the state machine
    state: StateId,

    // The number of symbols that have been processed so far
    count: usize,

    // If something other than none, the most recent accepting state
    accept: Option<(usize, &'a OutputSymbol)>,

    // The state machine this is running
    state_machine: &'a SymbolRangeDfa<InputSymbol, OutputSymbol>
}

impl<InputSymbol: Ord, OutputSymbol> SymbolRangeDfa<InputSymbol, OutputSymbol> {
    ///
    /// Returns a `MatchAction` for the initial state of the DFA
    ///
    pub fn start<'a>(&'a self) -> MatchAction<'a, OutputSymbol, SymbolRangeState<'a, InputSymbol, OutputSymbol>> {
        // TODO: if state 0 is accepting, then this will erroneously not move straight to the accepting state
        if let Some(ref outputsymbol) = self.accept[0] {
            More(SymbolRangeState { state: 0, count: 0, accept: Some((0, outputsymbol)), state_machine: self })
        } else {
            More(SymbolRangeState { state: 0, count: 0, accept: None, state_machine: self })
        }
    }
}

impl<'a, InputSymbol: Ord+'a, OutputSymbol: 'a> MatchingState<'a, InputSymbol, OutputSymbol> for SymbolRangeState<'a, InputSymbol, OutputSymbol> {
    fn next(self, symbol: InputSymbol) -> MatchAction<'a, OutputSymbol, Self> {
        // The transition range is defined by the current state
        let start_transition    = self.state_machine.states[self.state as usize];
        let end_transition      = self.state_machine.states[self.state as usize+1];

        // See if there is an input symbol matching this transition
        // TODO: consider binary searching for states with large numbers of transitions? (Do these occur regularly in patterns that people use?)
        for transit in start_transition..end_transition {
            // Test this transition
            let (ref range, new_state) = self.state_machine.transitions[transit];

            if range.includes(&symbol) {
                // Found a transition to a new state: result will be `More(new state)`
                let new_count = self.count+1;

                // If the new state is an accepting state, then remember it in case we reach a rejecting state later
                let new_accept = if let Some(ref output) = self.state_machine.accept[new_state as usize] {
                    Some((new_count, output))
                } else {
                    self.accept
                };

                // Action is 'More'
                // TODO: might be an option to return Accept or Reject here if the new state has no transitions
                // (Possible performance advantage, but depends on the regex and input conditions)
                return More(SymbolRangeState { state: new_state, count: new_count, accept: new_accept, state_machine: self.state_machine });
            }
        }

        // No matches: finish the state machine
        self.finish()
    }

    fn finish(self) -> MatchAction<'a, OutputSymbol, Self> {
        if let Some(accept_state) = self.accept {
            // We found an accepting state earlier on, so return that
            let (length, symbol) = accept_state;
            Accept(length, symbol)
        } else {
            // No accepting state was found while this state machine was running
            Reject
        }
    }
}

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

    #[test]
    fn can_build_state_machine() {
        let mut builder = SymbolRangeDfaBuilder::new();

        // State 0: '0', move to state 1
        builder.start_state();
        builder.transition(SymbolRange::new(0, 0), 1);

        // State 1: accept, output symbol "Success"
        builder.start_state();
        builder.accept("Success");

        // Create the state machine
        let state_machine = builder.build();

        assert!(state_machine.count_states() == 2);
        assert!(state_machine.output_symbol_for_state(0) == None);
        assert!(state_machine.output_symbol_for_state(1) == Some(&"Success"));
        assert!(state_machine.get_transitions_for_state(0) == vec![(SymbolRange::new(0,0), 1)]);
    }

    #[test]
    fn can_accept_single_symbol() {
        let mut builder = SymbolRangeDfaBuilder::new();

        // State 0: '0', move to state 1
        builder.start_state();
        builder.transition(SymbolRange::new(0, 0), 1);

        // State 1: accept, output symbol "Success"
        builder.start_state();
        builder.accept("Success");

        // Create the state machine
        let state_machine = builder.build();

        // Run the first state
        let mut action = state_machine.start();

        if let More(next_state) = action {
            action = next_state.next(0);
        }

        if let More(next_state) = action {
            action = next_state.next(0);

            // Should have reached an accepting state (read one character)
            if let Accept(count, symbol) = action {
                // One symbol accepted
                assert!(count == 1);

                // Output symbol correct
                assert!(symbol == &"Success");
            } else {
                // Should have accepted here (the second '0' is rejected)
                assert!(false);
            }
        } else {
            // State machine did not accept the character
            assert!(false);
        }
    }
}
<|endoftext|>


<commit_before>use rocket::request::{FromForm, FormItems};

#[derive(Debug)]
pub struct StatementStructResult {
    sql: String,
}
pub struct WhereStructResult {
    sql: String,
    values: Vec<String>,
}

// My Results
type QueryOpResult = Result<&'static str, String>;
type StatementResult = Result<StatementStructResult, String>;
type WhereResult = Result<WhereStructResult, String>;

// TODO: Move there later
pub struct Params {
    pub k: String,
    pub v: String,
}
// implement QueryString
pub struct QueryString {
    pub query: Vec<Params>,
}

impl<'f> FromForm<'f> for QueryString {
    type Error = ();

    fn from_form(items: &mut FormItems<'f>, _: bool) -> Result<QueryString, ()> {
        let mut qs: QueryString = QueryString { query: Vec::new() };
        for (k, v) in items {
            qs.query.push(Params {
                k: k.to_string(),
                v: v.url_decode().unwrap(),
            });
        }
        Ok(qs)
    }
}

pub fn query_operator(qop: &str) -> QueryOpResult {
    match &qop[..] {
        "$eq" => Ok("="),
        "$ne" => Ok("!="),
        "$gt" => Ok(">"),
        "$lt" => Ok("<"),
        "$gte" => Ok(">="),
        "$lte" => Ok("<="),
        "$in" => Ok("IN"),
        "$nin" => Ok("NOT IN"),
        "$notnull" => Ok("IS NOT NULL"),
        "$null" => Ok("IS NULL"),
        _ => Err(format!("operator {} not found", qop)),
    }
}

fn collect_params(v: &Vec<Params>, collect_values: bool) -> Result<Vec<String>, String> {
    let mut pid: i32 = 0;
    v.iter()
        .map(|param| {
            pid = pid + 1;
            let result = match param.v.contains(".") {
                true => {
                    let value_splited = param.v.split(".").collect::<Vec<&str>>();
                    let operator = match query_operator(value_splited[0]) {
                        Ok(op) => op,
                        Err(e) => return Err(e),
                    };
                    (operator, value_splited[1])
                }
                _ => ("=", param.v.as_str()),
            };
            if collect_values {
                Ok(format!("{}", result.1))
            } else {
                Ok(format!("{}{}${}", param.k, result.0, pid))
            }
        })
        .collect()
}

// generic function to process statements: _select, _groupby, _order, _count
fn process_statement<F>(
    qs: &QueryString,
    stm: &str,
    stm_default: &str,
    stm_fmt: &str,
    stm_fn: F,
) -> StatementResult
where
    F: Fn(&str) -> String,
{
    let mut statement_syntax: String = String::from(stm_default);
    let statement_params = qs.query.iter().find(|p| p.k == String::from(stm));
    let columns = match statement_params {
        Some(param) => stm_fn(&param.v),
        _ => return Err("".to_string()),
    };
    if columns != "" {
        statement_syntax = format!("{}", String::from(stm_fmt).replace("{}", &columns));
    }
    Ok(StatementStructResult { sql: statement_syntax })
}

// Get QueryString and return chunck WHERE statement with values
pub fn ext_where(qs: &QueryString) -> WhereResult {
    let where_syntax: String;
    let ref iter_params = qs.query;
    let where_values = match collect_params(iter_params, true) {
        Ok(result) => result,
        Err(e) => return Err(e.to_string()),
    };
    let where_fields = match collect_params(iter_params, false) {
        Ok(result) => result,
        Err(e) => return Err(e.to_string()),
    };

    if where_fields.len() > 1 {
        where_syntax = format!("WHERE {}", where_fields.join(" AND "));
    } else {
        where_syntax = format!("WHERE {}", where_fields.join(" "));
    }

    Ok(WhereStructResult {
        sql: where_syntax,
        values: where_values,
    })
}

// Get QueryString and return SELECT statement
pub fn ext_select(qs: &QueryString) -> StatementResult {
    Ok(
        process_statement(qs, "_select", "SELECT * FROM", "SELECT {} FROM", |x| {
            String::from(x)
        }).unwrap(),
    )
}

// Get QueryString and return COUNT clause statement
pub fn ext_count(qs: &QueryString) -> StatementResult {
    // FIXME: Need handle errors
    Ok(
        process_statement(qs, "_count", "", "SELECT COUNT({}) FROM", |x| {
            let vs = x.split(",").collect::<Vec<&str>>();
            let result = if vs.len() > 1 { "" } else { x };
            String::from(result)
        }).unwrap(),
    )
}

// Get QueryString and return chunk ORDER BY statement
pub fn ext_order(qs: QueryString) -> StatementResult {
    Ok(
        process_statement(&qs, "_order", "", "ORDER BY {}", |x| {
            let vspl = &x.split(",").collect::<Vec<&str>>();
            let od: Vec<String> = vspl.iter()
                .map(|param| {
                    let mut s = String::new();
                    s.push_str(param); // omg
                    if s.starts_with("-") {
                        s.remove(0);
                        s.push_str(" DESC")
                    }
                    format!("{}", s)
                })
                .collect();
            format!("{}", od.join(","))
        }).unwrap(),
    )

}

// Get QueryString and return chunk GROUP BY statement
pub fn ext_groupby(qs: &QueryString) -> StatementResult {
    Ok(
        process_statement(qs, "_groupby", "", "GROUP BY {}", |x| String::from(x)).unwrap(),
    )
}

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

    #[test]
    fn get_opetators() {
        use std::collections::HashMap;

        let mut test_cases = HashMap::new();
        test_cases.insert("$eq", "=");
        test_cases.insert("$ne", "!=");
        test_cases.insert("$gt", ">");
        test_cases.insert("$gte", ">=");
        test_cases.insert("$lt", "<");
        test_cases.insert("$lte", "<=");
        test_cases.insert("$in", "IN");
        test_cases.insert("$nin", "NOT IN");
        test_cases.insert("$notnull", "IS NOT NULL");
        test_cases.insert("$null", "IS NULL");

        for (op, expected) in &test_cases {
            match query_operator(&op.to_string()) {
                Ok(x) => assert_eq!(expected.to_string(), x),
                Err(e) => assert_eq!("", e),
            }
        }
    }

    #[test]
    fn get_opetators_error() {
        let invalid = "!tn".to_string();
        match query_operator(&invalid) {
            Ok(_) => println!("no result"),
            Err(e) => assert_eq!(format!("operator {} not found", invalid), e),
        }
    }

    #[test]
    fn where_by_request_one_querystring() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "user_id".to_string(),
            v: "5".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_where(&qs).unwrap();
        assert_eq!(result.sql, "WHERE user_id=$1".to_string());
        assert_eq!(result.values, vec!["5".to_string()])
    }

    #[test]
    fn where_by_request_n_querystring() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "user_id".to_string(),
            v: "5".to_string(),
        });
        hm.push(Params {
            k: "name".to_string(),
            v: "goga".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_where(&qs).unwrap();
        assert_eq!(result.sql, "WHERE user_id=$1 AND name=$2".to_string());
        assert_eq!(result.values, vec!["5".to_string(), "goga".to_string()])
    }

    #[test]
    fn where_by_request_with_query_operators() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "user_id".to_string(),
            v: "$ne.5".to_string(),
        });
        hm.push(Params {
            k: "name".to_string(),
            v: "goga".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_where(&qs).unwrap();
        assert_eq!(result.sql, "WHERE user_id!=$1 AND name=$2".to_string());
        assert_eq!(result.values, vec!["5".to_string(), "goga".to_string()])
    }

    #[test]
    fn where_by_request_with_query_invalid_operators() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "user_id".to_string(),
            v: "$nt.5".to_string(),
        });
        hm.push(Params {
            k: "name".to_string(),
            v: "goga".to_string(),
        });

        let qs = QueryString { query: hm };
        match ext_where(&qs) {
            Err(e) => assert_eq!(e, "operator $nt not found"),
            Ok(_) => println!("no result"),
        }
    }

    #[test]
    fn select_by_request_one_column() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_select".to_string(),
            v: "name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_select(&qs).unwrap();
        assert_eq!(result.sql, "SELECT name FROM");
    }

    #[test]
    fn select_by_request_n_column() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_select".to_string(),
            v: "name,age".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_select(&qs).unwrap();
        assert_eq!(result.sql, "SELECT name,age FROM");
    }

    #[test]
    fn select_by_request_n_empty_value() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_select".to_string(),
            v: "".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_select(&qs).unwrap();
        assert_eq!(result.sql, "SELECT * FROM");
    }

    #[test]
    fn count_by_request() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_count".to_string(),
            v: "name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_count(&qs).unwrap();
        assert_eq!(result.sql, "SELECT COUNT(name) FROM");
    }

    #[test]
    fn count_by_request_all_fields() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_count".to_string(),
            v: "*".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_count(&qs).unwrap();
        assert_eq!(result.sql, "SELECT COUNT(*) FROM");
    }

    #[test]
    fn count_by_request_two_fields() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_count".to_string(),
            v: "name,age".to_string(),
        });

        let qs = QueryString { query: hm };
        match ext_count(&qs) {
            Err(e) => assert_eq!(e, "could not use more than one column in count function"),
            Ok(s) => assert_eq!(s.sql, ""),
        }
    }

    #[test]
    fn count_by_request_empty_value() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_count".to_string(),
            v: "".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_count(&qs).unwrap();
        assert_eq!(result.sql, "")
    }

    #[test]
    fn order_by_request() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "ORDER BY name")
    }

    #[test]
    fn order_by_request_desc() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "-name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "ORDER BY name DESC")
    }

    #[test]
    fn order_by_request_empty_params() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(qs).unwrap();
        assert_eq!(result.sql, "")
    }

    #[test]
    fn order_by_request_multiples_columns() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "name,age".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "ORDER BY name,age")
    }

    #[test]
    fn order_by_request_multiples_columns_with_orders() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "name,-age".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "ORDER BY name,age DESC")
    }

    #[test]
    fn groupby_by_request() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_groupby".to_string(),
            v: "name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_groupby(&qs).unwrap();
        assert_eq!(result.sql, "GROUP BY name")
    }

    #[test]
    fn groupby_by_request_empty_param() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: String::from("_groupby"),
            v: String::from(""),
        });

        let qs = QueryString { query: hm };
        let result = ext_groupby(&qs).unwrap();
        assert_eq!(result.sql, "")
    }
}
<commit_msg>Fix bug in ext_order command<commit_after>use rocket::request::{FromForm, FormItems};

#[derive(Debug)]
pub struct StatementStructResult {
    pub sql: String,
}
pub struct WhereStructResult {
    pub sql: String,
    pub values: Vec<String>,
}

// My Results
type QueryOpResult = Result<&'static str, String>;
type StatementResult = Result<StatementStructResult, String>;
type WhereResult = Result<WhereStructResult, String>;

// TODO: Move there later
#[derive(Debug)]
pub struct Params {
    pub k: String,
    pub v: String,
}
// implement QueryString
#[derive(Debug)]
pub struct QueryString {
    pub query: Vec<Params>,
}

impl<'f> FromForm<'f> for QueryString {
    type Error = ();

    fn from_form(items: &mut FormItems<'f>, _: bool) -> Result<QueryString, ()> {
        let mut qs: QueryString = QueryString { query: Vec::new() };
        for (k, v) in items {
            qs.query.push(Params {
                k: k.to_string(),
                v: v.url_decode().unwrap(),
            });
        }
        Ok(qs)
    }
}

pub fn query_operator(qop: &str) -> QueryOpResult {
    match &qop[..] {
        "$eq" => Ok("="),
        "$ne" => Ok("!="),
        "$gt" => Ok(">"),
        "$lt" => Ok("<"),
        "$gte" => Ok(">="),
        "$lte" => Ok("<="),
        "$in" => Ok("IN"),
        "$nin" => Ok("NOT IN"),
        "$notnull" => Ok("IS NOT NULL"),
        "$null" => Ok("IS NULL"),
        _ => Err(format!("operator {} not found", qop)),
    }
}

fn collect_params(v: &Vec<Params>, collect_values: bool) -> Result<Vec<String>, String> {
    let mut pid: i32 = 0;
    v.iter()
        .map(|param| {
            pid = pid + 1;
            let result = match param.v.contains(".") {
                true => {
                    let value_splited = param.v.split(".").collect::<Vec<&str>>();
                    let operator = match query_operator(value_splited[0]) {
                        Ok(op) => op,
                        Err(e) => return Err(e),
                    };
                    (operator, value_splited[1])
                }
                _ => ("=", param.v.as_str()),
            };
            if collect_values {
                Ok(format!("{}", result.1))
            } else {
                Ok(format!("{}{}${}", param.k, result.0, pid))
            }
        })
        .collect()
}

// generic function to process statements: _select, _groupby, _order, _count
fn process_statement<F>(
    qs: &QueryString,
    stm: &str,
    stm_default: &str,
    stm_fmt: &str,
    stm_fn: F,
) -> StatementResult
where
    F: Fn(&str) -> String,
{
    let mut statement_syntax: String = String::from(stm_default);
    let statement_params = qs.query.iter().find(|p| p.k == String::from(stm));
    let columns = match statement_params {
        Some(param) => stm_fn(&param.v),
        _ => String::from(""),
    };
    if columns != "" {
        statement_syntax = format!("{}", String::from(stm_fmt).replace("{}", &columns));
    }
    Ok(StatementStructResult { sql: statement_syntax })
}

// Get QueryString and return chunck WHERE statement with values
pub fn ext_where(qs: &QueryString) -> WhereResult {
    let where_syntax: String;
    let ref iter_params = qs.query;
    let where_values = match collect_params(iter_params, true) {
        Ok(result) => result,
        Err(e) => return Err(e.to_string()),
    };
    let where_fields = match collect_params(iter_params, false) {
        Ok(result) => result,
        Err(e) => return Err(e.to_string()),
    };

    if where_fields.len() > 1 {
        where_syntax = format!("WHERE {}", where_fields.join(" AND "));
    } else {
        where_syntax = format!("WHERE {}", where_fields.join(" "));
    }

    Ok(WhereStructResult {
        sql: where_syntax,
        values: where_values,
    })
}

// Get QueryString and return SELECT statement
pub fn ext_select(qs: &QueryString) -> StatementResult {
    Ok(
        process_statement(qs, "_select", "SELECT * FROM", "SELECT {} FROM", |x| {
            String::from(x)
        }).unwrap(),
    )
}

// Get QueryString and return COUNT clause statement
pub fn ext_count(qs: &QueryString) -> StatementResult {
    // FIXME: Need handle errors
    Ok(
        process_statement(qs, "_count", "", "SELECT COUNT({}) FROM", |x| {
            let vs = x.split(",").collect::<Vec<&str>>();
            let result = if vs.len() > 1 { "" } else { x };
            String::from(result)
        }).unwrap(),
    )
}

// Get QueryString and return chunk ORDER BY statement
pub fn ext_order(qs: &QueryString) -> StatementResult {
    process_statement(qs, "_order", "", "ORDER BY {}", |x| {
        let vspl = &x.split(",").collect::<Vec<&str>>();
        let od: Vec<String> = vspl.iter()
            .map(|param| {
                let mut s = String::new();
                s.push_str(param); // omg
                if s.starts_with("-") {
                    s.remove(0);
                    s.push_str(" DESC")
                }
                format!("{}", s)
            })
            .collect();
        format!("{}", od.join(","))
    })
}

// Get QueryString and return chunk GROUP BY statement
pub fn ext_groupby(qs: &QueryString) -> StatementResult {
    Ok(
        process_statement(qs, "_groupby", "", "GROUP BY {}", |x| String::from(x)).unwrap(),
    )
}

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

    #[test]
    fn get_opetators() {
        use std::collections::HashMap;

        let mut test_cases = HashMap::new();
        test_cases.insert("$eq", "=");
        test_cases.insert("$ne", "!=");
        test_cases.insert("$gt", ">");
        test_cases.insert("$gte", ">=");
        test_cases.insert("$lt", "<");
        test_cases.insert("$lte", "<=");
        test_cases.insert("$in", "IN");
        test_cases.insert("$nin", "NOT IN");
        test_cases.insert("$notnull", "IS NOT NULL");
        test_cases.insert("$null", "IS NULL");

        for (op, expected) in &test_cases {
            match query_operator(&op.to_string()) {
                Ok(x) => assert_eq!(expected.to_string(), x),
                Err(e) => assert_eq!("", e),
            }
        }
    }

    #[test]
    fn get_opetators_error() {
        let invalid = "!tn".to_string();
        match query_operator(&invalid) {
            Ok(_) => println!("no result"),
            Err(e) => assert_eq!(format!("operator {} not found", invalid), e),
        }
    }

    #[test]
    fn where_by_request_one_querystring() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "user_id".to_string(),
            v: "5".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_where(&qs).unwrap();
        assert_eq!(result.sql, "WHERE user_id=$1".to_string());
        assert_eq!(result.values, vec!["5".to_string()])
    }

    #[test]
    fn where_by_request_n_querystring() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "user_id".to_string(),
            v: "5".to_string(),
        });
        hm.push(Params {
            k: "name".to_string(),
            v: "goga".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_where(&qs).unwrap();
        assert_eq!(result.sql, "WHERE user_id=$1 AND name=$2".to_string());
        assert_eq!(result.values, vec!["5".to_string(), "goga".to_string()])
    }

    #[test]
    fn where_by_request_with_query_operators() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "user_id".to_string(),
            v: "$ne.5".to_string(),
        });
        hm.push(Params {
            k: "name".to_string(),
            v: "goga".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_where(&qs).unwrap();
        assert_eq!(result.sql, "WHERE user_id!=$1 AND name=$2".to_string());
        assert_eq!(result.values, vec!["5".to_string(), "goga".to_string()])
    }

    #[test]
    fn where_by_request_with_query_invalid_operators() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "user_id".to_string(),
            v: "$nt.5".to_string(),
        });
        hm.push(Params {
            k: "name".to_string(),
            v: "goga".to_string(),
        });

        let qs = QueryString { query: hm };
        match ext_where(&qs) {
            Err(e) => assert_eq!(e, "operator $nt not found"),
            Ok(_) => println!("no result"),
        }
    }

    #[test]
    fn select_by_request_one_column() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_select".to_string(),
            v: "name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_select(&qs).unwrap();
        assert_eq!(result.sql, "SELECT name FROM");
    }

    #[test]
    fn select_by_request_n_column() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_select".to_string(),
            v: "name,age".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_select(&qs).unwrap();
        assert_eq!(result.sql, "SELECT name,age FROM");
    }

    #[test]
    fn select_by_request_n_empty_value() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_select".to_string(),
            v: "".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_select(&qs).unwrap();
        assert_eq!(result.sql, "SELECT * FROM");
    }

    #[test]
    fn count_by_request() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_count".to_string(),
            v: "name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_count(&qs).unwrap();
        assert_eq!(result.sql, "SELECT COUNT(name) FROM");
    }

    #[test]
    fn count_by_request_all_fields() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_count".to_string(),
            v: "*".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_count(&qs).unwrap();
        assert_eq!(result.sql, "SELECT COUNT(*) FROM");
    }

    #[test]
    fn count_by_request_two_fields() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_count".to_string(),
            v: "name,age".to_string(),
        });

        let qs = QueryString { query: hm };
        match ext_count(&qs) {
            Err(e) => assert_eq!(e, "could not use more than one column in count function"),
            Ok(s) => assert_eq!(s.sql, ""),
        }
    }

    #[test]
    fn count_by_request_empty_value() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_count".to_string(),
            v: "".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_count(&qs).unwrap();
        assert_eq!(result.sql, "")
    }

    #[test]
    fn order_by_request() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "ORDER BY name")
    }

    #[test]
    fn order_by_request_desc() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "-name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "ORDER BY name DESC")
    }

    #[test]
    fn order_by_request_empty_params() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "")
    }

    #[test]
    fn order_by_request_without_params() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "name".to_string(),
            v: "toby".to_string(),
        });

        let qs = QueryString { query: hm };
        match ext_order(&qs) {
            Ok(result) => assert_eq!(result.sql, ""),
            Err(e) => assert_eq!("error on params", e),
        };
    }

    #[test]
    fn order_by_request_multiples_columns() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "name,age".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "ORDER BY name,age")
    }

    #[test]
    fn order_by_request_multiples_columns_with_orders() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "name,-age".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "ORDER BY name,age DESC")
    }

    #[test]
    fn groupby_by_request() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_groupby".to_string(),
            v: "name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_groupby(&qs).unwrap();
        assert_eq!(result.sql, "GROUP BY name")
    }

    #[test]
    fn groupby_by_request_empty_param() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: String::from("_groupby"),
            v: String::from(""),
        });

        let qs = QueryString { query: hm };
        let result = ext_groupby(&qs).unwrap();
        assert_eq!(result.sql, "")
    }
}
<|endoftext|>