98 lines
2.4 KiB
Rust
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
|
|
}
|
|
}
|