Skip to main content

base_pool/
lib.rs

1// Released under the MIT License.
2// Copyright, 2019-2026, by Samuel Williams.
3
4//! Resource admission and lifetime, independent of resource construction and I/O.
5#![doc = include_str!("../readme.md")]
6#![forbid(unsafe_code)]
7
8mod core;
9mod multiplex;
10mod retirement;
11mod singleplex;
12
13pub use multiplex::{
14    Admission, MultiplexAbandonedUse, MultiplexBuildPermit, MultiplexPool, MultiplexReservation,
15    MultiplexResource, MultiplexUse, UseId,
16};
17pub use retirement::Retirement;
18pub use singleplex::{SingleplexBuildPermit, SingleplexLease, SingleplexPool, SingleplexResource};
19
20use base_scheduler::Cancellation;
21use std::{fmt, future::Future};
22
23/// Hard bounds. Retiring resources continue to occupy resource capacity.
24#[derive(Clone, Debug)]
25pub struct Options {
26    pub max_resources: usize,
27    pub max_constructing: usize,
28    pub max_waiters: usize,
29}
30impl Default for Options {
31    fn default() -> Self {
32        Self {
33            max_resources: 32,
34            max_constructing: 1,
35            max_waiters: 1024,
36        }
37    }
38}
39impl Options {
40    pub fn validate(&self) -> Result<(), Error> {
41        if self.max_resources == 0 || self.max_constructing == 0 {
42            Err(Error::InvalidOptions)
43        } else {
44            Ok(())
45        }
46    }
47}
48
49#[derive(Clone, Copy, Debug, Eq, PartialEq)]
50pub enum Error {
51    Closed,
52    Cancelled,
53    WaitersFull,
54    AdmissionChanged,
55    InvalidOptions,
56}
57impl fmt::Display for Error {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        f.write_str(match self {
60            Self::Closed => "pool admission is closed",
61            Self::Cancelled => "pool operation cancelled",
62            Self::WaitersFull => "pool waiter limit reached",
63            Self::AdmissionChanged => "resource admission changed before use activation",
64            Self::InvalidOptions => "resource and construction limits must be positive",
65        })
66    }
67}
68impl std::error::Error for Error {}
69impl From<base_scheduler::Cancelled> for Error {
70    fn from(_: base_scheduler::Cancelled) -> Self {
71        Self::Cancelled
72    }
73}
74
75/// Identifies one registration within a pool; identifiers are never recycled.
76#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
77pub struct ResourceId(pub(crate) u64);
78
79/// An admission opportunity: use an existing resource or construct a new one.
80/// A build permit reserves capacity before any asynchronous construction.
81#[derive(Debug)]
82pub enum Acquisition<P, B> {
83    Existing(P),
84    Build(B),
85}
86
87/// Snapshot of one pool. `uses` includes reserved and abandoned multiplex uses.
88#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
89pub struct Stats {
90    pub building: usize,
91    pub live: usize,
92    pub retiring: usize,
93    pub draining: usize,
94    pub uses: usize,
95    pub available: usize,
96    pub waiters: usize,
97    pub closed: bool,
98}
99impl Stats {
100    pub fn total(&self) -> usize {
101        self.building + self.live + self.retiring
102    }
103}
104
105/// Shared vocabulary with distinct associated acquisition types.
106/// Resource-specific mutation and use completion stay on the concrete types.
107pub trait Pool: Send + Sync {
108    type Permit: Send;
109    type BuildPermit: Send;
110    fn acquire_or_reserve(
111        &self,
112        cancellation: &Cancellation,
113    ) -> impl Future<Output = Result<Acquisition<Self::Permit, Self::BuildPermit>, Error>> + Send;
114    fn begin_close(&self);
115    fn stats(&self) -> Stats;
116}