use std::fmt;
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(
any(
feature = "serde",
feature = "serde-json",
feature = "serde-yaml",
feature = "serde-toml",
feature = "serde-ron"
),
derive(serde::Serialize, serde::Deserialize)
)]
pub enum Tree {
Node(String, Vec<Tree>),
Leaf(Vec<String>),
}
impl Tree {
#[inline]
pub fn new_node(label: impl Into<String>) -> Self {
Tree::Node(label.into(), Vec::new())
}
#[inline]
pub fn new_leaf(line: impl Into<String>) -> Self {
Tree::Leaf(vec![line.into()])
}
#[inline]
pub fn new_leaf_lines(lines: Vec<impl Into<String>>) -> Self {
Tree::Leaf(lines.into_iter().map(Into::into).collect())
}
pub fn add_child(&mut self, child: Tree) -> Option<&mut Self> {
match self {
Tree::Node(_, children) => {
children.push(child);
Some(self)
}
Tree::Leaf(_) => None,
}
}
#[inline]
pub fn child_count(&self) -> Option<usize> {
match self {
Tree::Node(_, children) => Some(children.len()),
Tree::Leaf(_) => None,
}
}
#[inline]
pub fn is_node(&self) -> bool {
matches!(self, Tree::Node(_, _))
}
#[inline]
pub fn is_leaf(&self) -> bool {
matches!(self, Tree::Leaf(_))
}
#[inline]
pub fn label(&self) -> Option<&str> {
match self {
Tree::Node(label, _) => Some(label),
Tree::Leaf(_) => None,
}
}
#[inline]
pub fn lines(&self) -> Option<&[String]> {
match self {
Tree::Leaf(lines) => Some(lines),
Tree::Node(_, _) => None,
}
}
#[inline]
pub fn children_mut(&mut self) -> Option<&mut Vec<Tree>> {
match self {
Tree::Node(_, children) => Some(children),
Tree::Leaf(_) => None,
}
}
#[inline]
pub fn children(&self) -> Option<&[Tree]> {
match self {
Tree::Node(_, children) => Some(children),
Tree::Leaf(_) => None,
}
}
pub fn validate(&self) -> Result<(), String> {
Ok(())
}
pub fn is_valid(&self) -> bool {
self.validate().is_ok()
}
}
impl fmt::Display for Tree {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Tree::Node(label, _) => write!(f, "Node({label})"),
Tree::Leaf(lines) => {
if lines.len() == 1 {
write!(f, "Leaf({})", lines[0])
} else {
write!(f, "Leaf([{} lines])", lines.len())
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_node() {
let node = Tree::new_node("test");
assert!(node.is_node());
assert_eq!(node.label(), Some("test"));
assert_eq!(node.child_count(), Some(0));
}
#[test]
fn test_new_leaf() {
let leaf = Tree::new_leaf("line");
assert!(leaf.is_leaf());
assert_eq!(leaf.lines(), Some(&["line".to_string()][..]));
}
#[test]
fn test_add_child() {
let mut node = Tree::new_node("root");
node.add_child(Tree::new_leaf("child"));
assert_eq!(node.child_count(), Some(1));
}
#[test]
fn test_add_child_to_leaf() {
let mut leaf = Tree::new_leaf("leaf");
assert!(leaf.add_child(Tree::new_leaf("child")).is_none());
}
}