actiondb 0.7.0

A safe and efficient unstructured text (log) parsing library.
Documentation
use std::cmp::{Ord, Ordering};
use utils::common_prefix::CommonPrefix;

use matcher::trie::node::SuffixTree;
use matcher::Pattern;

use matcher::trie::node::interface::{Entry, LiteralEntry};

#[derive(Debug, Clone)]
pub struct LiteralNode {
    literal: String,
    has_value: bool,
    pattern: Option<Pattern>,
    node: Option<SuffixTree>,
}

impl LiteralNode {
    pub fn new<S: Into<String>>(literal: S) -> LiteralNode {
        LiteralNode {
            literal: literal.into(),
            has_value: false,
            pattern: None,
            node: None,
        }
    }

    pub fn literal(&self) -> &str {
        &self.literal[..]
    }

    pub fn has_value(&self) -> bool {
        self.has_value
    }

    pub fn set_has_value(&mut self, has_value: bool) {
        self.has_value = has_value;
    }

    pub fn set_node(&mut self, node: Option<SuffixTree>) {
        self.node = node;
    }

    pub fn node_mut(&mut self) -> Option<&mut SuffixTree> {
        self.node.as_mut()
    }

    pub fn node(&self) -> Option<&SuffixTree> {
        self.node.as_ref()
    }

    pub fn cmp_str(&self, other: &str) -> Ordering {
        if self.literal.is_empty() && other.is_empty() {
            Ordering::Equal
        } else if self.literal.is_empty() {
            Ordering::Less
        } else if other.is_empty() {
            Ordering::Greater
        } else {
            self.literal[0..1].cmp(&other[0..1])
        }
    }

    pub fn split(&mut self, common_prefix_len: usize, literal: &str) {
        let common_prefix = literal.rtrunc(literal.len() - common_prefix_len);
        trace!("split(): common_prefix = {}", common_prefix);
        let mut new_node = SuffixTree::new();

        let mut left_node = {
            let left_branch = literal.ltrunc(common_prefix_len);
            trace!("split(): left_branch = {}", left_branch);
            LiteralNode::new(left_branch)
        };
        let mut right_node = {
            let right_branch = self.literal().ltrunc(common_prefix_len);
            trace!("split(): right_branch = {}", right_branch);
            LiteralNode::new(right_branch)
        };
        left_node.set_has_value(true);

        right_node.set_node(self.node.take());
        right_node.set_has_value(self.has_value);

        if let Some(pattern) = self.pattern.take() {
            right_node.set_pattern(Some(pattern));
        }

        new_node.add_literal_node(left_node);
        new_node.add_literal_node(right_node);
        self.set_node(Some(new_node));
        self.has_value = false;
        self.literal = common_prefix.to_owned();
    }

    pub fn is_leaf(&self) -> bool {
        self.node.is_none()
    }

    fn compare_first_chars(&self, other: &LiteralNode) -> Ordering {
        self.cmp_str(other.literal())
    }
}

impl Entry for LiteralNode {
    type ST = SuffixTree;
    fn pattern(&self) -> Option<&Pattern> {
        self.pattern.as_ref()
    }
    fn set_pattern(&mut self, pattern: Option<Pattern>) {
        self.pattern = pattern;
    }
    fn child(&self) -> Option<&SuffixTree> {
        self.node.as_ref()
    }
    fn child_mut(&mut self) -> Option<&mut SuffixTree> {
        self.node.as_mut()
    }
    fn set_child(&mut self, child: Option<Self::ST>) {
        self.node = child;
    }
}

impl LiteralEntry for LiteralNode {
    fn literal(&self) -> &String {
        &self.literal
    }
}

impl Eq for LiteralNode {}

impl PartialEq for LiteralNode {
    fn eq(&self, other: &Self) -> bool {
        self.compare_first_chars(other) == Ordering::Equal
    }

    fn ne(&self, other: &Self) -> bool {
        self.compare_first_chars(other) != Ordering::Equal
    }
}

impl Ord for LiteralNode {
    fn cmp(&self, other: &Self) -> Ordering {
        self.compare_first_chars(other)
    }
}

impl PartialOrd for LiteralNode {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

#[cfg(test)]
mod test {
    use matcher::trie::node::LiteralNode;
    use std::cmp::Ordering;

    #[test]
    fn given_literal_node_when_its_leafness_is_checked_the_right_result_is_returned() {
        let aleph = LiteralNode::new("aleph");

        assert_eq!(aleph.is_leaf(), true);
    }

    #[test]
    fn given_literal_node_when_it_is_compared_to_an_other_literal_node_then_only_their_first_chars_are_checked
        () {
        let alpha = LiteralNode::new("alpha");
        let beta = LiteralNode::new("beta");
        let aleph = LiteralNode::new("aleph");
        let a = LiteralNode::new("a");
        let empty = LiteralNode::new("");

        assert_eq!(alpha.cmp(&beta), Ordering::Less);
        assert_eq!(alpha.cmp(&aleph), Ordering::Equal);
        assert_eq!(beta.cmp(&alpha), Ordering::Greater);
        assert_eq!(alpha.cmp(&empty), Ordering::Greater);
        assert_eq!(empty.cmp(&alpha), Ordering::Less);
        assert_eq!(empty.cmp(&a), Ordering::Less);
        assert_eq!(empty.cmp_str("a"), Ordering::Less);
        assert_eq!(a.cmp(&empty), Ordering::Greater);
    }
}