dptree/handler/
inspect.rs1use crate::{
2 di::{Asyncify, Injectable},
3 from_fn_with_description, Handler, HandlerDescription, HandlerSignature,
4};
5
6use std::{collections::BTreeSet, sync::Arc};
7
8#[must_use]
13#[track_caller]
14pub fn inspect<'a, F, Output, Args, Descr>(f: F) -> Handler<'a, Output, Descr>
15where
16 Asyncify<F>: Injectable<(), Args> + Send + Sync + 'a,
17 Output: 'a,
18 Descr: HandlerDescription,
19{
20 inspect_with_description(Descr::inspect(), f)
21}
22
23#[must_use]
25#[track_caller]
26pub fn inspect_async<'a, F, Output, Args, Descr>(f: F) -> Handler<'a, Output, Descr>
27where
28 F: Injectable<(), Args> + Send + Sync + 'a,
29 Output: 'a,
30 Descr: HandlerDescription,
31{
32 inspect_async_with_description(Descr::inspect_async(), f)
33}
34
35#[must_use]
37#[track_caller]
38pub fn inspect_with_description<'a, F, Output, Args, Descr>(
39 description: Descr,
40 f: F,
41) -> Handler<'a, Output, Descr>
42where
43 Asyncify<F>: Injectable<(), Args> + Send + Sync + 'a,
44 Output: 'a,
45{
46 inspect_async_with_description(description, Asyncify(f))
47}
48
49#[must_use]
51#[track_caller]
52pub fn inspect_async_with_description<'a, F, Output, Args, Descr>(
53 description: Descr,
54 f: F,
55) -> Handler<'a, Output, Descr>
56where
57 F: Injectable<(), Args> + Send + Sync + 'a,
58 Output: 'a,
59{
60 let f = Arc::new(f);
61
62 from_fn_with_description(
63 description,
64 move |x, cont| {
65 let f = Arc::clone(&f);
66 async move {
67 {
68 let f = f.inject(&x);
69 f().await;
70 }
71
72 cont(x).await
73 }
74 },
75 HandlerSignature::Other {
76 obligations: F::obligations(),
77 guaranteed_outcomes: BTreeSet::default(),
78 conditional_outcomes: BTreeSet::default(),
79 },
80 )
81}
82
83#[cfg(test)]
84mod tests {
85 use std::{
86 ops::ControlFlow,
87 sync::atomic::{AtomicBool, Ordering},
88 };
89
90 use super::*;
91 use crate::{deps, help_inference};
92
93 #[tokio::test]
94 async fn test_inspect() {
95 let value = 123;
96 let inspect_passed = Arc::new(AtomicBool::new(false));
97 let inspect_passed_cloned = Arc::clone(&inspect_passed);
98
99 let result: ControlFlow<(), _> = help_inference(inspect(move |x: i32| {
100 assert_eq!(x, value);
101 inspect_passed_cloned.swap(true, Ordering::Relaxed);
102 }))
103 .dispatch(deps![value])
104 .await;
105
106 assert!(matches!(result, ControlFlow::Continue(_)));
107 assert!(inspect_passed.load(Ordering::Relaxed));
108 }
109}