Skip to main content

tower_resilience_fallback/
layer.rs

1//! Tower layer for fallback.
2
3use crate::config::{FallbackConfig, FallbackConfigBuilder};
4use crate::Fallback;
5use std::sync::Arc;
6use tower::layer::Layer;
7
8/// A Tower layer that applies fallback behavior to a service.
9///
10/// See the [module-level documentation](crate) for usage examples.
11pub struct FallbackLayer<Req, Res, E> {
12    config: Arc<FallbackConfig<Req, Res, E>>,
13}
14
15impl<Req, Res, E> FallbackLayer<Req, Res, E> {
16    /// Creates a new fallback layer from the given configuration.
17    pub(crate) fn new(config: FallbackConfig<Req, Res, E>) -> Self {
18        Self {
19            config: Arc::new(config),
20        }
21    }
22
23    /// Creates a new builder for configuring a fallback layer.
24    pub fn builder() -> FallbackConfigBuilder<Req, Res, E> {
25        FallbackConfigBuilder::new()
26    }
27
28    /// Creates a fallback layer that generates a value using a function.
29    ///
30    /// Unlike [`value`](Self::value), this doesn't require `Res: Clone` since
31    /// the function generates a fresh value for each fallback.
32    ///
33    /// # Example
34    ///
35    /// ```rust
36    /// use tower_resilience_fallback::FallbackLayer;
37    ///
38    /// # #[derive(Debug)]
39    /// # struct MyError;
40    /// # struct MyResponse { data: Vec<u8> }  // No Clone needed!
41    /// let layer = FallbackLayer::<String, MyResponse, MyError>::value_fn(|| {
42    ///     MyResponse { data: vec![0; 1024] }
43    /// });
44    /// ```
45    pub fn value_fn<F>(f: F) -> Self
46    where
47        F: Fn() -> Res + Send + Sync + 'static,
48    {
49        FallbackConfigBuilder::new().value_fn(f).build()
50    }
51}
52
53// Convenience constructors for common patterns
54impl<Req, Res, E> FallbackLayer<Req, Res, E>
55where
56    Res: Clone,
57{
58    /// Creates a fallback layer that returns a static value on failure.
59    ///
60    /// Note: This requires `Res: Clone`. If your response type doesn't implement
61    /// Clone, use [`value_fn`](Self::value_fn) instead.
62    ///
63    /// # Example
64    ///
65    /// ```rust
66    /// use tower_resilience_fallback::FallbackLayer;
67    ///
68    /// # #[derive(Debug, Clone)]
69    /// # struct MyError;
70    /// let layer = FallbackLayer::<String, String, MyError>::value("default".to_string());
71    /// ```
72    pub fn value(value: Res) -> Self {
73        FallbackConfigBuilder::new().value(value).build()
74    }
75
76    /// Creates a fallback layer that computes a response from the error.
77    ///
78    /// # Example
79    ///
80    /// ```rust
81    /// use tower_resilience_fallback::FallbackLayer;
82    ///
83    /// # #[derive(Debug, Clone)]
84    /// # struct MyError { msg: String }
85    /// let layer = FallbackLayer::<String, String, MyError>::from_error(|e| {
86    ///     format!("Error: {}", e.msg)
87    /// });
88    /// ```
89    pub fn from_error<F>(f: F) -> Self
90    where
91        F: Fn(&E) -> Res + Send + Sync + 'static,
92    {
93        FallbackConfigBuilder::new().from_error(f).build()
94    }
95
96    /// Creates a fallback layer that computes a response from request and error.
97    ///
98    /// # Example
99    ///
100    /// ```rust
101    /// use tower_resilience_fallback::FallbackLayer;
102    ///
103    /// # #[derive(Debug, Clone)]
104    /// # struct MyError;
105    /// let layer = FallbackLayer::<String, String, MyError>::from_request_error(|req, _err| {
106    ///     format!("Fallback for request: {}", req)
107    /// });
108    /// ```
109    pub fn from_request_error<F>(f: F) -> Self
110    where
111        F: Fn(&Req, &E) -> Res + Send + Sync + 'static,
112    {
113        FallbackConfigBuilder::new().from_request_error(f).build()
114    }
115
116    /// Creates a fallback layer that routes to a backup service.
117    ///
118    /// # Example
119    ///
120    /// ```rust
121    /// use tower_resilience_fallback::FallbackLayer;
122    ///
123    /// # #[derive(Debug, Clone)]
124    /// # struct MyError;
125    /// let layer = FallbackLayer::<String, String, MyError>::service(|req: String| async move {
126    ///     Ok::<_, MyError>(format!("backup: {}", req))
127    /// });
128    /// ```
129    pub fn service<S, Fut>(service: S) -> Self
130    where
131        S: Fn(Req) -> Fut + Send + Sync + 'static,
132        Fut: std::future::Future<Output = Result<Res, E>> + Send + 'static,
133    {
134        FallbackConfigBuilder::new().service(service).build()
135    }
136
137    /// Creates a fallback layer that transforms errors.
138    ///
139    /// Note: This still returns an error, just a transformed one.
140    ///
141    /// # Example
142    ///
143    /// ```rust
144    /// use tower_resilience_fallback::FallbackLayer;
145    ///
146    /// # #[derive(Debug, Clone)]
147    /// # struct MyError { code: u32 }
148    /// let layer = FallbackLayer::<String, String, MyError>::exception(|e| {
149    ///     MyError { code: 500 }
150    /// });
151    /// ```
152    pub fn exception<F>(f: F) -> Self
153    where
154        F: Fn(E) -> E + Send + Sync + 'static,
155    {
156        FallbackConfigBuilder::new().exception(f).build()
157    }
158}
159
160impl<Req, Res, E> Clone for FallbackLayer<Req, Res, E>
161where
162    Res: Clone,
163{
164    fn clone(&self) -> Self {
165        Self {
166            config: Arc::clone(&self.config),
167        }
168    }
169}
170
171impl<S, Req, Res, E> Layer<S> for FallbackLayer<Req, Res, E>
172where
173    Res: Clone,
174{
175    type Service = Fallback<S, Req, Res, E>;
176
177    fn layer(&self, service: S) -> Self::Service {
178        Fallback::new(service, Arc::clone(&self.config))
179    }
180}