deadpool/managed/
builder.rs

1use std::{fmt, marker::PhantomData, time::Duration};
2
3use crate::Runtime;
4
5use super::{
6    hooks::{Hook, Hooks},
7    Manager, Object, Pool, PoolConfig, Timeouts,
8};
9
10/// Possible errors returned when [`PoolBuilder::build()`] fails to build a
11/// [`Pool`].
12#[derive(Debug)]
13pub enum BuildError<E> {
14    /// Backend reported an error when creating a [`Pool`].
15    Backend(E),
16
17    /// [`Runtime`] is required.
18    NoRuntimeSpecified(String),
19}
20
21impl<E: std::fmt::Display> fmt::Display for BuildError<E> {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        match self {
24            Self::Backend(e) => write!(f, "Error occurred while building the pool: Backend: {}", e),
25            Self::NoRuntimeSpecified(msg) => write!(
26                f,
27                "Error occurred while building the pool: NoRuntimeSpecified: {}",
28                msg
29            ),
30        }
31    }
32}
33
34impl<E: std::error::Error + 'static> std::error::Error for BuildError<E> {
35    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
36        match self {
37            Self::Backend(e) => Some(e),
38            Self::NoRuntimeSpecified(_) => None,
39        }
40    }
41}
42
43/// Builder for [`Pool`]s.
44///
45/// Instances of this are created by calling the [`Pool::builder()`] method.
46#[must_use = "builder does nothing itself, use `.build()` to build it"]
47pub struct PoolBuilder<M, W = Object<M>>
48where
49    M: Manager,
50    W: From<Object<M>>,
51{
52    pub(crate) manager: M,
53    pub(crate) config: PoolConfig,
54    pub(crate) runtime: Option<Runtime>,
55    pub(crate) hooks: Hooks<M>,
56    _wrapper: PhantomData<fn() -> W>,
57}
58
59// Implemented manually to avoid unnecessary trait bound on `W` type parameter.
60impl<M, W> fmt::Debug for PoolBuilder<M, W>
61where
62    M: fmt::Debug + Manager,
63    W: From<Object<M>>,
64{
65    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66        f.debug_struct("PoolBuilder")
67            .field("manager", &self.manager)
68            .field("config", &self.config)
69            .field("runtime", &self.runtime)
70            .field("hooks", &self.hooks)
71            .field("_wrapper", &self._wrapper)
72            .finish()
73    }
74}
75
76impl<M, W> PoolBuilder<M, W>
77where
78    M: Manager,
79    W: From<Object<M>>,
80{
81    pub(crate) fn new(manager: M) -> Self {
82        Self {
83            manager,
84            config: PoolConfig::default(),
85            runtime: None,
86            hooks: Hooks::default(),
87            _wrapper: PhantomData::default(),
88        }
89    }
90
91    /// Builds the [`Pool`].
92    ///
93    /// # Errors
94    ///
95    /// See [`BuildError`] for details.
96    pub fn build(self) -> Result<Pool<M, W>, BuildError<M::Error>> {
97        // Return an error if a timeout is configured without runtime.
98        let t = &self.config.timeouts;
99        if (t.wait.is_some() || t.create.is_some() || t.recycle.is_some()) && self.runtime.is_none()
100        {
101            return Err(BuildError::NoRuntimeSpecified(
102                "Timeouts require a runtime".to_string(),
103            ));
104        }
105        Ok(Pool::from_builder(self))
106    }
107
108    /// Sets a [`PoolConfig`] to build the [`Pool`] with.
109    pub fn config(mut self, value: PoolConfig) -> Self {
110        self.config = value;
111        self
112    }
113
114    /// Sets the [`PoolConfig::max_size`].
115    pub fn max_size(mut self, value: usize) -> Self {
116        self.config.max_size = value;
117        self
118    }
119
120    /// Sets the [`PoolConfig::timeouts`].
121    pub fn timeouts(mut self, value: Timeouts) -> Self {
122        self.config.timeouts = value;
123        self
124    }
125
126    /// Sets the [`Timeouts::wait`] value of the [`PoolConfig::timeouts`].
127    pub fn wait_timeout(mut self, value: Option<Duration>) -> Self {
128        self.config.timeouts.wait = value;
129        self
130    }
131
132    /// Sets the [`Timeouts::create`] value of the [`PoolConfig::timeouts`].
133    pub fn create_timeout(mut self, value: Option<Duration>) -> Self {
134        self.config.timeouts.create = value;
135        self
136    }
137
138    /// Sets the [`Timeouts::recycle`] value of the [`PoolConfig::timeouts`].
139    pub fn recycle_timeout(mut self, value: Option<Duration>) -> Self {
140        self.config.timeouts.recycle = value;
141        self
142    }
143
144    /// Attaches a `post_create` hook.
145    ///
146    /// The given `hook` will be called each time right after a new [`Object`]
147    /// has been created.
148    pub fn post_create(mut self, hook: impl Into<Hook<M>>) -> Self {
149        self.hooks.post_create.push(hook.into());
150        self
151    }
152
153    /// Attaches a `pre_recycle` hook.
154    ///
155    /// The given `hook` will be called each time right before an [`Object`] will
156    /// be recycled.
157    pub fn pre_recycle(mut self, hook: impl Into<Hook<M>>) -> Self {
158        self.hooks.pre_recycle.push(hook.into());
159        self
160    }
161
162    /// Attaches a `post_recycle` hook.
163    ///
164    /// The given `hook` will be called each time right after an [`Object`] has
165    /// been recycled.
166    pub fn post_recycle(mut self, hook: impl Into<Hook<M>>) -> Self {
167        self.hooks.post_recycle.push(hook.into());
168        self
169    }
170
171    /// Sets the [`Runtime`].
172    ///
173    /// # Important
174    ///
175    /// The [`Runtime`] is optional. Most [`Pool`]s don't need a
176    /// [`Runtime`]. If want to utilize timeouts, however a [`Runtime`] must be
177    /// specified as you will otherwise get a [`PoolError::NoRuntimeSpecified`]
178    /// when trying to use [`Pool::timeout_get()`].
179    ///
180    /// [`PoolBuilder::build()`] will fail with a
181    /// [`BuildError::NoRuntimeSpecified`] if you try to build a
182    /// [`Pool`] with timeouts and no [`Runtime`] specified.
183    ///
184    /// [`PoolError::NoRuntimeSpecified`]: super::PoolError::NoRuntimeSpecified
185    pub fn runtime(mut self, value: Runtime) -> Self {
186        self.runtime = Some(value);
187        self
188    }
189}