1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use std::marker::PhantomData;

use crate::core::{
    convert::TryFromInput,
    handler::{Handler, HandlerError, HandlerResult, IntoHandlerResult},
    predicate::result::PredicateResult,
};

#[cfg(test)]
mod tests;

/// Decorates a handler with a predicate, allowing control over whether the handler should run.
///
/// The predicate must return a [`PredicateResult`].
pub struct Predicate<P, PI, H, HI> {
    predicate: P,
    predicate_input: PhantomData<PI>,
    handler: H,
    handler_input: PhantomData<HI>,
}

impl<P, PI, H, HI> Predicate<P, PI, H, HI> {
    /// Creates a new `Predicate`.
    ///
    /// # Arguments
    ///
    /// * `predicate` - A predicate handler.
    /// * `handler` - A handler to be decorated.
    pub fn new(predicate: P, handler: H) -> Self {
        Self {
            predicate,
            predicate_input: PhantomData,
            handler,
            handler_input: PhantomData,
        }
    }
}

impl<P, PI, H, HI> Handler<(PI, HI)> for Predicate<P, PI, H, HI>
where
    P: Handler<PI> + Sync + 'static,
    P::Output: Into<PredicateResult>,
    PI: TryFromInput + Sync + 'static,
    PI::Error: 'static,
    H: Handler<HI> + Sync + 'static,
    H::Output: IntoHandlerResult,
    HI: TryFromInput + Sync + 'static,
    HI::Error: 'static,
{
    type Output = PredicateOutput;

    async fn handle(&self, (predicate_input, handler_input): (PI, HI)) -> Self::Output {
        let predicate_result = self.predicate.handle(predicate_input).await.into();
        if let PredicateResult::True = predicate_result {
            self.handler.handle(handler_input).await.into_result().into()
        } else {
            predicate_result.into()
        }
    }
}

impl<P, PI, H, HI> Clone for Predicate<P, PI, H, HI>
where
    P: Clone,
    H: Clone,
{
    fn clone(&self) -> Self {
        Predicate {
            predicate: self.predicate.clone(),
            predicate_input: self.predicate_input,
            handler: self.handler.clone(),
            handler_input: self.handler_input,
        }
    }
}

/// Output of the predicate decorator
pub enum PredicateOutput {
    /// A decorated handler has been executed.
    True(HandlerResult),
    /// A decorated handler has not been executed.
    False,
    /// An error occurred during a predicate execution.
    Err(HandlerError),
}

impl From<PredicateResult> for PredicateOutput {
    fn from(result: PredicateResult) -> Self {
        match result {
            PredicateResult::True => PredicateOutput::True(Ok(())),
            PredicateResult::False => PredicateOutput::False,
            PredicateResult::Err(err) => PredicateOutput::Err(err),
        }
    }
}

impl From<HandlerResult> for PredicateOutput {
    fn from(result: HandlerResult) -> Self {
        PredicateOutput::True(result)
    }
}

impl IntoHandlerResult for PredicateOutput {
    fn into_result(self) -> HandlerResult {
        match self {
            PredicateOutput::True(result) => result,
            PredicateOutput::False => Ok(()),
            PredicateOutput::Err(err) => Err(err),
        }
    }
}