use crate::defs::*;
use std::fmt::Write;
const ROOT_LEVEL: usize = 0;
const ROOT_DELIMITER: char = NULL;
const ROOT_NAME: &str = "root";
const ROOT_CONTENT: &str = "";
#[derive(Debug, Clone)]
pub struct Node {
level: usize,
delimiter: char,
name: String,
content: String,
children: Vec<Node>,
}
impl Node {
pub(crate) fn root() -> Self {
Self {
level: ROOT_LEVEL,
delimiter: ROOT_DELIMITER,
name: ROOT_NAME.to_string(),
content: ROOT_CONTENT.to_string(),
children: vec![],
}
}
pub(crate) fn is_root(&self) -> bool {
self.level == ROOT_LEVEL && self.delimiter == ROOT_DELIMITER && self.name == ROOT_NAME && self.content == ROOT_CONTENT
}
pub(crate) fn new(level: usize, delimiter: char, name: String, content: String) -> Self {
Self {
level,
delimiter,
name,
content,
children: vec![],
}
}
pub(crate) fn add_child(&mut self, node: Node) {
self.children.push(node);
}
pub fn level(&self) -> usize {
self.level
}
pub fn delimiter(&self) -> char {
self.delimiter
}
pub fn name(&self) -> &str {
&self.name
}
pub fn content(&self) -> &str {
&self.content
}
pub fn text(&self) -> &str {
self.content.trim()
}
pub fn first_with_name(&self, name: impl AsRef<str>) -> Option<&Node> {
self.children.iter().find(|node| node.name == name.as_ref())
}
pub fn last_with_name(&self, name: impl AsRef<str>) -> Option<&Node> {
self.children.iter().rev().find(|node| node.name == name.as_ref())
}
pub fn children(&self) -> impl Iterator<Item = &Node> {
self.children.iter()
}
pub fn with_name(&self, name: impl AsRef<str>) -> impl Iterator<Item = &Node> {
self.children.iter().filter(move |node| node.name == name.as_ref())
}
pub fn with_names<'a>(&'a self, names: &'a [impl AsRef<str>]) -> impl Iterator<Item = &'a Node> {
let names = names.iter().map(|name| name.as_ref()).collect::<Vec<&str>>();
self.children.iter().filter(move |node| names.contains(&node.name()))
}
pub fn excluding_name(&self, name: impl AsRef<str>) -> impl Iterator<Item = &Node> {
self.children.iter().filter(move |node| node.name != name.as_ref())
}
pub fn excluding_names<'a>(&'a self, names: &'a [impl AsRef<str>]) -> impl Iterator<Item = &'a Node> {
let names = names.iter().map(|name| name.as_ref()).collect::<Vec<&str>>();
self.children.iter().filter(move |node| !names.contains(&node.name()))
}
pub fn child_count(&self) -> usize {
self.children.len()
}
pub fn document(&self, indent: usize, ch: char) -> String {
let mut buffer = String::new();
if !self.is_root() {
let indentation = if self.level > 1 {
ch.to_string().repeat((self.level - 1) * indent)
} else {
"".to_string()
};
let _ = write!(&mut buffer, "{}{}{}{}", indentation, self.delimiter, self.name, self.content);
}
for child in &self.children {
let _ = write!(&mut buffer, "{}", child.document(indent, ch));
}
buffer
}
}