1#[cfg(not(feature = "boxed-trait"))]
3use std::future::Future;
4
5use crate::{Context, Result};
6
7#[cfg_attr(feature = "boxed-trait", async_trait::async_trait)]
12pub trait Guard {
13 #[cfg(feature = "boxed-trait")]
15 async fn check(&self, ctx: &Context<'_>) -> Result<()>;
16
17 #[cfg(not(feature = "boxed-trait"))]
19 fn check(&self, ctx: &Context<'_>) -> impl Future<Output = Result<()>> + Send;
20}
21
22#[cfg_attr(feature = "boxed-trait", async_trait::async_trait)]
23impl<T> Guard for T
24where
25 T: Fn(&Context<'_>) -> Result<()> + Send + Sync + 'static,
26{
27 async fn check(&self, ctx: &Context<'_>) -> Result<()> {
28 self(ctx)
29 }
30}
31
32pub trait GuardExt: Guard + Sized {
34 fn and<R: Guard>(self, other: R) -> And<Self, R> {
36 And(self, other)
37 }
38
39 fn or<R: Guard>(self, other: R) -> Or<Self, R> {
41 Or(self, other)
42 }
43}
44
45impl<T: Guard> GuardExt for T {}
46
47pub struct And<A: Guard, B: Guard>(A, B);
49
50#[cfg_attr(feature = "boxed-trait", async_trait::async_trait)]
51impl<A: Guard + Send + Sync, B: Guard + Send + Sync> Guard for And<A, B> {
52 async fn check(&self, ctx: &Context<'_>) -> Result<()> {
53 self.0.check(ctx).await?;
54 self.1.check(ctx).await
55 }
56}
57
58pub struct Or<A: Guard, B: Guard>(A, B);
60
61#[cfg_attr(feature = "boxed-trait", async_trait::async_trait)]
62impl<A: Guard + Send + Sync, B: Guard + Send + Sync> Guard for Or<A, B> {
63 async fn check(&self, ctx: &Context<'_>) -> Result<()> {
64 if self.0.check(ctx).await.is_ok() {
65 return Ok(());
66 }
67 self.1.check(ctx).await
68 }
69}