magnetar/ext_activity_pub/src/lib.rs

238 lines
5.7 KiB
Rust

pub mod link;
pub mod object;
pub mod recipe;
use crate::link::Link;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::borrow::Cow;
use std::fmt::Debug;
use std::ops::Deref;
use url::Url;
pub trait ObjectSingle: Clone + Debug + Sized + 'static {
fn get_type() -> &'static str;
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ObjectRaw<T> {
#[serde(flatten)]
data: Box<T>,
#[serde(flatten)]
raw: Value,
}
impl<T> Deref for ObjectRaw<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<T> ObjectRaw<T> {
pub fn into_inner(self) -> Box<T> {
self.data
}
}
impl<T> AsRef<T> for ObjectRaw<T> {
fn as_ref(&self) -> &T {
self.as_data()
}
}
impl<T> ObjectRaw<T> {
pub fn as_data(&self) -> &T {
&self.data
}
pub fn as_json(&self) -> &Value {
&self.raw
}
}
#[async_trait::async_trait]
pub trait Resolver: Send + Sync {
type Error: Send + Sync;
async fn resolve<T: for<'a> Deserialize<'a>>(&self, id: &str) -> Result<T, Self::Error>;
}
#[async_trait::async_trait]
pub trait Resolvable {
type Output: Clone + Send + Sync;
async fn resolve<R: Resolver>(&self, resolver: &R) -> Result<Cow<Self::Output>, R::Error>;
fn unresolve(&self) -> Option<&str>;
}
#[macro_export]
macro_rules! def_ld {
($obj_type: expr, $x: ty) => {
impl $crate::ObjectSingle for $x {
fn get_type() -> &'static str {
$obj_type
}
}
};
}
#[macro_export]
macro_rules! ld_document {
($y: ident, $x: ty) => {
impl $y {
pub async fn resolve<R: $crate::Resolver>(
&self,
resolver: &R,
) -> Result<std::borrow::Cow<ObjectRaw<$x>>, R::Error> {
match self {
$y::Object(obj) => Ok(std::borrow::Cow::Borrowed(obj)),
$y::Remote(Id(link)) => {
Ok(std::borrow::Cow::Owned(resolver.resolve(link).await?))
}
}
}
pub fn unresolve(&self) -> Option<&str> {
match self {
$y::Object(obj) => obj.as_data().as_id.as_deref(),
$y::Remote(Id(id)) => Some(&id),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum $y {
Remote(Id),
Object(Box<ObjectRaw<$x>>),
}
#[async_trait::async_trait]
impl $crate::Resolvable for $y {
type Output = $crate::ObjectRaw<$x>;
async fn resolve<R: $crate::Resolver>(
&self,
resolver: &R,
) -> Result<std::borrow::Cow<Self::Output>, R::Error> {
self.resolve(resolver).await
}
fn unresolve(&self) -> Option<&str> {
self.unresolve()
}
}
/*
impl ObjectRaw<$x> {
pub fn try_cast<T>() -> T {}
}
*/
};
}
#[macro_export]
macro_rules! ld_union {
($y: ident, $z: ident, $($item_name: ident as $item_type: ty),+) => {
impl $y {
pub async fn resolve<R: $crate::Resolver>(
&self,
resolver: &R,
) -> Result<std::borrow::Cow<ObjectRaw<$z>>, R::Error> {
match self {
$y::Object(obj) => Ok(std::borrow::Cow::Borrowed(obj)),
$y::Remote(Id(link)) => {
Ok(std::borrow::Cow::Owned(resolver.resolve(link).await?))
}
}
}
pub fn unresolve(&self) -> Option<&str> {
match self {
$y::Object(obj) => obj.as_data().base.as_id.as_deref(),
$y::Remote(Id(id)) => Some(&id),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct $z {
#[serde(flatten)]
pub base: $crate::Base,
$(
#[serde(flatten)]
$item_name: Box<$item_type>,
)+
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum $y {
Remote(Id),
Object(ObjectRaw<$z>),
}
#[async_trait::async_trait]
impl $crate::Resolvable for $y {
type Output = $crate::ObjectRaw<$z>;
async fn resolve<R: $crate::Resolver>(
&self,
resolver: &R,
) -> Result<std::borrow::Cow<Self::Output>, R::Error> {
self.resolve(resolver).await
}
fn unresolve(&self) -> Option<&str> {
self.unresolve()
}
}
};
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum OneOrMore<T> {
One(T),
Many(Vec<T>),
}
impl<T> OneOrMore<T> {
pub fn into_vec(self) -> Vec<T> {
match self {
OneOrMore::One(x) => vec![x],
OneOrMore::Many(x) => x,
}
}
pub fn iter(&self) -> std::slice::Iter<'_, T> {
match self {
OneOrMore::One(x) => std::slice::from_ref(x).iter(),
OneOrMore::Many(x) => x.iter(),
}
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Base {
#[serde(rename = "@type")]
as_type: Option<OneOrMore<String>>,
#[serde(rename = "@id")]
as_id: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum LinkOrUrl {
Url(Url),
Link(Box<Link>),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[repr(transparent)]
pub struct Id(pub String);