238 lines
5.7 KiB
Rust
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);
|