//! Field guards use crate::{Context, Result}; /// Field guard /// /// Guard is a pre-condition for a field that is resolved if `Ok(())` is /// returned, otherwise an error is returned. #[async_trait::async_trait] pub trait Guard { /// Check whether the guard will allow access to the field. async fn check(&self, ctx: &Context<'_>) -> Result<()>; } #[async_trait::async_trait] impl Guard for T where T: Fn(&Context<'_>) -> Result<()> + Send + Sync + 'static, { async fn check(&self, ctx: &Context<'_>) -> Result<()> { self(ctx) } } /// An extension trait for `Guard`. pub trait GuardExt: Guard + Sized { /// Perform `and` operator on two rules fn and(self, other: R) -> And { And(self, other) } /// Perform `or` operator on two rules fn or(self, other: R) -> Or { Or(self, other) } } impl GuardExt for T {} /// Guard for [`GuardExt::and`](trait.GuardExt.html#method.and). pub struct And(A, B); #[async_trait::async_trait] impl Guard for And { async fn check(&self, ctx: &Context<'_>) -> Result<()> { self.0.check(ctx).await?; self.1.check(ctx).await } } /// Guard for [`GuardExt::or`](trait.GuardExt.html#method.or). pub struct Or(A, B); #[async_trait::async_trait] impl Guard for Or { async fn check(&self, ctx: &Context<'_>) -> Result<()> { if self.0.check(ctx).await.is_ok() { return Ok(()); } self.1.check(ctx).await } }