use std::fmt;
use std::collections::VecDeque;
use crate::traits::node_getter::NodeGetter;
use super::{ node_tree_base::NodeTreeBase, rid::RID };
#[derive(Clone, Hash, PartialEq, Eq)]
pub(crate) enum PathSeg {
Node(Box<str>), This, Parent }
impl PathSeg {
fn parse(input: &str) -> Self {
match input {
"." => Self::This,
".." => Self::Parent,
i @ _ => Self::Node(i.into())
}
}
#[inline]
fn is_empty_identifier(&self) -> bool {
if let Self::Node(str) = self {
return str.is_empty();
}
false
}
pub fn to_string(&self) -> String {
match self {
Self::Node(str) => str.to_string(),
Self::This => ".".to_string(),
Self::Parent => "..".to_string(),
}
}
}
#[derive(Clone, Default, Hash, PartialEq, Eq)]
pub struct NodePath {
path: VecDeque<PathSeg>,
abs: bool
}
impl NodePath {
pub fn new() -> NodePath {
NodePath {
path: VecDeque::new(),
abs: false
}
}
pub fn new_abs() -> NodePath {
NodePath {
path: VecDeque::new(),
abs: true
}
}
pub fn from_str(str: &str) -> NodePath {
let mut path: VecDeque<PathSeg> = str.split('/').map(PathSeg::parse).collect();
let abs: bool = path.front().map(|f| f.is_empty_identifier()).unwrap_or(false);
if abs {
path.pop_front();
}
let mut np: NodePath = NodePath {
path,
abs
};
np.scan();
np
}
pub fn to_string(mut self) -> String {
let mut out: String = String::new();
while let Some(segment) = self.pop_front() {
out += &(segment.to_string() + "/");
}
out.get(0..(out.len() - 1)).unwrap().to_string()
}
#[inline]
pub fn add_node(&mut self, node_name: &str) {
self.path.push_back(PathSeg::parse(node_name));
self.scan();
}
#[inline]
pub(crate) fn pop_front(&mut self) -> Option<PathSeg> {
self.path.pop_front()
}
#[inline]
pub fn pop_front_as_string(&mut self) -> Option<String> {
self.path.pop_front().map(|seg| seg.to_string())
}
pub fn is_absolute(&self) -> bool {
self.abs
}
#[inline]
fn scan(&mut self) {
self.path.retain(|seg| !seg.is_empty_identifier());
}
}
impl NodeGetter for NodePath {
fn get_from(&self, tree: &NodeTreeBase, caller: Option<RID>) -> Option<RID> {
if !self.is_absolute() {
return tree.get_node(caller?)?.get_node_raw(self.clone());
}
let mut absolute_path: NodePath = self.clone();
if Some(tree.root().name()) != absolute_path.pop_front_as_string().as_deref() {
return None;
}
tree.root().get_node_raw(absolute_path)
}
}
impl fmt::Debug for NodePath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut path: String = self.path.iter().map(|node| "/".to_owned() + &node.to_string()).collect();
path = "'".to_string() + &path + "'";
f.write_str(&path)?;
Ok(())
}
}
#[macro_export]
macro_rules! nodepath {
($fmt_str:literal) => {{
NodePath::from_str(&format!($fmt_str))
}};
($fmt_str:literal, $($args:expr),*) => {{
NodePath::from_str(&format!($fmt_str, $($args),*))
}};
}