deadpool/managed/
hooks.rs
1use std::{fmt, future::Future, pin::Pin};
4
5use super::{Manager, Metrics, ObjectInner, PoolError};
6
7pub type HookResult<E> = Result<(), HookError<E>>;
9
10pub type HookFuture<'a, E> = Pin<Box<dyn Future<Output = HookResult<E>> + Send + 'a>>;
12
13type SyncFn<M> =
15 dyn Fn(&mut <M as Manager>::Type, &Metrics) -> HookResult<<M as Manager>::Error> + Sync + Send;
16
17type AsyncFn<M> = dyn for<'a> Fn(&'a mut <M as Manager>::Type, &'a Metrics) -> HookFuture<'a, <M as Manager>::Error>
19 + Sync
20 + Send;
21
22pub enum Hook<M: Manager> {
24 Fn(Box<SyncFn<M>>),
26 AsyncFn(Box<AsyncFn<M>>),
28}
29
30impl<M: Manager> Hook<M> {
31 pub fn sync_fn(
33 f: impl Fn(&mut M::Type, &Metrics) -> HookResult<M::Error> + Sync + Send + 'static,
34 ) -> Self {
35 Self::Fn(Box::new(f))
36 }
37 pub fn async_fn(
39 f: impl for<'a> Fn(&'a mut M::Type, &'a Metrics) -> HookFuture<'a, M::Error>
40 + Sync
41 + Send
42 + 'static,
43 ) -> Self {
44 Self::AsyncFn(Box::new(f))
45 }
46}
47
48impl<M: Manager> fmt::Debug for Hook<M> {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 match self {
51 Self::Fn(_) => f
52 .debug_tuple("Fn")
53 .finish(),
55 Self::AsyncFn(_) => f
56 .debug_tuple("AsyncFn")
57 .finish(),
59 }
60 }
61}
62
63#[derive(Debug)]
76pub enum HookError<E> {
77 Continue(Option<HookErrorCause<E>>),
80 Abort(HookErrorCause<E>),
83}
84
85#[derive(Debug)]
87pub enum HookErrorCause<E> {
88 Message(String),
90
91 StaticMessage(&'static str),
93
94 Backend(E),
96}
97
98impl<E> HookError<E> {
99 pub fn cause(&self) -> Option<&HookErrorCause<E>> {
101 match self {
102 Self::Continue(option) => option.as_ref(),
103 Self::Abort(cause) => Some(cause),
104 }
105 }
106}
107
108impl<E: fmt::Display> fmt::Display for HookError<E> {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 match self.cause() {
111 Some(HookErrorCause::Message(msg)) => write!(f, "{}", msg),
112 Some(HookErrorCause::StaticMessage(msg)) => write!(f, "{}", msg),
113 Some(HookErrorCause::Backend(e)) => write!(f, "{}", e),
114 None => write!(f, "No cause given"),
115 }
116 }
117}
118
119impl<E: std::error::Error + 'static> std::error::Error for HookError<E> {
120 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
121 match self.cause() {
122 Some(HookErrorCause::Message(_)) => None,
123 Some(HookErrorCause::StaticMessage(_)) => None,
124 Some(HookErrorCause::Backend(e)) => Some(e),
125 None => None,
126 }
127 }
128}
129
130pub(crate) struct HookVec<M: Manager> {
131 vec: Vec<Hook<M>>,
132}
133
134impl<M: Manager> fmt::Debug for HookVec<M> {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 f.debug_struct("HookVec")
138 .finish_non_exhaustive()
140 }
141}
142
143impl<M: Manager> Default for HookVec<M> {
145 fn default() -> Self {
146 Self { vec: Vec::new() }
147 }
148}
149
150impl<M: Manager> HookVec<M> {
151 pub(crate) async fn apply(
152 &self,
153 inner: &mut ObjectInner<M>,
154 error: fn(e: HookError<M::Error>) -> PoolError<M::Error>,
155 ) -> Result<Option<HookError<M::Error>>, PoolError<M::Error>> {
156 for hook in &self.vec {
157 let result = match hook {
158 Hook::Fn(f) => f(&mut inner.obj, &inner.metrics),
159 Hook::AsyncFn(f) => f(&mut inner.obj, &inner.metrics).await,
160 };
161 match result {
162 Ok(()) => {}
163 Err(e) => match e {
164 HookError::Continue(_) => return Ok(Some(e)),
165 HookError::Abort(_) => return Err(error(e)),
166 },
167 }
168 }
169 Ok(None)
170 }
171 pub(crate) fn push(&mut self, hook: Hook<M>) {
172 self.vec.push(hook);
173 }
174}
175
176pub(crate) struct Hooks<M: Manager> {
180 pub(crate) post_create: HookVec<M>,
181 pub(crate) pre_recycle: HookVec<M>,
182 pub(crate) post_recycle: HookVec<M>,
183}
184
185impl<M: Manager> fmt::Debug for Hooks<M> {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 f.debug_struct("Hooks")
189 .field("post_create", &self.post_create)
190 .field("pre_recycle", &self.post_recycle)
191 .field("post_recycle", &self.post_recycle)
192 .finish()
193 }
194}
195
196impl<M: Manager> Default for Hooks<M> {
198 fn default() -> Self {
199 Self {
200 pre_recycle: HookVec::default(),
201 post_create: HookVec::default(),
202 post_recycle: HookVec::default(),
203 }
204 }
205}