diff --git a/apb/src/macros.rs b/apb/src/macros.rs index 04cdd61..f797b37 100644 --- a/apb/src/macros.rs +++ b/apb/src/macros.rs @@ -338,9 +338,9 @@ pub fn set_maybe_node(obj: &mut serde_json::Value, key: &str, node: crate::Node< obj, key, Some(serde_json::Value::String(l.href().to_string())), ); }, - crate::Node::Array(arr) => { + crate::Node::Array(_) => { set_maybe_value( - obj, key, Some(serde_json::Value::Array(arr.into())), + obj, key, Some(serde_json::Value::Array(node.into_iter().collect())), ); }, crate::Node::Empty => { diff --git a/apb/src/node.rs b/apb/src/node.rs index b51eea9..c1244e9 100644 --- a/apb/src/node.rs +++ b/apb/src/node.rs @@ -1,12 +1,13 @@ /// ActivityPub object node, representing either nothing, something, a link to something or /// multiple things pub enum Node { - Array(std::collections::VecDeque), // TODO would be cool to make it Box<[T]> so that Node is just a ptr + Array(std::collections::VecDeque>), // TODO would be cool to make it Box<[T]> so that Node is just a ptr Object(Box), Link(Box), // TODO feature flag to toggle these maybe? Empty, } +// TODO convert in a from_residual (iirc?) so that in rust nightly we can do ? impl From> for Node { fn from(value: Option) -> Self { match value { @@ -16,9 +17,6 @@ impl From> for Node { } } -// TODO how do i move out of the box for a moment? i need to leave it uninitialized while i update -// the value and then put it back, i think it should be safe to do so! but i'm not sure how, so i'm -// using a clone (expensive but simple solution) impl Iterator for Node { type Item = T; @@ -31,30 +29,36 @@ impl Iterator for Node { None }, Self::Array(mut arr) => { - let res = arr.pop_front(); + let mut out = None; + while let Some(res) = arr.pop_front() { + if let Some(inner) = res.extract() { + out = Some(inner); + break; + } + } *self = Self::Array(arr); - res + out } } } } impl Node { - /// return reference to embedded object (or last if many are present) + /// return reference to embedded object (or first if many are present) pub fn get(&self) -> Option<&T> { match self { Node::Empty | Node::Link(_) => None, Node::Object(x) => Some(x), - Node::Array(v) => v.front(), + Node::Array(v) => v.iter().filter_map(|x| x.get()).next(), } } - /// consume node and extract embedded object (or last if many are present) + /// return reference to embedded object (or first if many are present) pub fn extract(self) -> Option { match self { Node::Empty | Node::Link(_) => None, Node::Object(x) => Some(*x), - Node::Array(mut v) => v.pop_front(), + Node::Array(mut v) => v.pop_front()?.extract(), } } @@ -103,6 +107,15 @@ impl Node { Node::Array(arr) => Some(arr.front()?.id()?.to_string()), } } + + pub fn ids(&self) -> Vec { + match self { + Node::Empty => vec![], + Node::Link(uri) => vec![uri.href().to_string()], + Node::Object(x) => x.id().map_or(vec![], |x| vec![x.to_string()]), + Node::Array(x) => x.iter().filter_map(Self::id).collect() + } + } } #[cfg(feature = "unstructured")] @@ -115,7 +128,7 @@ impl Node { Node::Array( uris .into_iter() - .map(serde_json::Value::String) + .map(Node::link) .collect() ) } @@ -139,7 +152,12 @@ impl Node { } pub fn array(values: Vec) -> Self { - Node::Array(values.into()) + Node::Array( + std::collections::VecDeque::from_iter( + values.into_iter() + .map(Node::object) + ) + ) } #[cfg(feature = "fetch")] @@ -180,7 +198,12 @@ impl From for Node { fn from(value: serde_json::Value) -> Self { match value { serde_json::Value::String(uri) => Node::Link(Box::new(uri)), - serde_json::Value::Array(arr) => Node::Array(arr.into()), + serde_json::Value::Array(arr) => Node::Array( + std::collections::VecDeque::from_iter( + arr.into_iter() + .map(Node::from) + ) + ), serde_json::Value::Object(_) => match value.get("href") { None => Node::Object(Box::new(value)), Some(_) => Node::Link(Box::new(value)),