Skip to main content

zrx_stream/stream/function/traits/
default.rs

1// Copyright (c) 2025-2026 Zensical and contributors
2
3// SPDX-License-Identifier: MIT
4// All contributions are certified under the DCO
5
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to
8// deal in the Software without restriction, including without limitation the
9// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10// sell copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12
13// The above copyright notice and this permission notice shall be included in
14// all copies or substantial portions of the Software.
15
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22// IN THE SOFTWARE.
23
24// ----------------------------------------------------------------------------
25
26//! Default function.
27
28use std::fmt::Display;
29
30use zrx_scheduler::action::report::IntoReport;
31use zrx_scheduler::action::Result;
32use zrx_scheduler::Value;
33
34use crate::stream::function::adapter::WithId;
35use crate::stream::function::catch;
36
37// ----------------------------------------------------------------------------
38// Traits
39// ----------------------------------------------------------------------------
40
41/// Default function.
42///
43/// This trait defines a function allowing to create a value of type `T` from an
44/// optional identifier. It is useful in scenarios where you want to ensure that
45/// each item in a stream has associated data, such as providing default values
46/// when none are present.
47///
48/// This trait is also implemented for the [`WithId`] adapter. Furthermore, the
49/// trait can be implemented for custom types to add new behaviors. Note that
50/// all implementations also allow to return a [`Report`][], which makes it
51/// possible to return diagnostics from the function execution.
52///
53/// The `'static` lifetimes is mandatory as closures must be moved into actions,
54/// so requiring it here allows us to reduce the verbosity of trait bounds.
55///
56/// [`Report`]: zrx_scheduler::action::Report
57///
58/// # Examples
59///
60/// ```
61/// # use std::error::Error;
62/// # fn main() -> Result<(), Box<dyn Error>> {
63/// use zrx_stream::function::DefaultFn;
64///
65/// // Define and execute function
66/// let f = || Some(42);
67/// f.execute(&"id")?;
68/// # Ok(())
69/// # }
70/// ```
71pub trait DefaultFn<I, T>: Send + 'static {
72    /// Executes the default function.
73    ///
74    /// # Errors
75    ///
76    /// This method returns an error if the function fails to execute.
77    fn execute(&self, id: &I) -> Result<Option<T>>;
78}
79
80// ----------------------------------------------------------------------------
81// Blanket implementations
82// ----------------------------------------------------------------------------
83
84impl<F, R, I, T> DefaultFn<I, T> for F
85where
86    F: Fn() -> R + Send + 'static,
87    R: IntoReport<Option<T>>,
88    I: Display,
89{
90    #[cfg_attr(
91        feature = "tracing",
92        tracing::instrument(level = "debug", skip_all, fields(id = %id))
93    )]
94    #[inline]
95    fn execute(&self, id: &I) -> Result<Option<T>> {
96        catch(|| self().into_report())
97    }
98}
99
100impl<F, R, I, T> DefaultFn<I, T> for WithId<F>
101where
102    F: Fn(&I) -> R + Send + 'static,
103    R: IntoReport<Option<T>>,
104    I: Display,
105    T: Value,
106{
107    #[cfg_attr(
108        feature = "tracing",
109        tracing::instrument(level = "debug", skip_all, fields(id = %id))
110    )]
111    #[inline]
112    fn execute(&self, id: &I) -> Result<Option<T>> {
113        catch(|| self(id).into_report())
114    }
115}