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