cling/
effects.rs

1use crate::params::CollectedArgs;
2use crate::prelude::CliError;
3use crate::State;
4
5// Internal struct, not meant for public use.
6pub struct _Sync;
7// Internal struct, not meant for public use.
8pub struct _Async;
9
10/// A type returned by handlers to set state for downstream handlers
11#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
12pub struct SetState<S: Clone + Send + Sync + 'static>(pub S);
13
14/// Defines the handler effect behaviour
15pub trait HandlerEffect {
16    fn apply_effect(self, args: &mut CollectedArgs);
17}
18
19impl HandlerEffect for () {
20    fn apply_effect(self, _args: &mut CollectedArgs) {}
21}
22
23impl<S> HandlerEffect for SetState<S>
24where
25    S: Clone + Send + Sync + 'static,
26{
27    fn apply_effect(self, args: &mut CollectedArgs) {
28        args.insert(State(self.0), true)
29    }
30}
31
32/// Handlers can return any type that implements this trait
33#[async_trait::async_trait]
34pub trait IntoEffect<Type> {
35    type Effect: HandlerEffect;
36
37    async fn into_effect(self) -> Result<Self::Effect, CliError>;
38}
39
40#[async_trait::async_trait]
41impl IntoEffect<_Sync> for () {
42    type Effect = ();
43
44    async fn into_effect(self) -> Result<(), CliError> {
45        Ok(())
46    }
47}
48
49#[async_trait::async_trait]
50impl<S> IntoEffect<_Sync> for State<S>
51where
52    S: Clone + Send + Sync + 'static,
53{
54    type Effect = SetState<S>;
55
56    async fn into_effect(self) -> Result<Self::Effect, CliError> {
57        Ok(SetState(self.0))
58    }
59}
60
61#[async_trait::async_trait]
62impl<S> IntoEffect<_Sync> for SetState<S>
63where
64    S: Clone + Send + Sync + 'static,
65{
66    type Effect = SetState<S>;
67
68    async fn into_effect(self) -> Result<Self::Effect, CliError> {
69        Ok(self)
70    }
71}
72
73#[async_trait::async_trait]
74impl<E, F> IntoEffect<_Sync> for Result<F, E>
75where
76    E: Into<CliError>,
77    F: IntoEffect<_Sync> + Send,
78    Self: Send,
79{
80    type Effect = F::Effect;
81
82    async fn into_effect(self) -> Result<Self::Effect, CliError> {
83        match self {
84            | Ok(f) => f.into_effect().await,
85            | Err(e) => Err(e.into()),
86        }
87    }
88}
89
90/// Adaptor to allow async handlers as long as their return type is also
91/// [IntoEffect]
92#[async_trait::async_trait]
93impl<T, Output> IntoEffect<_Async> for T
94where
95    T: std::future::Future<Output = Output> + Send,
96    Output: IntoEffect<_Sync> + Send,
97{
98    type Effect = Output::Effect;
99
100    async fn into_effect(self) -> Result<Self::Effect, CliError> {
101        self.await.into_effect().await
102    }
103}