use super::state::State;
use libdictenstein::{CharUnit, DictionaryNode};
#[derive(Clone)]
pub struct PathNode<U: CharUnit> {
label: U,
depth: u16,
parent: Option<Box<PathNode<U>>>,
}
impl<U: CharUnit> PathNode<U> {
#[inline(always)]
pub fn new(label: U, parent: Option<Box<PathNode<U>>>) -> Self {
let depth = match &parent {
Some(p) => p.depth + 1,
None => 1,
};
Self {
label,
depth,
parent,
}
}
pub fn collect_labels(&self, labels: &mut Vec<U>) {
let mut current = Some(self);
while let Some(node) = current {
labels.push(node.label);
current = node.parent.as_deref();
}
}
#[inline(always)]
pub fn depth(&self) -> usize {
self.depth as usize
}
}
pub struct Intersection<N: DictionaryNode> {
pub label: Option<N::Unit>,
pub node: N,
pub state: State,
pub parent: Option<Box<PathNode<N::Unit>>>,
}
impl<N: DictionaryNode> Intersection<N> {
pub fn new(node: N, state: State) -> Self {
Self {
label: None,
node,
state,
parent: None,
}
}
#[inline]
pub fn with_parent(
label: N::Unit,
node: N,
state: State,
parent: Option<Box<PathNode<N::Unit>>>,
) -> Self {
Self {
label: Some(label),
node,
state,
parent,
}
}
pub fn term(&self) -> String {
let mut units = Vec::new();
if let Some(label) = self.label {
units.push(label);
}
if let Some(parent) = &self.parent {
parent.collect_labels(&mut units);
}
units.reverse();
N::Unit::to_string(&units)
}
pub fn depth(&self) -> usize {
match &self.parent {
Some(parent) => 1 + parent.depth(),
None => {
if self.label.is_some() {
1
} else {
0
}
}
}
}
#[inline(always)]
pub fn is_final(&self) -> bool {
self.node.is_final()
}
#[inline(always)]
pub fn min_distance(&self) -> Option<usize> {
self.state.min_distance()
}
}
impl<N: DictionaryNode> Clone for Intersection<N> {
fn clone(&self) -> Self {
Self {
label: self.label,
node: self.node.clone(),
state: self.state.clone(),
parent: self.parent.clone(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::transducer::Position;
use libdictenstein::double_array_trie::DoubleArrayTrie;
use libdictenstein::Dictionary;
#[test]
fn test_intersection_creation() {
let dict = DoubleArrayTrie::from_terms(vec!["test"]);
let root = dict.root();
let state = State::single(Position::new(0, 0));
let intersection = Intersection::new(root, state);
assert_eq!(intersection.depth(), 0);
assert_eq!(intersection.term(), "");
}
#[test]
fn test_intersection_path_reconstruction() {
let dict = DoubleArrayTrie::from_terms(vec!["test"]);
let root = dict.root();
let t_node = root
.transition(b't')
.expect("test fixture: 't' exists in dictionary root");
let _i2 = Intersection::with_parent(
b't',
t_node.clone(),
State::new(),
None, );
let e_node = t_node
.transition(b'e')
.expect("test fixture: 'e' exists at t-node");
let _i3 = Intersection::with_parent(
b'e',
e_node.clone(),
State::new(),
Some(Box::new(PathNode::new(b't', None))), );
let s_node = e_node
.transition(b's')
.expect("test fixture: 's' exists at e-node");
let i4 = Intersection::with_parent(
b's',
s_node,
State::new(),
Some(Box::new(PathNode::new(
b'e',
Some(Box::new(PathNode::new(b't', None))),
))), );
assert_eq!(i4.term(), "tes");
assert_eq!(i4.depth(), 3);
}
}