Skip to main content

apalis_core/backend/ext/
delegate.rs

1//! A helper macros to delegate `Backend` trait methods from a wrapper type to its inner backend field.
2
3/// This macro is used to implement the `Sink` trait for a wrapper type that contains a backend field. It delegates the `Sink` methods to the inner backend field, allowing the wrapper type to behave like a `Sink` without having to manually implement each method.
4#[macro_export]
5macro_rules! delegate_sink {
6    ($wrapper:ident<$($lt:lifetime,)? $backend:ident $(, $rest:ident)* $(,)?>, $field:ident) => {
7        impl<$($lt,)? $backend, $($rest,)* T, Err> Sink<T> for $wrapper<$($lt,)? $backend, $($rest,)*>
8        where
9            $backend: Sink<T, Error = Err> + Unpin,
10            $($rest: Unpin,)*
11        {
12            type Error = Err;
13
14            fn start_send(self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> {
15                self.get_mut().$field.start_send_unpin(item)
16            }
17
18            fn poll_ready(
19                self: Pin<&mut Self>,
20                cx: &mut Context<'_>,
21            ) -> Poll<Result<(), Self::Error>> {
22                self.get_mut().$field.poll_ready_unpin(cx)
23            }
24
25            fn poll_flush(
26                self: Pin<&mut Self>,
27                cx: &mut Context<'_>,
28            ) -> Poll<Result<(), Self::Error>> {
29                self.get_mut().$field.poll_flush_unpin(cx)
30            }
31
32            fn poll_close(
33                self: Pin<&mut Self>,
34                cx: &mut Context<'_>,
35            ) -> Poll<Result<(), Self::Error>> {
36                self.get_mut().$field.poll_close_unpin(cx)
37            }
38        }
39    };
40}
41
42/// This macro is used to implement the `Deref` and `DerefMut` traits for a wrapper type
43/// that contains a backend field. It delegates to the inner backend field, allowing the
44/// wrapper type to behave like the backend without having to manually implement each method.
45#[macro_export]
46macro_rules! delegate_deref {
47    ($wrapper:ident<$($lt:lifetime,)? $backend:ident $(, $rest:ident)* $(,)?>, $field:ident) => {
48        impl<$($lt,)? $backend, $($rest,)*> std::ops::Deref for $wrapper<$($lt,)? $backend, $($rest,)*> {
49            type Target = $backend;
50
51            fn deref(&self) -> &Self::Target {
52                &self.$field
53            }
54        }
55
56        impl<$($lt,)? $backend, $($rest,)*> std::ops::DerefMut for $wrapper<$($lt,)? $backend, $($rest,)*> {
57            fn deref_mut(&mut self) -> &mut Self::Target {
58                &mut self.$field
59            }
60        }
61    };
62}
63
64/// This macro is used to implement the `BackendConfig` trait for a wrapper type that
65/// contains a backend field. It delegates the associated types and methods to the inner
66/// backend field, allowing the wrapper type to behave like a `BackendConfig` without having
67/// to manually implement each item.
68#[macro_export]
69macro_rules! delegate_config {
70    ($wrapper:ident<$($lt:lifetime,)? $backend:ident $(, $rest:ident)* $(,)?>, $field:ident) => {
71        impl<$($lt,)? $backend, $($rest,)*> BackendConfig for $wrapper<$($lt,)? $backend, $($rest,)*>
72        where
73            $backend: BackendConfig,
74        {
75            type Id = $backend::Id;
76            type Args = $backend::Args;
77            type Kind = $backend::Kind;
78            type Config = $backend::Config;
79            type Layer = $backend::Layer;
80
81            fn config(&self) -> &Self::Config {
82                self.$field.config()
83            }
84
85            fn middleware(&mut self, worker: &mut WorkerContext) -> Self::Layer {
86                self.$field.middleware(worker)
87            }
88        }
89    };
90}
91
92/// This macro is used to implement the `WireFormatBackend` trait for a wrapper type that
93/// contains a backend field. It delegates the associated types and methods to the inner
94/// backend field, allowing the wrapper type to behave like a `WireFormatBackend` without having
95/// to manually implement each item.
96#[macro_export]
97macro_rules! delegate_codec {
98    ($wrapper:ident<$($lt:lifetime,)? $backend:ident $(, $rest:ident)* $(,)?>, $field:ident) => {
99        impl<$($lt,)? $backend, $($rest,)*> WireFormatBackend for $wrapper<$($lt,)? $backend, $($rest,)*>
100        where
101            $backend: WireFormatBackend,
102        {
103            type Compact = $backend::Compact;
104            type Codec = $backend::Codec;
105
106            fn codec(&self) -> &Self::Codec {
107                self.$field.codec()
108            }
109        }
110    };
111}
112
113/// Delegates FetchById, Update, Reschedule, Vacuum, ResumeById,
114/// ResumeAbandoned, RegisterWorker, and WaitForCompletion to a named field
115/// in one call. The caller supplies shared extra bounds, and optionally a
116/// `wrap` expression applied to every delegated method's `Result`.
117///
118/// `wrap` receives the `Result<T, B::Error>` returned by the inner call and
119/// must produce the wrapper's own `Result<T, Self::Error>` — use it for
120/// `.map_err(...)`, logging, retries, or any other postprocessing.
121///
122/// The `impl<...>` generic list may include a leading lifetime (e.g. `impl<'a, B>`)
123/// when the wrapper type itself is generic over a lifetime.
124///
125/// ```ignore
126/// // plain forwarding
127/// delegate_expose!(
128///     impl<B> for RawDataBackend<B>
129///     where {
130///         B: Send + 'static,
131///         B::Compact: Send + Clone + 'static,
132///     }
133///     => inner
134/// );
135///
136/// // with a lifetime parameter
137/// delegate_expose!(
138///     impl<'a, B> for BorrowedBackend<'a, B>
139///     where {
140///         B: Send + 'static,
141///     }
142///     => inner
143/// );
144///
145/// // with postprocessing
146/// delegate_expose!(
147///     impl<B, F, E2> for MapErr<B, F>
148///     where {
149///         B: Backend,
150///         F: Fn(B::Error) -> E2,
151///         E2: std::error::Error + Send + Sync + 'static,
152///     }
153///     => backend,
154///     wrap = |this, result| result.map_err(|err| (this.f)(err))
155/// );
156/// ```
157#[macro_export]
158macro_rules! delegate_expose {
159    (
160        impl<$($lt:lifetime),* $(,)? $($generic:ident),+> for $wrapper:ty
161        where { $($bound:tt)+ }
162        => $field:ident
163    ) => {
164        $crate::delegate_expose!(
165            impl<$($lt),* , $($generic),+> for $wrapper
166            where { $($bound)+ }
167            => $field,
168            wrap = |this, result| result
169        );
170    };
171    (
172        impl<$($lt:lifetime),* $(,)? $($generic:ident),+> for $wrapper:ty
173        where { $($bound:tt)+ }
174        => $field:ident,
175        wrap = |$this:ident, $result:ident| $wrap_body:expr
176    ) => {
177        impl<$($lt,)* $($generic),+> FetchById for $wrapper
178        where
179            B: FetchById,
180            B::Task: Send,
181            $($bound)+
182        {
183            async fn fetch_by_id(
184                &mut self,
185                task_id: &$crate::task::task_id::TaskId,
186            ) -> Result<Option<B::Task>, Self::Error> {
187                let $result = self.$field.fetch_by_id(task_id).await;
188                #[allow(unused_variables)]
189                let $this = &*self;
190                $wrap_body
191            }
192        }
193
194        impl<$($lt,)* $($generic),+> Update for $wrapper
195        where
196            B: Update + Send,
197            B::Task: Send,
198            $($bound)+
199        {
200            async fn update(
201                &mut self,
202                task: Self::Task,
203            ) -> Result<(), Self::Error> {
204                let $result = self.$field.update(task).await;
205                #[allow(unused_variables)]
206                let $this = &*self;
207                $wrap_body
208            }
209        }
210
211        impl<$($lt,)* $($generic),+> Reschedule for $wrapper
212        where
213            B: Reschedule,
214            B::Task: Send,
215            $($bound)+
216        {
217            async fn reschedule(
218                &mut self,
219                task: Self::Task,
220                wait: std::time::Duration,
221            ) -> Result<(), Self::Error> {
222                let $result = self.$field.reschedule(task, wait).await;
223                #[allow(unused_variables)]
224                let $this = &*self;
225                $wrap_body
226            }
227        }
228
229        impl<$($lt,)* $($generic),+> Vacuum for $wrapper
230        where
231            B: Vacuum,
232            $($bound)+
233        {
234            async fn vacuum(&mut self) -> Result<usize, Self::Error> {
235                let $result = self.$field.vacuum().await;
236                #[allow(unused_variables)]
237                let $this = &*self;
238                $wrap_body
239            }
240
241            async fn vacuum_before(&mut self, duration: Duration) -> Result<usize, Self::Error> {
242                let $result = self.$field.vacuum_before(duration).await;
243                #[allow(unused_variables)]
244                let $this = &*self;
245                $wrap_body
246            }
247        }
248
249        impl<$($lt,)* $($generic),+> ResumeById for $wrapper
250        where
251            B: ResumeById,
252            $($bound)+
253        {
254            async fn resume_by_id(
255                &mut self,
256                id: TaskId,
257            ) -> Result<bool, Self::Error> {
258                let $result = self.$field.resume_by_id(id).await;
259                #[allow(unused_variables)]
260                let $this = &*self;
261                $wrap_body
262            }
263        }
264
265        impl<$($lt,)* $($generic),+> ResumeAbandoned for $wrapper
266        where
267            B: ResumeAbandoned,
268            $($bound)+
269        {
270            async fn resume_abandoned(&mut self) -> Result<usize, Self::Error> {
271                let $result = self.$field.resume_abandoned().await;
272                #[allow(unused_variables)]
273                let $this = &*self;
274                $wrap_body
275            }
276        }
277
278        impl<$($lt,)* $($generic),+> RegisterWorker for $wrapper
279        where
280            B: RegisterWorker,
281            $($bound)+
282        {
283            async fn register_worker(&mut self, worker_id: String) -> Result<(), Self::Error> {
284                let $result = self.$field.register_worker(worker_id).await;
285                #[allow(unused_variables)]
286                let $this = &*self;
287                $wrap_body
288            }
289        }
290
291        impl<$($lt,)* Output, $($generic),+> WaitForCompletion<Output> for $wrapper
292        where
293            B: WaitForCompletion<Output> + Sync,
294            Output: 'static,
295            $($bound)+
296        {
297            type ResultStream = futures_core::stream::BoxStream<'static, Result<TaskResult<Output>, Self::Error>>;
298
299            fn wait_for(
300                &mut self,
301                task_ids: impl IntoIterator<Item = TaskId>,
302            ) -> Self::ResultStream {
303                use futures_util::StreamExt;
304                let $result = self.$field.wait_for(task_ids);
305                #[allow(unused_variables)]
306                let $this = &*self;
307                $wrap_body.boxed()
308            }
309
310            async fn check_status(
311                &mut self,
312                task_ids: impl IntoIterator<Item = TaskId> + Send,
313            ) -> Result<Vec<TaskResult<Output>>, Self::Error> {
314                let $result = self.$field.check_status(task_ids).await;
315                #[allow(unused_variables)]
316                let $this = &*self;
317                $wrap_body
318            }
319        }
320
321        impl<$($lt,)* $($generic),+> ListQueues for $wrapper
322        where
323            B: ListQueues + Send + Sync,
324            $($bound)+
325        {
326            async fn list_queues(
327                &self,
328            ) -> Result<Vec<QueueInfo>, Self::Error> {
329                let $result = self.$field.list_queues().await;
330                 #[allow(unused_variables)]
331                let $this = &*self;
332                $wrap_body
333            }
334        }
335
336        impl<$($lt,)* $($generic),+> ListWorkers for $wrapper
337        where
338            B: ListWorkers + Send + Sync,
339            $($bound)+
340        {
341            async fn list_workers(
342                &self,
343            ) -> Result<Vec<RunningWorker>, Self::Error> {
344                let $result = self.$field.list_workers().await;
345                #[allow(unused_variables)]
346                let $this = &*self;
347                $wrap_body
348            }
349
350            async fn list_all_workers(
351                &self,
352            ) -> Result<Vec<RunningWorker>, Self::Error> {
353                let $result = self.$field.list_all_workers().await;
354                #[allow(unused_variables)]
355                let $this = &*self;
356                $wrap_body
357            }
358        }
359
360        impl<$($lt,)* $($generic),+> ListTasks for $wrapper
361        where
362            B: ListTasks + Send + Sync,
363            $($bound)+
364        {
365            async fn list_tasks(
366                &self,
367                filter: &Filter,
368            ) -> Result<Vec<Task<Self::Compact>>, Self::Error> {
369                let $result = self.$field.list_tasks(filter).await;
370                #[allow(unused_variables)]
371                let $this = &*self;
372                $wrap_body
373            }
374        }
375
376        impl<$($lt,)* $($generic),+> ListAllTasks for $wrapper
377        where
378            B: ListAllTasks + Send + Sync,
379            $($bound)+
380        {
381            async fn list_all_tasks(
382                &self,
383                filter: &Filter,
384            ) -> Result<Vec<Task<Self::Compact>>, Self::Error> {
385                let $result = self.$field.list_all_tasks(filter).await;
386                #[allow(unused_variables)]
387                let $this = &*self;
388                $wrap_body
389            }
390        }
391
392        impl<$($lt,)* $($generic),+> Metrics for $wrapper
393        where
394            B: Metrics + Send + Sync,
395            $($bound)+
396        {
397            async fn global(
398                &self,
399            ) -> Result<Vec<Statistic>, Self::Error> {
400                let $result = self.$field.global().await;
401                #[allow(unused_variables)]
402                let $this = &*self;
403                $wrap_body
404            }
405
406            async fn fetch_by_queue(
407                &self,
408            ) -> Result<Vec<Statistic>, Self::Error> {
409                let $result = self.$field.fetch_by_queue().await;
410                #[allow(unused_variables)]
411                let $this = &*self;
412                $wrap_body
413            }
414        }
415    };
416}