duckling 0.4.0

A Rust port of Facebook's Duckling library for parsing natural language into structured data
Documentation
use crate::types::Node;
use std::collections::BTreeMap;

/// A Stash stores parsed nodes keyed by their start position.
/// This allows efficient lookup of nodes at a given position.
#[derive(Debug, Clone, Default)]
pub struct Stash {
    nodes: BTreeMap<usize, Vec<Node>>,
    count: usize,
}

impl Stash {
    pub fn new() -> Self {
        Stash {
            nodes: BTreeMap::new(),
            count: 0,
        }
    }

    pub fn add(&mut self, node: Node) {
        self.nodes.entry(node.range.start).or_default().push(node);
        self.count = self.count.saturating_add(1);
    }

    pub fn all_nodes(&self) -> impl Iterator<Item = &Node> {
        self.nodes.values().flat_map(|v| v.iter())
    }

    pub fn is_empty(&self) -> bool {
        self.count == 0
    }

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

    pub fn merge_from(&mut self, other: Stash) {
        for (_pos, nodes) in other.nodes {
            for node in nodes {
                self.nodes.entry(node.range.start).or_default().push(node);
                self.count = self.count.saturating_add(1);
            }
        }
    }

    /// Consume the stash and return an iterator over all owned nodes.
    pub fn into_nodes(self) -> impl Iterator<Item = Node> {
        self.nodes.into_values().flat_map(|v| v.into_iter())
    }

    /// Iterate over nodes starting at or after the given position.
    /// Uses BTreeMap's range for efficient lookup.
    pub fn nodes_starting_from(&self, pos: usize) -> impl Iterator<Item = &Node> {
        self.nodes.range(pos..).flat_map(|(_, v)| v.iter())
    }
}