1use 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
39pub trait FlatMapFn<A, I, T, U, R>: Send + 'static
45where
46 R: IntoIterator<Item = (I, U)>,
47{
48 fn execute(&self, scope: &Scope<I>, value: T) -> Result<R>;
54}
55
56impl<F, I, T, U, R> FlatMapFn<ForScope, I, T, U, R> for F
61where
62 F: Fn(&Scope<I>) -> Result<R> + Send + 'static,
63 R: IntoIterator<Item = (I, U)>,
64 I: Display,
65{
66 #[cfg_attr(
67 feature = "tracing",
68 tracing::instrument(level = "debug", skip_all, fields(scope = %scope))
69 )]
70 #[inline]
71 fn execute(&self, scope: &Scope<I>, _: T) -> Result<R> {
72 catch(|| self(scope))
73 }
74}
75
76impl<F, I, T, U, R> FlatMapFn<ForId, I, T, U, R> for F
77where
78 F: Fn(&I) -> Result<R> + Send + 'static,
79 R: IntoIterator<Item = (I, U)>,
80 I: Display,
81{
82 #[cfg_attr(
83 feature = "tracing",
84 tracing::instrument(level = "debug", skip_all, fields(scope = %scope))
85 )]
86 #[inline]
87 fn execute(&self, scope: &Scope<I>, _: T) -> Result<R> {
88 catch(|| self(scope.try_as_id()?))
89 }
90}
91
92impl<F, I, T, U, R> FlatMapFn<ForValue, I, T, U, R> for F
93where
94 F: Fn(T) -> Result<R> + Send + 'static,
95 R: IntoIterator<Item = (I, U)>,
96 I: Display,
97{
98 #[cfg_attr(
99 feature = "tracing",
100 tracing::instrument(level = "debug", skip_all, fields(scope = %scope))
101 )]
102 #[inline]
103 fn execute(&self, scope: &Scope<I>, value: T) -> Result<R> {
104 catch(|| self(value))
105 }
106}
107
108impl<F, I, T, U, R> FlatMapFn<ForScopeValue, I, T, U, R> for F
109where
110 F: Fn(&Scope<I>, T) -> Result<R> + Send + 'static,
111 R: IntoIterator<Item = (I, U)>,
112 I: Display,
113{
114 #[cfg_attr(
115 feature = "tracing",
116 tracing::instrument(level = "debug", skip_all, fields(scope = %scope))
117 )]
118 #[inline]
119 fn execute(&self, scope: &Scope<I>, value: T) -> Result<R> {
120 catch(|| self(scope, value))
121 }
122}
123
124impl<F, I, T, U, R> FlatMapFn<ForIdValue, I, T, U, R> for F
125where
126 F: Fn(&I, T) -> Result<R> + Send + 'static,
127 R: IntoIterator<Item = (I, U)>,
128 I: Display,
129{
130 #[cfg_attr(
131 feature = "tracing",
132 tracing::instrument(level = "debug", skip_all, fields(scope = %scope))
133 )]
134 #[inline]
135 fn execute(&self, scope: &Scope<I>, value: T) -> Result<R> {
136 catch(|| self(scope.try_as_id()?, value))
137 }
138}
139
140macro_rules! impl_flat_map_fn_for_splat {
146 ($($T:ident),+) => {
147 impl<F, I, $($T,)+ U, R> FlatMapFn<ForSplat, I, ($($T,)+), U, R>
148 for F
149 where
150 F: Fn($($T),+) -> Result<R> + Send + 'static,
151 R: IntoIterator<Item = (I, U)>,
152 I: Display,
153 {
154 #[cfg_attr(
155 feature = "tracing",
156 tracing::instrument(
157 level = "debug", skip_all, fields(scope = %scope)
158 )
159 )]
160 #[inline]
161 fn execute(
162 &self, scope: &Scope<I>, value: ($($T,)+)
163 ) -> Result<R> {
164 #[allow(non_snake_case)]
165 let ($($T,)+) = value;
166 catch(|| self($($T),+))
167 }
168 }
169 };
170}
171
172macro_rules! impl_flat_map_fn_for_scope_splat {
174 ($($T:ident),+) => {
175 impl<F, I, $($T,)+ U, R> FlatMapFn<ForScopeSplat, I, ($($T,)+), U, R>
176 for F
177 where
178 F: Fn(&Scope<I>, $($T),+) -> Result<R> + Send + 'static,
179 R: IntoIterator<Item = (I, U)>,
180 I: Display,
181 {
182 #[cfg_attr(
183 feature = "tracing",
184 tracing::instrument(
185 level = "debug", skip_all, fields(scope = %scope)
186 )
187 )]
188 #[inline]
189 fn execute(
190 &self, scope: &Scope<I>, value: ($($T,)+)
191 ) -> Result<R> {
192 #[allow(non_snake_case)]
193 let ($($T,)+) = value;
194 catch(|| self(scope, $($T),+))
195 }
196 }
197 };
198}
199
200macro_rules! impl_flat_map_fn_for_id_splat {
202 ($($T:ident),+) => {
203 impl<F, I, $($T,)+ U, R> FlatMapFn<ForIdSplat, I, ($($T,)+), U, R>
204 for F
205 where
206 F: Fn(&I, $($T),+) -> Result<R> + Send + 'static,
207 R: IntoIterator<Item = (I, U)>,
208 I: Display,
209 {
210 #[cfg_attr(
211 feature = "tracing",
212 tracing::instrument(
213 level = "debug", skip_all, fields(scope = %scope)
214 )
215 )]
216 #[inline]
217 fn execute(
218 &self, scope: &Scope<I>, value: ($($T,)+)
219 ) -> Result<R> {
220 #[allow(non_snake_case)]
221 let ($($T,)+) = value;
222 catch(|| self(scope.try_as_id()?, $($T),+))
223 }
224 }
225 };
226}
227
228macro_rules! impl_flat_map_fn {
230 ($($T:ident),+) => {
231 impl_flat_map_fn_for_splat!($($T),+);
232 impl_flat_map_fn_for_scope_splat!($($T),+);
233 impl_flat_map_fn_for_id_splat!($($T),+);
234 };
235}
236
237impl_flat_map_fn!(T1);
240impl_flat_map_fn!(T1, T2);
241impl_flat_map_fn!(T1, T2, T3);
242impl_flat_map_fn!(T1, T2, T3, T4);
243impl_flat_map_fn!(T1, T2, T3, T4, T5);
244impl_flat_map_fn!(T1, T2, T3, T4, T5, T6);
245impl_flat_map_fn!(T1, T2, T3, T4, T5, T6, T7);
246impl_flat_map_fn!(T1, T2, T3, T4, T5, T6, T7, T8);