upub/src/activitystream/node.rs

153 lines
3.3 KiB
Rust
Raw Normal View History

pub enum Node<T : super::Base> {
Array(Vec<Node<T>>), // TODO would be cool to make it Box<[Node<T>]> so that Node is just a ptr
Object(Box<T>),
Link(Box<dyn super::Link>),
Empty,
}
impl<T : super::Base> From<Option<T>> for Node<T> {
fn from(value: Option<T>) -> Self {
match value {
Some(x) => Node::Object(Box::new(x)),
None => Node::Empty,
}
}
}
impl<T : super::Base> Node<T> {
pub fn get(&self) -> Option<&T> {
match self {
Node::Empty | Node::Link(_) => None,
Node::Object(x) => Some(x),
2024-03-19 06:49:02 +01:00
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<Vec<&T>> {
match self {
Node::Empty | Node::Link(_) => None,
Node::Object(x) => Some(vec![x]),
Node::Array(v) =>
2024-03-19 06:49:02 +01:00
Some(v.iter().filter_map(|x| match x {
Node::Object(x) => Some(&**x),
2024-03-19 06:49:02 +01:00
_ => 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<serde_json::Value> {
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()
}
}
}
2024-03-19 06:49:02 +01:00
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<serde_json::Value>{
2024-03-20 07:54:24 +01:00
pub fn link(uri: &str) -> Self {
Node::Link(Box::new(uri.to_string()))
}
pub fn object(x: serde_json::Value) -> Self {
Node::Object(Box::new(x))
}
pub fn array(x: Vec<impl super::Base>) -> Self {
Node::Array(x.into_iter().map(|x| Node::object(x.underlying_json_object())).collect())
}
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::<serde_json::Value>()
.await?
.into();
}
Ok(())
}
}
2024-03-19 06:49:02 +01:00
impl From<Option<&str>> for Node<serde_json::Value> {
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<serde_json::Value> {
fn from(value: &str) -> Self {
Node::Link(Box::new(value.to_string()))
}
}
impl From<serde_json::Value> for Node<serde_json::Value> {
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()
2024-03-19 06:49:02 +01:00
.map(Self::from)
.collect()
),
_ => Node::Empty,
}
}
}
2024-03-19 06:49:02 +01:00