pub enum Node { Array(Vec>), // TODO would be cool to make it Box<[Node]> so that Node is just a ptr Object(Box), Link(Box), Empty, } impl From> for Node { fn from(value: Option) -> Self { match value { Some(x) => Node::Object(Box::new(x)), None => Node::Empty, } } } impl Node { pub fn get(&self) -> Option<&T> { match self { Node::Empty | Node::Link(_) => None, Node::Object(x) => Some(x), Node::Array(v) => match v.iter().find_map(|x| match x { Node::Object(x) => Some(x), _ => None, }) { Some(x) => Some(x), None => None, }, } } pub fn all(&self) -> Option> { match self { Node::Empty | Node::Link(_) => None, Node::Object(x) => Some(vec![x]), Node::Array(v) => Some(v.iter().filter_map(|x| match x { Node::Object(x) => Some(&**x), _ => None, }).collect()), } } pub fn is_empty(&self) -> bool { match self { Node::Empty | Node::Link(_) => true, Node::Object(_) | Node::Array(_) => false, } } pub fn len(&self) -> usize { match self { Node::Empty => 0, Node::Link(_) => 0, Node::Object(_) => 1, Node::Array(v) => v.len(), } } pub fn flat(self) -> Vec { match self { Node::Empty => vec![], Node::Link(l) => vec![serde_json::Value::String(l.href().to_string())], Node::Object(x) => vec![x.underlying_json_object()], Node::Array(arr) => { arr .into_iter() .filter_map(|node| match node { Node::Empty | Node::Link(_) => None, Node::Object(o) => Some(o.underlying_json_object()), Node::Array(_) => Some(serde_json::Value::Array(node.flat())), }).collect() } } } pub fn id(&self) -> Option<&str> { match self { Node::Empty => None, Node::Link(uri) => Some(uri.href()), Node::Object(obj) => obj.id(), Node::Array(arr) => arr.first()?.id(), } } } impl Node{ pub async fn fetch(&mut self) -> reqwest::Result<()> { if let Node::Link(link) = self { *self = reqwest::Client::new() .get(link.href()) .header("Accept", "application/json") .send() .await? .json::() .await? .into(); } Ok(()) } } impl From> for Node { fn from(value: Option<&str>) -> Self { match value { Some(x) => Node::Link(Box::new(x.to_string())), None => Node::Empty, } } } impl From<&str> for Node { fn from(value: &str) -> Self { Node::Link(Box::new(value.to_string())) } } 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::Object(_) => match value.get("href") { None => Node::Object(Box::new(value)), Some(_) => Node::Link(Box::new(value)), }, serde_json::Value::Array(arr) => Node::Array( arr .into_iter() .map(Self::from) .collect() ), _ => Node::Empty, } } }