Skip to main content

tower_resilience_executor/
layer.rs

1//! Layer implementation for the executor middleware.
2
3use crate::{Executor, ExecutorService};
4use tower_layer::Layer;
5
6/// A Tower layer that delegates request processing to an executor.
7///
8/// This layer wraps a service and spawns each request's processing
9/// as a new task on the provided executor. This enables parallel
10/// processing of requests across multiple executor threads.
11///
12/// # Example
13///
14/// ```rust,no_run
15/// use tower_resilience_executor::ExecutorLayer;
16/// use tokio::runtime::Handle;
17///
18/// // Use the current runtime
19/// let layer = ExecutorLayer::new(Handle::current());
20/// ```
21#[derive(Clone)]
22pub struct ExecutorLayer<E> {
23    executor: E,
24}
25
26impl<E> ExecutorLayer<E>
27where
28    E: Executor,
29{
30    /// Creates a new executor layer with the given executor.
31    pub fn new(executor: E) -> Self {
32        Self { executor }
33    }
34
35    /// Creates a builder for configuring the executor layer.
36    pub fn builder() -> ExecutorLayerBuilder<E> {
37        ExecutorLayerBuilder::new()
38    }
39}
40
41impl ExecutorLayer<tokio::runtime::Handle> {
42    /// Creates an executor layer using the current tokio runtime.
43    ///
44    /// # Panics
45    ///
46    /// Panics if called from outside a tokio runtime.
47    pub fn current() -> Self {
48        Self::new(tokio::runtime::Handle::current())
49    }
50}
51
52impl<S, E> Layer<S> for ExecutorLayer<E>
53where
54    E: Clone,
55{
56    type Service = ExecutorService<S, E>;
57
58    fn layer(&self, service: S) -> Self::Service {
59        ExecutorService::new(service, self.executor.clone())
60    }
61}
62
63/// Builder for configuring an [`ExecutorLayer`].
64pub struct ExecutorLayerBuilder<E> {
65    executor: Option<E>,
66}
67
68impl<E> ExecutorLayerBuilder<E> {
69    /// Creates a new builder.
70    fn new() -> Self {
71        Self { executor: None }
72    }
73}
74
75impl<E> ExecutorLayerBuilder<E>
76where
77    E: Executor,
78{
79    /// Sets the executor to use for spawning request processing.
80    pub fn executor(mut self, executor: E) -> Self {
81        self.executor = Some(executor);
82        self
83    }
84
85    /// Builds the executor layer.
86    ///
87    /// # Panics
88    ///
89    /// Panics if no executor was configured.
90    pub fn build(self) -> ExecutorLayer<E> {
91        ExecutorLayer {
92            executor: self.executor.expect("executor must be configured"),
93        }
94    }
95}
96
97impl ExecutorLayerBuilder<tokio::runtime::Handle> {
98    /// Sets a tokio runtime handle as the executor.
99    pub fn handle(mut self, handle: tokio::runtime::Handle) -> Self {
100        self.executor = Some(handle);
101        self
102    }
103
104    /// Uses the current tokio runtime as the executor.
105    ///
106    /// # Panics
107    ///
108    /// Panics if called from outside a tokio runtime.
109    pub fn current(mut self) -> Self {
110        self.executor = Some(tokio::runtime::Handle::current());
111        self
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118
119    #[tokio::test]
120    async fn test_layer_creation() {
121        let layer = ExecutorLayer::current();
122        let _layer2 = layer.clone();
123    }
124
125    #[tokio::test]
126    async fn test_builder() {
127        let layer = ExecutorLayer::<tokio::runtime::Handle>::builder()
128            .current()
129            .build();
130        let _layer2 = layer.clone();
131    }
132
133    #[tokio::test]
134    async fn test_builder_with_handle() {
135        let handle = tokio::runtime::Handle::current();
136        let layer = ExecutorLayer::builder().handle(handle).build();
137        let _layer2 = layer.clone();
138    }
139}