use crate::core::*;
use crate::strings::*;
use std::fmt;
use std::error;
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use std::path::PathBuf;
impl NodePath {
pub fn new(tree: &Tree) -> NodePath {
NodePath {
components: vec![],
tree: Rc::downgrade(&tree.0)
}
}
pub fn to_string(&self) -> String {
format!("{root}{components}", root=ROOT, components=self.components.join(PATH_SEPARATOR))
}
pub fn from(raw_path: &String, tree: &Tree) -> Result<NodePath, Error> {
let mut path = raw_path.clone();
if path.starts_with("/") {
path = path[1..].to_string();
if path.ends_with("/") {
path.pop();
}
let components = if path.is_empty() {
vec![]
} else {
path.split("/").map(|component| component.to_string()).collect::<Vec<String>>()
};
Ok(NodePath {
components,
tree: Rc::downgrade(&tree.0)
})
} else {
Err(Error::NodePathMustBeAbsolute(raw_path.clone()))
}
}
pub fn push(&self, component: String) -> NodePath {
let mut components = self.components.clone();
components.push(component);
NodePath {
components,
tree: self.tree.clone()
}
}
pub fn parent(&self) -> Option<NodePath> {
let mut components = self.components.clone();
if let Some(_) = components.pop() {
Some(NodePath {
components,
tree: self.tree.clone()
})
} else {
None
}
}
pub fn name(&self) -> Option<String> {
self.components.last().cloned()
}
pub(crate) fn tree(&self) -> Tree {
Tree(self.tree.upgrade().unwrap())
}
}
impl fmt::Display for NodePath {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}", self.to_string())
}
}
impl Node {
pub fn node_properties(&self) -> NodeProperties {
use Node::*;
match &self {
Direct(direct_node) => direct_node.node_properties.clone(),
Link(link_node) => link_node.node_properties.clone(),
}
}
pub fn get_direct(&self) -> Option<&DirectNode> {
if let Node::Direct(direct_node) = &self {
Some(direct_node)
} else {
None
}
}
}
impl InnerTree {
fn new(config: &TreeConfig) -> InnerTree {
InnerTree {
nodes: HashMap::new(),
config: config.clone()
}
}
pub(crate) fn root(&self) -> Option<Rc<RefCell<Node>>> {
let root_path = vec![];
self.nodes.get(&root_path).map(|node_ref| Rc::clone(&node_ref))
}
fn get_node(&self, node_path: &NodePath) -> Option<Rc<RefCell<Node>>> {
self.nodes.get(&node_path.components)
.map(|node_ref| Rc::clone(node_ref))
}
fn insert_node(&mut self, node_path: NodePath, node: Rc<RefCell<Node>>) -> Option<Rc<RefCell<Node>>> {
self.nodes.insert(node_path.components, node)
}
fn clear(&mut self) {
self.nodes.clear()
}
}
impl Tree {
pub fn new(config: &TreeConfig) -> Tree {
Tree(Rc::new(RefCell::new(InnerTree::new(config))))
}
pub fn root(&self) -> Option<Rc<RefCell<Node>>> {
self.0.borrow().root()
}
pub fn config(&self) -> TreeConfig {
self.0.borrow().config.clone()
}
pub fn get_node(&self, node_path: &NodePath) -> Option<Rc<RefCell<Node>>> {
self.0.borrow().get_node(node_path)
}
pub fn insert_node(&self, node_path: NodePath, node: Rc<RefCell<Node>>) -> Option<Rc<RefCell<Node>>> {
self.0.borrow_mut().insert_node(node_path, node)
}
pub fn get_node_path(&self, node: Rc<RefCell<Node>>) -> NodePath {
if let Some(parent) = node.borrow().node_properties().parent {
parent.push(node.borrow().node_properties().name.clone())
} else {
NodePath::new(&self)
}
}
pub fn get_path_buf(&self, node_path: &NodePath) -> Result<PathBuf, Error> {
let node = self.get_node(node_path).ok_or(Error::PathNotFound(node_path.clone()))?;
let node = node.borrow();
if let Some(parent) = &node.node_properties().parent {
Ok(self.get_path_buf(parent)?.join(node.node_properties().name))
} else {
let dir = node.node_properties().record_file.parent().unwrap().to_path_buf();
Ok(dir)
}
}
pub fn clear(&self) {
self.0.borrow_mut().clear()
}
pub fn resolve_node<F>(&self,
node_path: &NodePath,
resolve_handler: &F,
preserved_keys: &Vec<&'static str>) -> Result<(), Error>
where
F: Fn(&LinkNode) -> Result<(PathBuf, String), Box<dyn error::Error>> {
if let Some(node) = self.get_node(node_path) {
if let Node::Link(link_node) = &*node.borrow() {
let (path, node_str) = resolve_handler(link_node).map_err(|error| Error::Custom(error))?;
let parent_and_given_name = link_node.node_properties.parent.clone()
.map(|parent| (parent, link_node.node_properties.name.clone()));
self.insert_nodes_from_str(&node_str,
path,
parent_and_given_name,
preserved_keys)
.map_err(|de_error| Error::Custom(Box::new(de_error)))?;
self.resolve_node(node_path, resolve_handler, preserved_keys)?;
}
Ok(())
} else {
if let Some(parent) = &node_path.parent() {
self.resolve_node(&parent, resolve_handler, preserved_keys)?;
if let Some(node) = self.get_node(node_path) {
if let Node::Link(link_node) = &*node.borrow() {
let (path, node_str) = resolve_handler(link_node).map_err(|error| Error::Custom(error))?;
let parent_and_given_name = link_node.node_properties.parent.clone()
.map(|parent| (parent, link_node.node_properties.name.clone()));
self.insert_nodes_from_str(&node_str,
path,
parent_and_given_name,
preserved_keys)
.map_err(|de_error| Error::Custom(Box::new(de_error)))?;
self.resolve_node(node_path, resolve_handler, preserved_keys)?;
}
Ok(())
} else {
Err(Error::PathNotFound(node_path.clone()))
}
} else {
Err(Error::PathNotFound(node_path.clone()))
}
}
}
pub fn resolve_in_depth<F>(&self,
node_path: &NodePath,
depth: usize,
resolve_handler: &F,
preserved_keys: &Vec<&'static str>) -> Result<(), Error>
where
F: Fn(&LinkNode) -> Result<(PathBuf, String), Box<dyn error::Error>> {
let node = self.get_node(node_path).ok_or(Error::PathNotFound(node_path.clone()))?;
let node = &*node.borrow();
match node {
Node::Direct(direct_node) => {
if depth > 0 {
for child in &direct_node.children {
self.resolve_in_depth(child,
depth - 1,
resolve_handler,
preserved_keys)?;
}
}
},
Node::Link(link_node) => {
let (path, node_str) = resolve_handler(link_node).map_err(|error| Error::Custom(error))?;
let parent_and_given_name = link_node.node_properties.parent.clone()
.map(|parent| (parent, link_node.node_properties.name.clone()));
self.insert_nodes_from_str(&node_str,
path,
parent_and_given_name,
preserved_keys)
.map_err(|de_error| Error::Custom(Box::new(de_error)))?;
self.resolve_in_depth(node_path, depth, resolve_handler,
preserved_keys)?;
}
}
Ok(())
}
}
#[derive(Debug)]
pub enum Error {
PathNotFound(NodePath),
Custom(Box<dyn error::Error>),
NodePathMustBeAbsolute(String)
}
impl error::Error for Error {}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
use Error::*;
let message = match &self {
PathNotFound(path) => format!("Path {} not found.", path),
Custom(error) => format!("{}", error),
NodePathMustBeAbsolute(path) => format!("Node path must be absolute, but {} is not.", path)
};
write!(f, "{}", message)
}
}