use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use std::error;
use std::fmt;
use std::path::PathBuf;
use crate::core::*;
use crate::strings::*;
use serde::Deserialize;
use serde_json;
#[derive(Debug, Deserialize)]
struct RawNode {
#[serde(flatten)]
properties: HashMap<String, String>,
children: Option<Vec<Rc<RefCell<RawNode>>>>
}
enum RawNodeType {
Direct,
Link
}
impl RawNodeType {
fn from_str(s: &str) -> Option<RawNodeType> {
use RawNodeType::*;
match s {
"Direct" => Some(Direct),
"Link" => Some(Link),
_ => None
}
}
}
impl Default for RawNodeType {
fn default() -> Self {
RawNodeType::Direct
}
}
impl RawNode {
fn convert_to_nodes(raw_node: &Rc<RefCell<RawNode>>,
parent: Option<NodePath>,
given_name: Option<String>,
tree: &Tree,
record_file: &PathBuf,
preserved_keys: &Vec<&'static str>) -> Result<Vec<(NodePath, Rc<RefCell<Node>>)>, Error> {
let raw_node_type = if let Some(node_type_str) = raw_node.borrow().properties.get("type") {
RawNodeType::from_str(node_type_str).ok_or(Error::UnknownType(node_type_str.to_owned()))?
} else {
RawNodeType::default()
};
match raw_node_type {
RawNodeType::Direct => {
let name = if let Some(name) = given_name {
name
} else {
raw_node.borrow().properties.get(NAME).cloned().ok_or(Error::LackName)?
};
let path = if let Some(parent) = &parent {
parent.push(name.clone())
} else {
NodePath::new(tree)
};
let node_properties = NodeProperties {
name,
parent,
record_file: record_file.clone(),
};
let sub_node_children = if let Some(children) = &raw_node.borrow().children {
children.iter()
.map(|sub_node| -> Result<_, Error> {
RawNode::convert_to_nodes(sub_node, Some(path.clone()), None, tree, record_file, preserved_keys)
})
.collect::<Result<Vec<_>, Error>>()?
} else {
vec![]
};
let sub_nodes = sub_node_children.iter().map(|children| {
children.last().unwrap().0.clone()
}).collect::<Vec<_>>();
let raw_node = raw_node.borrow();
let keys = raw_node.properties.keys();
for key in keys {
if preserved_keys.contains(&key.as_str()) {
return Err(Error::PreservedKey(key.clone()));
}
}
let node = Rc::new(RefCell::new(Node::Direct(DirectNode {
children: sub_nodes,
node_properties,
properties: raw_node.properties.clone(),
})));
let mut nodes = sub_node_children.into_iter().flatten().collect::<Vec<_>>();
nodes.push((path, node));
Ok(nodes)
},
RawNodeType::Link => {
let name = if let Some(name) = given_name {
name
} else {
raw_node.borrow().properties.get("name").cloned().ok_or(Error::LackName)?
};
let path = if let Some(parent) = &parent {
parent.push(name.clone())
} else {
NodePath::new(tree)
};
let node_properties = NodeProperties {
name,
parent,
record_file: record_file.clone(),
};
let link_node = Rc::new(RefCell::new(Node::Link(LinkNode {
node_properties,
target: PathBuf::from(raw_node.borrow().properties.get("target").cloned().ok_or(Error::LackTarget)?)
})));
Ok(vec![(path, link_node)])
},
}
}
}
impl Tree {
pub fn insert_nodes_from_str(&self,
node_str: &str,
recorded_file: PathBuf,
parent_and_given_name: Option<(NodePath, String)>,
preserved_keys: &Vec<&'static str>) -> Result<Rc<RefCell<Node>>, Error> {
let raw_node = serde_json::from_str::<RawNode>(node_str).map_err(|error| Error::ParsingFailed(error))?;
let raw_node = Rc::new(RefCell::new(raw_node));
let (parent, given_name) = if let Some((parent, given_name)) = parent_and_given_name {
(Some(parent), given_name)
} else {
(None, self.config().project_name.clone())
};
let nodes = RawNode::convert_to_nodes(&raw_node,
parent,
Some(given_name),
&self,
&recorded_file,
preserved_keys)?;
let root = Rc::clone(&nodes.last().unwrap().1);
for (path, node) in nodes {
self.insert_node(path, node);
}
Ok(root)
}
}
#[derive(Debug)]
pub enum Error {
ParsingFailed(serde_json::error::Error),
UnknownType(String),
LackName,
LackTarget,
PreservedKey(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 {
ParsingFailed(error) => format!("JSON syntax parsing error: {}", error),
UnknownType(type_str) => format!("Unknown type {}", type_str),
LackName => String::from("Lack name"),
LackTarget => String::from(r#"The node whose type is "Link" lacks target"#),
PreservedKey(key) => format!("Key {} is preserved.", key),
};
write!(f, "{}", message)
}
}
impl From<serde_json::error::Error> for Error {
fn from(error: serde_json::error::Error) -> Self {
Error::ParsingFailed(error)
}
}