magnetar/ext_activity_pub/src/recipe/mod.rs

98 lines
2.4 KiB
Rust

use crate::{OneOrMore, Resolvable};
use thiserror::Error;
#[macro_use]
pub mod account_move;
#[macro_use]
pub mod block;
#[macro_use]
pub mod flag;
#[macro_use]
pub mod poll;
#[macro_use]
pub mod tag;
#[derive(Debug, Error)]
pub enum RecipeError {
#[error("Serde error")]
DeserializationError(#[from] serde_json::Error),
#[error("Unexpected type: {0}")]
UnexpectedType(String),
#[error("Missing field: {0}")]
MissingField(&'static str),
#[error("Single item expected: {0}")]
ExpectedSingleField(&'static str),
#[error("Missing ID")]
MissingId,
}
#[derive(Debug, Error)]
pub struct FieldPipeline<T> {
value: T,
field_name: &'static str,
}
#[macro_export]
macro_rules! extract_field {
($obj: expr, $field: ident, $($step:ident)|+ $(|)?) => {{
let pipeline = $crate::recipe::FieldPipeline {
value: $obj.$field.as_ref(),
field_name: stringify!($field),
};
$(
let pipeline = pipeline.$step()?;
)+
pipeline.into_inner()
}};
}
impl<T> FieldPipeline<Option<T>> {
fn unwrap(self) -> Result<FieldPipeline<T>, RecipeError> {
Ok(FieldPipeline {
value: self
.value
.ok_or(RecipeError::MissingField(self.field_name))?,
field_name: self.field_name,
})
}
}
impl<T: Resolvable> FieldPipeline<&T> {
fn as_id(&self) -> Result<FieldPipeline<&str>, RecipeError> {
Ok(FieldPipeline {
value: self.value.unresolve().ok_or(RecipeError::MissingId)?,
field_name: self.field_name,
})
}
}
impl<'a, T> FieldPipeline<&'a OneOrMore<T>> {
fn single(self) -> Result<FieldPipeline<&'a T>, RecipeError> {
Ok(FieldPipeline {
value: match self.value {
OneOrMore::One(x) => Ok(x),
OneOrMore::Many(vec) if vec.len() == 1 => Ok(vec.first().unwrap()),
OneOrMore::Many(_) => Err(RecipeError::ExpectedSingleField(self.field_name)),
}?,
field_name: self.field_name,
})
}
}
impl<T: ToOwned + ?Sized> FieldPipeline<&T> {
fn owned(&self) -> Result<FieldPipeline<T::Owned>, RecipeError> {
Ok(FieldPipeline {
value: self.value.to_owned(),
field_name: self.field_name,
})
}
}
impl<T> FieldPipeline<T> {
fn into_inner(self) -> T {
self.value
}
}