waterui_core/
handler.rs

1//! Handler traits and implementations for processing environments.
2//!
3//! This module provides a handler system that allows functions to process environments
4//! and extract parameters from them in various ways:
5//!
6//! - `Handler` - For immutable handlers that don't change during execution
7//! - `HandlerMut` - For mutable handlers that may modify their state
8//! - `HandlerOnce` - For single-use handlers that are consumed during processing
9//!
10//! The module also provides utility functions to convert regular functions into handlers
11//! with automatic parameter extraction from environments.
12
13use crate::{AnyView, View, extract::Extractor};
14use alloc::boxed::Box;
15use core::{any::type_name, fmt::Debug, marker::PhantomData};
16
17use crate::Environment;
18
19/// Type alias for an action handler that produces no result.
20pub type ActionObject = BoxHandler<()>;
21
22/// Handler trait that processes an environment and produces a result of type T.
23///
24/// This trait is implemented by handlers that don't modify themselves during execution.
25pub trait Handler<T>: 'static {
26    /// Processes the environment and returns a value of type T.
27    ///
28    /// # Arguments
29    ///
30    /// * `env` - The environment containing request data and context
31    fn handle(&mut self, env: &Environment) -> T;
32}
33
34impl<T> Debug for dyn Handler<T> {
35    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
36        f.write_str(type_name::<Self>())
37    }
38}
39
40impl<T> Debug for dyn HandlerOnce<T> {
41    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
42        f.write_str(type_name::<Self>())
43    }
44}
45
46impl Handler<()> for () {
47    fn handle(&mut self, _env: &Environment) {}
48}
49
50impl HandlerOnce<()> for () {
51    fn handle(self, _env: &Environment) {}
52}
53
54/// Handler trait for single-use handlers that are consumed during execution.
55///
56/// This trait is implemented by handlers that can only be called once because
57/// they consume themselves during processing.
58pub trait HandlerOnce<T>: 'static {
59    /// Processes the environment and returns a value of type T.
60    ///
61    /// # Arguments
62    ///
63    /// * `env` - The environment containing request data and context
64    fn handle(self, env: &Environment) -> T;
65}
66
67/// A boxed handler with dynamic dispatch.
68pub type BoxHandler<T> = Box<dyn Handler<T>>;
69
70impl<T: 'static> Handler<T> for BoxHandler<T> {
71    fn handle(&mut self, env: &Environment) -> T {
72        self.as_mut().handle(env)
73    }
74}
75
76/// A boxed one-time handler with dynamic dispatch.
77pub type BoxHandlerOnce<T> = Box<dyn HandlerOnce<T>>;
78
79impl<T: 'static> HandlerOnce<T> for Box<dyn HandlerOnce<T>> {
80    fn handle(self, env: &Environment) -> T {
81        trait CallBoxHandlerOnce<T> {
82            fn call_box(self: Box<Self>, env: &Environment) -> T;
83        }
84
85        impl<T, H> CallBoxHandlerOnce<T> for H
86        where
87            H: HandlerOnce<T>,
88        {
89            fn call_box(self: Box<Self>, env: &Environment) -> T {
90                self.handle(env)
91            }
92        }
93
94        Box::call_box(self.into(), env)
95    }
96}
97
98/// Function-like trait for immutable handlers that extract parameters from the environment.
99///
100/// P represents the parameter types to extract, T represents the return type.
101pub trait HandlerFn<P, T>: 'static {
102    /// Internal implementation that extracts parameters from the environment and calls the handler.
103    fn handle_inner(&mut self, env: &Environment) -> T;
104}
105
106/// Function-like trait for immutable handlers that extract parameters from the environment with additional state.
107///
108/// P represents the parameter types to extract, T represents the return type, S represents the state type.
109pub trait HandlerFnWithState<P, T, S>: 'static {
110    /// Internal implementation that extracts parameters from the environment and calls the handler.
111    fn handle_inner(&mut self, state: S, env: &Environment) -> T;
112}
113
114/// Function-like trait for single-use handlers that extract parameters from the environment.
115///
116/// P represents the parameter types to extract, T represents the return type.
117pub trait HandlerFnOnce<P, T>: 'static {
118    /// Internal implementation that extracts parameters from the environment and calls the handler.
119    fn handle_inner(self, env: &Environment) -> T;
120}
121
122macro_rules! impl_handle_fn {
123    ($($ty:ident),*) => {
124        #[allow(unused_variables)]
125        #[allow(non_snake_case)]
126        impl<F, R, $($ty:Extractor,)*> HandlerFn<($($ty,)*),R> for F
127        where
128            F: FnMut($($ty,)*) -> R+ 'static,
129        {
130            fn handle_inner(&mut self, env: &Environment) -> R {
131
132                $(
133                    let $ty:$ty=Extractor::extract(env).expect("failed to extract value from environment");
134                )*
135
136                self($($ty,)*)
137            }
138        }
139    };
140}
141
142macro_rules! impl_handle_fn_with_state {
143    ($($ty:ident),*) => {
144        #[allow(unused_variables)]
145        #[allow(non_snake_case)]
146        impl<F, S, R, $($ty:Extractor,)*> HandlerFnWithState<($($ty,)*),R,S> for F
147        where
148            F: FnMut(S,$($ty,)*) -> R+ 'static,
149        {
150            fn handle_inner(&mut self, state:S, env: &Environment) -> R {
151
152                $(
153                    let $ty:$ty=Extractor::extract(env).expect("failed to extract value from environment");
154                )*
155
156                self(state,$($ty,)*)
157            }
158        }
159    };
160}
161
162tuples!(impl_handle_fn_with_state);
163
164tuples!(impl_handle_fn);
165
166macro_rules! impl_handle_fn_once {
167    ($($ty:ident),*) => {
168        #[allow(unused_variables)]
169        #[allow(non_snake_case)]
170        impl<F, R, $($ty:Extractor,)*> HandlerFnOnce<($($ty,)*),R> for F
171        where
172            F: FnOnce($($ty,)*) -> R+ 'static,
173        {
174            fn handle_inner(self, env: &Environment) -> R {
175
176                $(
177                    let $ty:$ty=Extractor::extract(env).expect("failed to extract value from environment");
178                )*
179
180                self($($ty,)*)
181            }
182        }
183    };
184}
185
186tuples!(impl_handle_fn_once);
187
188macro_rules! into_handlers {
189    ($name:ident,$handler:ident,$handler_fn:ident) => {
190        /// Wrapper that converts a function into a handler.
191        #[derive(Debug, Clone)]
192        pub struct $name<H, P, T> {
193            h: H,
194            _marker: PhantomData<(P, T)>,
195        }
196
197        impl<H, P, T> $name<H, P, T>
198        where
199            H: $handler_fn<P, T>,
200        {
201            /// Creates a new handler wrapper around the given function.
202            #[must_use]
203            pub const fn new(h: H) -> Self {
204                Self {
205                    h,
206                    _marker: PhantomData,
207                }
208            }
209        }
210    };
211}
212
213/// A wrapper that allows a handler function with state to be used as a regular handler.
214#[derive(Debug)]
215pub struct IntoHandlerWithState<H, P, T, S> {
216    h: H,
217    state: S,
218    _marker: PhantomData<(P, T, S)>,
219}
220
221impl<H, P, T, S> IntoHandlerWithState<H, P, T, S>
222where
223    H: HandlerFnWithState<P, T, S>,
224    S: 'static + Clone,
225{
226    /// Creates a new handler wrapper around the given function and state.
227    #[must_use]
228    pub const fn new(h: H, state: S) -> Self {
229        Self {
230            h,
231            state,
232            _marker: PhantomData,
233        }
234    }
235}
236
237impl<H, P, T, S> Handler<T> for IntoHandlerWithState<H, P, T, S>
238where
239    H: HandlerFnWithState<P, T, S>,
240    S: 'static + Clone,
241    T: 'static,
242    P: 'static,
243{
244    fn handle(&mut self, env: &Environment) -> T {
245        self.h.handle_inner(self.state.clone(), env)
246    }
247}
248
249/// Creates a handler with associated state from a handler function and state value.
250pub const fn into_handler_with_state<H, P, T, S>(h: H, state: S) -> IntoHandlerWithState<H, P, T, S>
251where
252    H: HandlerFnWithState<P, T, S>,
253    S: 'static + Clone,
254    T: 'static,
255    P: 'static,
256{
257    IntoHandlerWithState::new(h, state)
258}
259
260into_handlers!(IntoHandler, Handler, HandlerFn);
261
262impl<H, P, T> Handler<T> for IntoHandler<H, P, T>
263where
264    H: HandlerFn<P, T>,
265    P: 'static,
266    T: 'static,
267{
268    fn handle(&mut self, env: &Environment) -> T {
269        self.h.handle_inner(env)
270    }
271}
272
273impl<H, P, T> HandlerOnce<T> for IntoHandlerOnce<H, P, T>
274where
275    H: HandlerFnOnce<P, T>,
276    P: 'static,
277    T: 'static,
278{
279    fn handle(self, env: &Environment) -> T {
280        self.h.handle_inner(env)
281    }
282}
283
284into_handlers!(IntoHandlerOnce, HandlerOnce, HandlerFnOnce);
285
286/// Converts a function into an immutable handler.
287///
288/// # Arguments
289///
290/// * `h` - The function to convert into a handler
291///
292/// # Returns
293///
294/// A handler that implements the Handler trait
295pub const fn into_handler<H, P, T>(h: H) -> IntoHandler<H, P, T>
296where
297    P: 'static,
298    T: 'static,
299    H: HandlerFn<P, T>,
300{
301    IntoHandler::new(h)
302}
303
304/// Converts a single-use function into a one-time handler.
305///
306/// # Arguments
307///
308/// * `h` - The single-use function to convert into a handler
309///
310/// # Returns
311///
312/// A handler that implements the [`HandlerOnce`] trait
313pub const fn into_handler_once<H, P, T>(h: H) -> IntoHandlerOnce<H, P, T>
314where
315    H: HandlerFnOnce<P, T>,
316    P: 'static,
317    T: 'static,
318{
319    IntoHandlerOnce::new(h)
320}
321
322/// A trait for types that can repeatedly construct views.
323///
324/// This is a convenience trait that provides similar functionality to `Fn() -> impl View`,
325/// allowing types to be used as view factories.
326pub trait ViewBuilder: 'static {
327    /// The type of view produced by this builder.
328    type Output: View;
329    /// Builds a view
330    // Note: unlike `Handler`, a `View` can obtain its `Environment` during rendering
331    // so no need to pass it here
332    fn build(&self) -> Self::Output;
333}
334
335impl<V: View, F> ViewBuilder for F
336where
337    F: 'static + Fn() -> V,
338{
339    type Output = V;
340    fn build(&self) -> Self::Output {
341        (self)()
342    }
343}
344
345/// A builder for creating views from handler functions.
346///
347/// This struct wraps a boxed handler that produces `AnyView` instances.
348pub struct AnyViewBuilder<V = AnyView>(Box<dyn ViewBuilder<Output = V>>);
349
350impl<V: View> AnyViewBuilder<V> {
351    /// Creates a new `ViewBuilder` from a handler function.
352    /// # Arguments
353    /// * `handler` - The function that builds a view from extracted parameters
354    #[must_use]
355    pub fn new(handler: impl ViewBuilder<Output = V>) -> Self {
356        Self(Box::new(handler))
357    }
358
359    /// Builds a view by invoking the underlying handler.
360    /// # Returns
361    /// An `AnyView` produced by the handler
362    #[must_use]
363    pub fn build(&self) -> V {
364        ViewBuilder::build(&*self.0)
365    }
366
367    /// Erases the specific view type, returning a builder that produces `AnyView`.
368    #[must_use]
369    pub fn erase(self) -> AnyViewBuilder<AnyView> {
370        AnyViewBuilder::new(move || {
371            let v = self.build();
372            AnyView::new(v)
373        })
374    }
375}
376
377impl<V> Debug for AnyViewBuilder<V> {
378    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
379        f.write_str("AnyViewBuilder")
380    }
381}