Skip to main content

zrx_stream/stream/function/signature/
inspect.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//! Inspect function.
27
28use std::fmt::Display;
29
30use zrx_scheduler::step::Result;
31use zrx_scheduler::Scope;
32
33use crate::stream::function::arguments::{
34    ForId, ForIdSplat, ForIdValue, ForScope, ForScopeSplat, ForScopeValue,
35    ForSplat, ForValue,
36};
37use crate::stream::function::catch;
38
39// ----------------------------------------------------------------------------
40// Traits
41// ----------------------------------------------------------------------------
42
43/// Inspect function.
44pub trait InspectFn<A, I, T>: Send + 'static {
45    /// Executes the inspect function.
46    ///
47    /// # Errors
48    ///
49    /// This method returns an error if the function fails to execute.
50    fn execute(&self, scope: &Scope<I>, value: &T) -> Result;
51}
52
53// ----------------------------------------------------------------------------
54// Blanket implementations
55// ----------------------------------------------------------------------------
56
57impl<F, I, T> InspectFn<ForScope, I, T> for F
58where
59    F: Fn(&Scope<I>) -> Result + Send + 'static,
60    I: Display,
61{
62    #[cfg_attr(
63        feature = "tracing",
64        tracing::instrument(level = "debug", skip_all, fields(scope = %scope))
65    )]
66    #[inline]
67    fn execute(&self, scope: &Scope<I>, _: &T) -> Result {
68        catch(|| self(scope))
69    }
70}
71
72impl<F, I, T> InspectFn<ForId, I, T> for F
73where
74    F: Fn(&I) -> Result + Send + 'static,
75    I: Display,
76{
77    #[cfg_attr(
78        feature = "tracing",
79        tracing::instrument(level = "debug", skip_all, fields(scope = %scope))
80    )]
81    #[inline]
82    fn execute(&self, scope: &Scope<I>, _: &T) -> Result {
83        catch(|| self(scope.try_as_id()?))
84    }
85}
86
87impl<F, I, T> InspectFn<ForValue, I, T> for F
88where
89    F: Fn(&T) -> Result + Send + 'static,
90    I: Display,
91{
92    #[cfg_attr(
93        feature = "tracing",
94        tracing::instrument(level = "debug", skip_all, fields(scope = %scope))
95    )]
96    #[inline]
97    fn execute(&self, scope: &Scope<I>, value: &T) -> Result {
98        catch(|| self(value))
99    }
100}
101
102impl<F, I, T> InspectFn<ForScopeValue, I, T> for F
103where
104    F: Fn(&Scope<I>, &T) -> Result + Send + 'static,
105    I: Display,
106{
107    #[cfg_attr(
108        feature = "tracing",
109        tracing::instrument(level = "debug", skip_all, fields(scope = %scope))
110    )]
111    #[inline]
112    fn execute(&self, scope: &Scope<I>, value: &T) -> Result {
113        catch(|| self(scope, value))
114    }
115}
116
117impl<F, I, T> InspectFn<ForIdValue, I, T> for F
118where
119    F: Fn(&I, &T) -> Result + Send + 'static,
120    I: Display,
121{
122    #[cfg_attr(
123        feature = "tracing",
124        tracing::instrument(level = "debug", skip_all, fields(scope = %scope))
125    )]
126    #[inline]
127    fn execute(&self, scope: &Scope<I>, value: &T) -> Result {
128        catch(|| self(scope.try_as_id()?, value))
129    }
130}
131
132// ----------------------------------------------------------------------------
133// Macros
134// ----------------------------------------------------------------------------
135
136/// Implements inspect function trait for splat arguments.
137macro_rules! impl_inspect_fn_for_splat {
138    ($($T:ident),+) => {
139        impl<F, I, $($T,)+> InspectFn<ForSplat, I, ($($T,)+)> for F
140        where
141            F: Fn($(&$T),+) -> Result + Send + 'static,
142            I: Display,
143        {
144            #[cfg_attr(
145                feature = "tracing",
146                tracing::instrument(
147                    level = "debug", skip_all, fields(scope = %scope)
148                )
149            )]
150            #[inline]
151            fn execute(
152                &self, scope: &Scope<I>, value: &($($T,)+)
153            ) -> Result {
154                #[allow(non_snake_case)]
155                let ($($T,)+) = value;
156                catch(|| self($($T),+))
157            }
158        }
159    };
160}
161
162/// Implements inspect function trait for scope and splat arguments.
163macro_rules! impl_inspect_fn_for_scope_splat {
164    ($($T:ident),+) => {
165        impl<F, I, $($T,)+> InspectFn<ForScopeSplat, I, ($($T,)+)> for F
166        where
167            F: Fn(&Scope<I>, $(&$T),+) -> Result + Send + 'static,
168            I: Display,
169        {
170            #[cfg_attr(
171                feature = "tracing",
172                tracing::instrument(
173                    level = "debug", skip_all, fields(scope = %scope)
174                )
175            )]
176            #[inline]
177            fn execute(
178                &self, scope: &Scope<I>, value: &($($T,)+)
179            ) -> Result {
180                #[allow(non_snake_case)]
181                let ($($T,)+) = value;
182                catch(|| self(scope, $($T),+))
183            }
184        }
185    };
186}
187
188/// Implements inspect function trait for identifier and splat arguments.
189macro_rules! impl_inspect_fn_for_id_splat {
190    ($($T:ident),+) => {
191        impl<F, I, $($T,)+> InspectFn<ForIdSplat, I, ($($T,)+)> for F
192        where
193            F: Fn(&I, $(&$T),+) -> Result + Send + 'static,
194            I: Display,
195        {
196            #[cfg_attr(
197                feature = "tracing",
198                tracing::instrument(
199                    level = "debug", skip_all, fields(scope = %scope)
200                )
201            )]
202            #[inline]
203            fn execute(
204                &self, scope: &Scope<I>, value: &($($T,)+)
205            ) -> Result {
206                #[allow(non_snake_case)]
207                let ($($T,)+) = value;
208                catch(|| self(scope.try_as_id()?, $($T),+))
209            }
210        }
211    };
212}
213
214/// Implements inspect function traits.
215macro_rules! impl_inspect_fn {
216    ($($T:ident),+) => {
217        impl_inspect_fn_for_splat!($($T),+);
218        impl_inspect_fn_for_scope_splat!($($T),+);
219        impl_inspect_fn_for_id_splat!($($T),+);
220    };
221}
222
223// ----------------------------------------------------------------------------
224
225impl_inspect_fn!(T1);
226impl_inspect_fn!(T1, T2);
227impl_inspect_fn!(T1, T2, T3);
228impl_inspect_fn!(T1, T2, T3, T4);
229impl_inspect_fn!(T1, T2, T3, T4, T5);
230impl_inspect_fn!(T1, T2, T3, T4, T5, T6);
231impl_inspect_fn!(T1, T2, T3, T4, T5, T6, T7);
232impl_inspect_fn!(T1, T2, T3, T4, T5, T6, T7, T8);