#![warn(missing_docs)] //! This file defines the expected behaviours of forests, and provides //! a default implementation for forests. //! //! The default forest actually implements the so-called shared packed //! parse forest, or SPPF. It packs sub-trees with the same parents //! under the same branch, and lets nodes from different branches //! share the same children, and hence the name. use graph::{error::Error as GError, GraphLabel, LabelGraph, ParentsGraph}; /// An internal type that indicates the status of a node as either a /// packed, cloned, or plain node. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)] enum ForestLabelType { Packed, #[default] Plain, Cloned(usize), } impl core::fmt::Display for ForestLabelType { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Self::Packed => write!(f, "packed"), Self::Plain => write!(f, "plain"), Self::Cloned(index) => write!(f, "the {index}-th clone"), } } } /// A type that encodes the properties demanded by a forest. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct ForestLabel { label: T, status: ForestLabelType, } impl core::fmt::Display for ForestLabel { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { writeln!(f, "label: {}, status: {}", self.label, self.status) } } /// The type of erros for converting forest labels. #[non_exhaustive] #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub enum ForestLabelError { /// Try to pack a cloned node. PackClone, /// Try to clone a packed node. ClonePack, } impl core::fmt::Display for ForestLabelError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Self::PackClone => write!(f, "cannot pack a cloned node"), Self::ClonePack => write!(f, "cannot clone a packed node"), } } } impl std::error::Error for ForestLabelError {} impl ForestLabel { /// Retrieve the label. pub fn label(&self) -> T { self.label } /// Return true if and only if this node is packed. pub fn is_packed(&self) -> bool { matches!(self.status, ForestLabelType::Packed) } /// Retrieve the optional clone index. pub fn is_cloned(&self) -> Option { match self.status { ForestLabelType::Cloned(index) => Some(index), _ => None, } } /// Try to clone a node. pub fn clone(self, forest: &F) -> Result where F: Forest, { if self.is_packed() { Err(ForestLabelError::ClonePack) } else { let clone_index = if let Some(old_index) = self.is_cloned() { let mut new_index: usize = old_index + 1; let mut new_label = Self { status: ForestLabelType::Cloned(new_index), ..self }; while forest.query_label(new_label).is_some() { new_index += 1; new_label = Self { status: ForestLabelType::Cloned(new_index), ..self }; } new_index } else { 0 }; Ok(Self { status: ForestLabelType::Cloned(clone_index), ..self }) } } /// Try to pack a node. pub fn pack(self) -> Result { if self.is_cloned().is_some() { Err(ForestLabelError::PackClone) } else { let new_label = Self { status: ForestLabelType::Packed, ..self }; Ok(new_label) } } } impl From for ForestLabel { fn from(label: T) -> Self { let status = ForestLabelType::default(); Self { label, status } } } /// The expected behaviours of a forest. /// /// Note that it requires only a subset of the functionalities of /// labelled graphs. pub trait Forest: ParentsGraph + LabelGraph> { /// The type of errors for operations on the forest. type Error: std::error::Error + From + From; /// Return the root of the forest. /// /// A forest without a root is regarded as empty. fn root(&self) -> Option; /// Construct a forest consisting of one leaf node with the given /// label. fn new_leaf(label: T) -> Self; /// Detect if the fragment is a prefix of the sub-forest rooted at /// `node_id`. fn is_prefix(&self, node_id: usize, fragment: F) -> Result where F: AsRef; /// Extend the forest by adjoining another forest at a given node. fn plant(&mut self, node_id: usize, fragment: F, planted: bool) -> Result<(), Self::Error> where F: AsRef; /// Clone a node by making a new node and making all the nodes /// that previously pointed to the old node now point to the new /// node, and the new node points to the old node. Return the /// index of the new node. In addition, if the old node had /// already been cloned, just return the index of its /// representitave. /// /// The labels of the representing node and of the cloned node /// will be handled automatically. fn clone_node(&mut self, node_id: usize) -> Result; } pub mod default; pub use default::Error;