connpool/factories/
async_factory.rs1use std::error::Error;
8use std::future::Future;
9use std::pin::Pin;
10
11use crate::core::errors::FactoryError;
12
13pub type BoxFuture<'a, O> = Pin<Box<dyn Future<Output = O> + Send + 'a>>;
15
16pub trait AsyncConnectionFactory<T>: Send + Sync {
19 fn create(&self) -> impl Future<Output = Result<T, FactoryError>> + Send;
21
22 fn validate(&self, _conn: &T) -> impl Future<Output = bool> + Send {
24 async { true }
25 }
26
27 fn reset(&self, _conn: &T) -> impl Future<Output = Result<(), FactoryError>> + Send {
29 async { Ok(()) }
30 }
31
32 fn close(&self, _conn: &T) -> impl Future<Output = Result<(), FactoryError>> + Send {
34 async { Ok(()) }
35 }
36
37 fn is_fatal_error(&self, _err: &(dyn Error + 'static)) -> bool {
39 false
40 }
41}
42
43type CreateFn<T> = Box<dyn Fn() -> BoxFuture<'static, Result<T, FactoryError>> + Send + Sync>;
44type ValidateFn<T> = Box<dyn for<'a> Fn(&'a T) -> BoxFuture<'a, bool> + Send + Sync>;
45type ResetFn<T> =
46 Box<dyn for<'a> Fn(&'a T) -> BoxFuture<'a, Result<(), FactoryError>> + Send + Sync>;
47type CloseFn<T> =
48 Box<dyn for<'a> Fn(&'a T) -> BoxFuture<'a, Result<(), FactoryError>> + Send + Sync>;
49type IsFatalFn = Box<dyn Fn(&(dyn Error + 'static)) -> bool + Send + Sync>;
50
51pub struct AsyncFnFactory<T> {
53 create_fn: CreateFn<T>,
54 validate_fn: Option<ValidateFn<T>>,
55 reset_fn: Option<ResetFn<T>>,
56 close_fn: Option<CloseFn<T>>,
57 is_fatal_fn: Option<IsFatalFn>,
58}
59
60impl<T> AsyncFnFactory<T> {
61 pub fn new<F>(create: F) -> Self
63 where
64 F: Fn() -> BoxFuture<'static, Result<T, FactoryError>> + Send + Sync + 'static,
65 {
66 Self {
67 create_fn: Box::new(create),
68 validate_fn: None,
69 reset_fn: None,
70 close_fn: None,
71 is_fatal_fn: None,
72 }
73 }
74
75 pub fn with_validate<F>(mut self, f: F) -> Self
77 where
78 F: for<'a> Fn(&'a T) -> BoxFuture<'a, bool> + Send + Sync + 'static,
79 {
80 self.validate_fn = Some(Box::new(f));
81 self
82 }
83
84 pub fn with_reset<F>(mut self, f: F) -> Self
86 where
87 F: for<'a> Fn(&'a T) -> BoxFuture<'a, Result<(), FactoryError>> + Send + Sync + 'static,
88 {
89 self.reset_fn = Some(Box::new(f));
90 self
91 }
92
93 pub fn with_close<F>(mut self, f: F) -> Self
95 where
96 F: for<'a> Fn(&'a T) -> BoxFuture<'a, Result<(), FactoryError>> + Send + Sync + 'static,
97 {
98 self.close_fn = Some(Box::new(f));
99 self
100 }
101
102 pub fn with_is_fatal_error<F>(mut self, f: F) -> Self
104 where
105 F: Fn(&(dyn Error + 'static)) -> bool + Send + Sync + 'static,
106 {
107 self.is_fatal_fn = Some(Box::new(f));
108 self
109 }
110}
111
112impl<T> AsyncConnectionFactory<T> for AsyncFnFactory<T>
113where
114 T: Send + Sync,
115{
116 fn create(&self) -> impl Future<Output = Result<T, FactoryError>> + Send {
117 (self.create_fn)()
118 }
119
120 async fn validate(&self, conn: &T) -> bool {
121 match &self.validate_fn {
122 Some(f) => f(conn).await,
123 None => true,
124 }
125 }
126
127 async fn reset(&self, conn: &T) -> Result<(), FactoryError> {
128 match &self.reset_fn {
129 Some(f) => f(conn).await,
130 None => Ok(()),
131 }
132 }
133
134 async fn close(&self, conn: &T) -> Result<(), FactoryError> {
135 match &self.close_fn {
136 Some(f) => f(conn).await,
137 None => Ok(()),
138 }
139 }
140
141 fn is_fatal_error(&self, err: &(dyn Error + 'static)) -> bool {
142 match &self.is_fatal_fn {
143 Some(f) => f(err),
144 None => false,
145 }
146 }
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152
153 #[tokio::test]
154 async fn defaults_apply_when_unset() {
155 let f = AsyncFnFactory::<u32>::new(|| Box::pin(async { Ok::<_, FactoryError>(7u32) }));
156 assert_eq!(f.create().await.unwrap(), 7u32);
157 assert!(f.validate(&7).await);
158 assert!(f.reset(&7).await.is_ok());
159 assert!(f.close(&7).await.is_ok());
160 let err: FactoryError = "x".into();
161 assert!(!f.is_fatal_error(&*err));
162 }
163
164 #[tokio::test]
165 async fn custom_hooks_are_used() {
166 let f = AsyncFnFactory::<u32>::new(|| Box::pin(async { Ok::<_, FactoryError>(1u32) }))
167 .with_validate(|c: &u32| {
168 let v = *c == 1;
169 Box::pin(async move { v }) as _
170 })
171 .with_reset(|_| Box::pin(async { Err::<(), FactoryError>("reset boom".into()) }) as _)
172 .with_close(|_| Box::pin(async { Err::<(), FactoryError>("close boom".into()) }) as _)
173 .with_is_fatal_error(|e| e.to_string() == "fatal");
174 assert!(f.validate(&1).await);
175 assert_eq!(f.reset(&1).await.unwrap_err().to_string(), "reset boom");
176 assert_eq!(f.close(&1).await.unwrap_err().to_string(), "close boom");
177 let fatal: FactoryError = "fatal".into();
178 assert!(f.is_fatal_error(&*fatal));
179 }
180
181 #[tokio::test]
182 async fn trait_defaults_apply_to_a_minimal_impl() {
183 struct Minimal;
184 impl AsyncConnectionFactory<u32> for Minimal {
185 async fn create(&self) -> Result<u32, FactoryError> {
186 Ok(1)
187 }
188 }
189 let m = Minimal;
190 assert_eq!(m.create().await.unwrap(), 1);
191 assert!(m.validate(&1).await);
192 assert!(m.reset(&1).await.is_ok());
193 assert!(m.close(&1).await.is_ok());
194 let e: FactoryError = "x".into();
195 assert!(!m.is_fatal_error(&*e));
196 }
197}