From 878194e1fb45ce2aea1ee1eb5a16dbecb1a34d0f Mon Sep 17 00:00:00 2001 From: Matt Bilker Date: Sat, 18 Aug 2018 22:12:18 -0400 Subject: [PATCH] node: new container object ExtraNodes for storing extra struct nodes --- src/node/de.rs | 49 +++++++++++++++++++++++------------ src/node/extra/de.rs | 60 +++++++++++++++++++++++++++++++++++++++++++ src/node/extra/mod.rs | 41 +++++++++++++++++++++++++++++ src/node/extra/ser.rs | 24 +++++++++++++++++ src/node/mod.rs | 20 ++++++++++++++- 5 files changed, 177 insertions(+), 17 deletions(-) create mode 100644 src/node/extra/de.rs create mode 100644 src/node/extra/mod.rs create mode 100644 src/node/extra/ser.rs diff --git a/src/node/de.rs b/src/node/de.rs index 3349c98..b01c3e6 100644 --- a/src/node/de.rs +++ b/src/node/de.rs @@ -8,10 +8,36 @@ use node::Node; use node_types::StandardType; use value::Value; -struct NodeVisitor { +pub(crate) struct NodeVisitor { key: Option, } +impl<'de> NodeVisitor { + pub(crate) fn map_to_node(node_type: StandardType, key: &str, map: &mut A) -> Result + where A: MapAccess<'de> + { + match node_type { + StandardType::Attribute => Err(A::Error::custom("`Attribute` nodes must be handled elsewhere")), + StandardType::NodeStart => { + let value = try!(map.next_value_seed(NodeValueSeed(key.to_owned()))); + debug!("NodeVisitor::map_to_node() => value: {:?}", value); + + Ok(value) + }, + // TODO: roll up `NodeStart` and everything else into a single map handler + _ => { + let value = try!(map.next_value()); + debug!("NodeVisitor::map_to_node() => value: {:?}", value); + + let node = Node::new(key.to_owned(), Some(value)); + debug!("NodeVisitor::map_to_node() => node_type: {:?}, node: {:?}", node_type, node); + + Ok(node) + }, + } + } +} + impl<'de> Visitor<'de> for NodeVisitor { type Value = Node; @@ -45,18 +71,9 @@ impl<'de> Visitor<'de> for NodeVisitor { return Err(A::Error::custom("`Attribute` node must have `Value::Attribute` value")); } }, - StandardType::NodeStart => { - let value = map.next_value_seed(NodeValueSeed(key.clone()))?; - debug!("NodeVisitor::visit_map() => value: {:?}", value); - - nodes.insert(key, value); - }, _ => { - let value = map.next_value(); - debug!("NodeVisitor::visit_map() => value: {:?}", value); - - let node = Node::new(key.clone(), Some(try!(value))); - debug!("NodeVisitor::visit_map() => node_type: {:?}, node: {:?}", node_type, node); + let node = NodeVisitor::map_to_node(node_type, &key, &mut map)?; + debug!("NodeVisitor::visit_map() => node: {:?}", node); if !nodes.contains_key(&key) { nodes.insert(key, node); @@ -113,12 +130,12 @@ impl<'de> DeserializeSeed<'de> for NodeValueSeed { /// Node classifier that gets the key name and the type of the node before the /// main `Node` object handles getting the value based on the type and the /// attributes. -struct NodeSeed; +pub(crate) struct NodeSeed; #[derive(Debug)] -struct NodeStart { - key: String, - node_type: StandardType, +pub(crate) struct NodeStart { + pub(crate) key: String, + pub(crate) node_type: StandardType, } impl<'de> DeserializeSeed<'de> for NodeSeed { diff --git a/src/node/extra/de.rs b/src/node/extra/de.rs new file mode 100644 index 0000000..c2588f1 --- /dev/null +++ b/src/node/extra/de.rs @@ -0,0 +1,60 @@ +use std::fmt; + +use serde::de::{self, Deserialize, Error, MapAccess, Visitor}; + +use node::ExtraNodes; +use node::de::{NodeSeed, NodeStart, NodeVisitor}; +use node_types::StandardType; +use value::Value; + +impl<'de> Deserialize<'de> for ExtraNodes { + #[inline] + fn deserialize(deserializer: D) -> Result + where D: de::Deserializer<'de> + { + struct ExtraNodesVisitor; + + impl<'de> Visitor<'de> for ExtraNodesVisitor { + type Value = ExtraNodes; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("any valid map of kbin nodes") + } + + #[inline] + fn visit_map(self, mut map: A) -> Result + where A: MapAccess<'de> + { + trace!("ExtraNodesVisitor::visit_map()"); + + let mut extra = ExtraNodes::new(); + + while let Some(NodeStart { key, node_type }) = try!(map.next_key_seed(NodeSeed)) { + debug!("ExtraNodesVisitor::visit_map() => key: {:?}, node_type: {:?}", key, node_type); + + match node_type { + StandardType::Attribute => { + let value = try!(map.next_value()); + debug!("ExtraNodesVisitor::visit_map() => value: {:?}", value); + + if let Value::Attribute(s) = value { + let key = String::from(&key["attr_".len()..]); + extra.attributes.insert(key, s); + } else { + return Err(A::Error::custom("`Attribute` node must have `Value::Attribute` value")); + } + }, + _ => { + let node = NodeVisitor::map_to_node(node_type, &key, &mut map)?; + debug!("ExtraNodesVisitor::visit_map() => node: {:?}", node); + }, + }; + } + + Ok(extra) + } + } + + deserializer.deserialize_map(ExtraNodesVisitor) + } +} diff --git a/src/node/extra/mod.rs b/src/node/extra/mod.rs new file mode 100644 index 0000000..6e795f8 --- /dev/null +++ b/src/node/extra/mod.rs @@ -0,0 +1,41 @@ +use indexmap::IndexMap; + +use node::Node; + +mod de; +mod ser; + +/// Container for extra `Node` and `Attribute` objects that are not part of a +/// parent object +#[derive(Clone, Debug, Default, PartialEq)] +pub struct ExtraNodes { + attributes: IndexMap, + nodes: IndexMap, +} + +impl ExtraNodes { + pub fn new() -> Self { + Self { + attributes: IndexMap::new(), + nodes: IndexMap::new(), + } + } + + #[inline] + pub fn attributes(&self) -> &IndexMap { + &self.attributes + } + + #[inline] + pub fn nodes(&self) -> &IndexMap { + &self.nodes + } + + pub fn set_attr(&mut self, key: String, value: String) -> Option { + self.attributes.insert(key, value) + } + + pub fn insert(&mut self, key: String, value: Node) -> Option { + self.nodes.insert(key, value) + } +} diff --git a/src/node/extra/ser.rs b/src/node/extra/ser.rs new file mode 100644 index 0000000..e5dd41a --- /dev/null +++ b/src/node/extra/ser.rs @@ -0,0 +1,24 @@ +use serde::ser::{Serialize, SerializeMap}; + +use node::ExtraNodes; + +impl Serialize for ExtraNodes { + #[inline] + fn serialize(&self, serializer: S) -> Result + where S: ::serde::Serializer + { + trace!("::serialize()"); + + let len = self.attributes.len() + self.nodes.len(); + let mut map = serializer.serialize_map(Some(len))?; + + for (k, v) in &self.attributes { + map.serialize_entry(k, v)?; + } + for (k, v) in &self.nodes { + map.serialize_entry(k, v)?; + } + + map.end() + } +} diff --git a/src/node/mod.rs b/src/node/mod.rs index 46e6772..a6cf571 100644 --- a/src/node/mod.rs +++ b/src/node/mod.rs @@ -3,9 +3,12 @@ use indexmap::IndexMap; use value::Value; mod de; +mod extra; mod ser; -#[derive(Clone, Debug, PartialEq)] +pub use self::extra::ExtraNodes; + +#[derive(Clone, Debug, Default, PartialEq)] pub struct Node { key: String, attributes: Option>, @@ -23,11 +26,26 @@ impl Node { } } + #[inline] + pub fn key(&self) -> &str { + &self.key + } + + #[inline] + pub fn attributes(&self) -> Option<&IndexMap> { + self.attributes.as_ref() + } + #[inline] pub fn children(&self) -> Option<&IndexMap> { self.children.as_ref() } + #[inline] + pub fn value(&self) -> Option<&Value> { + self.value.as_ref() + } + pub fn set_attr(&mut self, key: String, value: String) -> Option { let attributes = self.attributes.get_or_insert_with(Default::default); attributes.insert(key, value)