tang_rs/lib.rs
1//! # An asynchronous connection pool.
2//! some code come from
3//! [bb8](https://docs.rs/bb8/0.3.1/bb8/)
4//! [L3-37](https://github.com/OneSignal/L3-37/)
5//!
6//! ## feature
7//!
8//! * `default` - multi thread pool where `Send` bound is needed for all futures.
9//! * `no-send` - single thread pool where `!Send` futures are accepted.
10//!
11//! # Known Limitation:
12//! can't be used in nested runtimes.
13//!
14//! # Example:
15//! ```
16//! // This example shows how to implement the pool on async_std runtime.
17//! // Most of the xxx-tang crates are implemented with tokio runtime so they can be seen as examples on that matter.
18//!
19//! use std::fmt::{Debug, Formatter, Result as FmtResult};
20//! use std::future::Future;
21//! use std::sync::atomic::{AtomicUsize, Ordering};
22//! use std::time::{Duration, Instant};
23//!
24//! use async_std::task;
25//! use smol::Timer;
26//! use tang_rs::{Builder, Manager, ManagerFuture, ManagerTimeout};
27//!
28//! // our test pool would just generate usize from 0 as connections.
29//! struct TestPoolManager(AtomicUsize);
30//!
31//! impl TestPoolManager {
32//! fn new() -> Self {
33//! TestPoolManager(AtomicUsize::new(0))
34//! }
35//! }
36//!
37//! // dummy error type
38//! struct TestPoolError;
39//!
40//! impl Debug for TestPoolError {
41//! fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
42//! f.debug_struct("TestPoolError")
43//! .field("source", &"Unknown")
44//! .finish()
45//! }
46//! }
47//!
48//! // convert instant as timeout error to our pool error.
49//! impl From<Instant> for TestPoolError {
50//! fn from(_: Instant) -> Self {
51//! TestPoolError
52//! }
53//! }
54//!
55//! impl Manager for TestPoolManager {
56//! type Connection = usize;
57//! type Error = TestPoolError;
58//! type Timeout = Timer;
59//! type TimeoutError = Instant;
60//!
61//! fn connect(&self) -> ManagerFuture<'_, Result<Self::Connection, Self::Error>> {
62//! // how we generate new connections and put them into pool.
63//! Box::pin(async move { Ok(self.0.fetch_add(1, Ordering::SeqCst)) })
64//! }
65//!
66//! fn is_valid<'a>(
67//! &self,
68//! _conn: &'a mut Self::Connection,
69//! ) -> ManagerFuture<'a, Result<(), Self::Error>> {
70//! Box::pin(async {
71//! // when the connection is pulled from the pool we can check if it's valid.
72//! Ok(())
73//! })
74//! }
75//!
76//! fn is_closed(&self, _conn: &mut Self::Connection) -> bool {
77//! // return true if you check the connection and want it to be dropped from the pool because it's closed.
78//! false
79//! }
80//!
81//! fn spawn<Fut>(&self, fut: Fut)
82//! where
83//! Fut: Future<Output = ()> + Send + 'static,
84//! {
85//! // some pool inner functions would want to spawn on your executor.
86//! // you can use the handler to further manage them if you want.
87//! // normally we just spawn the task and forget about it.
88//! let _handler = task::spawn(fut);
89//! }
90//!
91//! // Boilerplate implement for runtime specific timeout future.
92//! fn timeout<Fut: Future>(&self,fut: Fut, dur: Duration) -> ManagerTimeout<Fut, Self::Timeout> {
93//! ManagerTimeout::new(fut, Timer::after(dur))
94//! }
95//! }
96//!
97//! #[async_std::main]
98//! async fn main() {
99//! let mgr = TestPoolManager::new();
100//!
101//! let builder = Builder::new()
102//! .always_check(false)
103//! .idle_timeout(None)
104//! .max_lifetime(None)
105//! .min_idle(24)
106//! .max_size(24)
107//! .build(mgr);
108//!
109//! let pool = builder.await.expect("fail to build pool");
110//!
111//! // spawn 24 futures and pull connections from pool at the same time.
112//! let (tx, rx) = async_std::sync::channel(100);
113//! for _i in 0..24 {
114//! let pool = pool.clone();
115//! let tx = tx.clone();
116//! task::spawn(async move {
117//! let mut pool_ref = pool.get().await.expect("fail to get PoolRef");
118//! let conn_ref = &*pool_ref;
119//! println!("we have the reference of a connection : {:?}", conn_ref);
120//!
121//! // we can also get a mut reference from pool_ref
122//! let conn_ref = &mut *pool_ref;
123//!
124//! let _ = tx.send(*conn_ref);
125//! });
126//! }
127//! drop(tx);
128//!
129//! while let Ok(_connection) = rx.recv().await {
130//! // We just wait until all connections are pulled out once
131//! }
132//! }
133//!```
134
135pub use builder::Builder;
136pub use manager::{GarbageCollect, Manager, ManagerFuture, ManagerInterval, ScheduleReaping};
137pub use pool::{Pool, PoolRef, PoolRefOwned, SharedManagedPool};
138pub use util::timeout::ManagerTimeout;
139
140mod builder;
141mod manager;
142mod pool;
143mod pool_inner;
144mod util;
145
146#[cfg(all(feature = "default", feature = "no-send"))]
147compile_error!("only one of 'default' or 'no-send' features can be enabled");