1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
//! # Deadpool [![Latest Version](https://img.shields.io/crates/v/deadpool.svg)](https://crates.io/crates/deadpool) [![Build Status](https://img.shields.io/github/workflow/status/bikeshedder/deadpool/Rust)](https://github.com/bikeshedder/deadpool/actions?query=workflow%3ARust)
//!
//!
//! Deadpool is a dead simple async pool for connections and objects
//! of any type.
//!
//! This crate provides two implementations:
//!
//! - Managed pool (`deadpool::managed::Pool`)
//!   - Creates and recycles objects as needed
//!   - Useful for [database connection pools](#database-connection-pools)
//!   - Enabled via the `managed` feature in your `Cargo.toml`
//!
//! - Unmanaged pool (`deadpool::unmanaged::Pool`)
//!   - All objects either need to to be created by the user and added to the
//!     pool manually. It is also possible to create a pool from an existing
//!     collection of objects.
//!   - Enabled via the `unmanaged` feature in your `Cargo.toml`
//!
//! ## Features
//!
//! | Feature | Description | Extra dependencies | Default |
//! | ------- | ----------- | ------------------ | ------- |
//! | `managed` | Enable managed pool implementation | `async-trait` | yes |
//! | `unmanaged` | Enable unmanaged pool implementation | - | yes |
//! | `config` | Enable support for [config](https://crates.io/crates/config) crate | `config`, `serde/derive` | yes |
//! | `rt_tokio_1` | Enable support for [tokio](https://crates.io/crates/tokio) crate | `tokio/time` | no |
//! | `rt_async-std_1` | Enable support for [async-std](https://crates.io/crates/config) crate | `async-std` | no |
//!
//! The runtime features (`rt_*`) are only needed if you need support for
//! timeouts. If you try to use timeouts without specifying a runtime at
//! pool creation the pool get methods will return an
//! `PoolError::NoRuntimeSpecified` error.
//!
//! ## Managed pool (aka. connection pool)
//!
//! This is the obvious choice for connection pools of any kind. Deadpool already
//! comes with a couple of [database connection pools](#database-connection-pools)
//! which work out of the box.
//!
//! ### Example
//!
//! ```rust,ignore
//! use async_trait::async_trait;
//!
//! #[derive(Debug)]
//! enum Error { Fail }
//!
//! struct Computer {}
//! struct Manager {}
//! type Pool = deadpool::managed::Pool<Manager>;
//!
//! impl Computer {
//!     async fn get_answer(&self) -> i32 {
//!         42
//!     }
//! }
//!
//! #[async_trait]
//! impl deadpool::managed::Manager for Manager {
//!     type Type = Computer;
//!     type Error = Error;
//!     async fn create(&self) -> Result<Computer, Error> {
//!         Ok(Computer {})
//!     }
//!     async fn recycle(&self, conn: &mut Computer) -> deadpool::managed::RecycleResult<Error> {
//!         Ok(())
//!     }
//! }
//!
//! #[tokio::main]
//! async fn main() {
//!     let mgr = Manager {};
//!     let pool = Pool::new(mgr, 16);
//!     let mut conn = pool.get().await.unwrap();
//!     let answer = conn.get_answer().await;
//!     assert_eq!(answer, 42);
//! }
//! ```
//!
//! ### Database connection pools
//!
//! Deadpool supports various database backends by implementing the
//! `deadpool::managed::Manager` trait. The following backends are
//! currently supported:
//!
//! Backend | Crate | Latest Version |
//! ------- | ----- | -------------- |
//! [tokio-postgres](https://crates.io/crates/tokio-postgres) | [deadpool-postgres](https://crates.io/crates/deadpool-postgres) | [![Latest Version](https://img.shields.io/crates/v/deadpool-postgres.svg)](https://crates.io/crates/deadpool-postgres) |
//! [lapin](https://crates.io/crates/lapin) (AMQP) | [deadpool-lapin](https://crates.io/crates/deadpool-lapin) | [![Latest Version](https://img.shields.io/crates/v/deadpool-lapin.svg)](https://crates.io/crates/deadpool-lapin) |
//! [redis](https://crates.io/crates/redis) | [deadpool-redis](https://crates.io/crates/deadpool-redis) | [![Latest Version](https://img.shields.io/crates/v/deadpool-redis.svg)](https://crates.io/crates/deadpool-redis) |
//! [async-memcached](https://crates.io/crates/async-memcached) | [deadpool-memcached](https://crates.io/crates/deadpool-memcached) | [![Latest Version](https://img.shields.io/crates/v/deadpool-memcached.svg)](https://crates.io/crates/deadpool-memcached) |
//! [rusqlite](https://crates.io/crates/rusqlite) | [deadpool-sqlite](https://crates.io/crates/deadpool-sqlite) | [![Latest Version](https://img.shields.io/crates/v/deadpool-sqlite.svg)](https://crates.io/crates/deadpool-sqlite) |
//!
//! ### Reasons for yet another connection pool
//!
//! Deadpool is by no means the only pool implementation available. It does
//! things a little different and that is the main reason for it to exist:
//!
//! - **Deadpool is compatible with any executor.** Objects are returned to the
//!   pool using the `Drop` trait. The health of those objects is checked upon
//!   next retrieval and not when they are returned. Deadpool never performs any
//!   actions in the background. This is the reason why deadpool does not need
//!   to spawn futures and does not rely on a background thread or task of any
//!   type.
//!
//! - **Identical startup and runtime behaviour**. When writing long running
//!   application there usually should be no difference between startup and
//!   runtime if a database connection is temporarily not available. Nobody
//!   would expect an application to crash if the database becomes unavailable
//!   at runtime. So it should not crash on startup either. Creating the pool
//!   never fails and errors are only ever returned when calling `Pool::get()`.
//!
//!   If you really want your application to crash on startup if objects can
//!   not be created on startup simply call
//!   `pool.get().await.expect("DB connection failed")` right after creating
//!   the pool.
//!
//! - **Deadpool is fast.** Whenever working with locking primitives they are
//!   held for the shortest duration possible. When returning an object to the
//!   pool a single mutex is locked and when retrieving objects from the pool
//!   a Semaphore is used to make this Mutex as little contested as possible.
//!
//! - **Deadpool is simple.** Dead simple. There is very little API surface.
//!   The actual code is barely 100 lines of code and lives in the two functions
//!   `Pool::get` and `Object::drop`.
//!
//! ### Differences to other connection pool implementations
//!
//! - [`r2d2`](https://crates.io/crates/r2d2) provides a lot more configuration
//!   options but only provides a synchroneous interface.
//!
//! - [`bb8`](https://crates.io/crates/bb8) provides an `async/.await` based
//!   interface and provides the same configuration options as `r2d2`. It
//!   depends on the tokio executor though and the code is more complex.
//!
//! - [`mobc`](https://crates.io/crates/mobc) provides an `async/.await` based
//!   interface and provides a lot more configuration options. It requires an
//!   executor though and the code is a lot more complex.
//!
//! ## Unmanaged pool
//!
//! An unmanaged pool is useful when you can't write a manager for the objects
//! you want to pool or simply don't want to. This pool implementation is slightly
//! faster than the managed pool because it does not use a `Manager` trait to
//! `create` and `recycle` objects but leaves it up to the user.
//!
//! ### Unmanaged pool example
//!
//! ```rust,ignore
//! use deadpool::unmanaged::Pool;
//!
//! struct Computer {}
//!
//! impl Computer {
//!     async fn get_answer(&self) -> i32 {
//!         42
//!     }
//! }
//!
//! #[tokio::main]
//! async fn main() {
//!     let pool = Pool::from(vec![
//!         Computer {},
//!         Computer {},
//!     ]);
//!     let s = pool.get().await.unwrap();
//!     assert_eq!(s.get_answer().await, 42);
//! }
//! ```
//!
//! ## FAQ
//!
//! ### Why does deadpool depend on `tokio`? I thought it was runtime agnostic...
//!
//! Deadpool depends on `tokio::sync::Semaphore`. This does **not** mean that
//! the tokio runtime or anything else of tokio is being used or will be part
//! of your build. You can easily check this by running the following command
//! in your own code base:
//!
//! ```shell
//! cargo tree --format "{p} {f}"
//! ```
//!
//! ## License
//!
//! Licensed under either of
//!
//! - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0)>
//! - MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT)>
//!
//! at your option.
#![warn(missing_docs)]

#[cfg(feature = "managed")]
pub mod managed;

#[cfg(feature = "unmanaged")]
pub mod unmanaged;

mod runtime;
pub use runtime::Runtime;

#[derive(Debug)]
/// The current pool status.
pub struct Status {
    /// The maximum size of the pool
    pub max_size: usize,
    /// The current size of the pool
    pub size: usize,
    /// The number of available objects in the pool. If there are no
    /// objects in the pool this number can become negative and stores the
    /// number of futures waiting for an object.
    pub available: isize,
}