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
use std::{fmt, time::Duration};

use super::BuildError;

/// [`Pool`] configuration.
///
/// [`Pool`]: super::Pool
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct PoolConfig {
    /// Maximum size of the [`Pool`].
    ///
    /// Default: `cpu_count * 4`
    ///
    /// [`Pool`]: super::Pool
    pub max_size: usize,

    /// Timeouts of the [`Pool`].
    ///
    /// Default: No timeouts
    ///
    /// [`Pool`]: super::Pool
    #[cfg_attr(feature = "serde", serde(default))]
    pub timeouts: Timeouts,

    /// Queue mode of the [`Pool`].
    ///
    /// Determines the order of objects being queued and dequeued.
    ///
    /// Default: `Fifo`
    ///
    /// [`Pool`]: super::Pool
    #[cfg_attr(feature = "serde", serde(default))]
    pub queue_mode: QueueMode,
}

impl PoolConfig {
    /// Creates a new [`PoolConfig`] without any timeouts and with the provided
    /// `max_size`.
    #[must_use]
    pub fn new(max_size: usize) -> Self {
        Self {
            max_size,
            timeouts: Timeouts::default(),
            queue_mode: QueueMode::default(),
        }
    }
}

impl Default for PoolConfig {
    /// Creates a new [`PoolConfig`] with the `max_size` being set to
    /// `cpu_count * 4` ignoring any logical CPUs (Hyper-Threading).
    fn default() -> Self {
        Self::new(num_cpus::get_physical() * 4)
    }
}

/// Timeouts when getting [`Object`]s from a [`Pool`].
///
/// [`Object`]: super::Object
/// [`Pool`]: super::Pool
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Timeouts {
    /// Timeout when waiting for a slot to become available.
    pub wait: Option<Duration>,

    /// Timeout when creating a new object.
    pub create: Option<Duration>,

    /// Timeout when recycling an object.
    pub recycle: Option<Duration>,
}

impl Timeouts {
    /// Create an empty [`Timeouts`] config (no timeouts set).
    #[must_use]
    pub const fn new() -> Self {
        Self {
            create: None,
            wait: None,
            recycle: None,
        }
    }

    /// Creates a new [`Timeouts`] config with only the `wait` timeout being
    /// set.
    #[must_use]
    pub const fn wait_millis(wait: u64) -> Self {
        Self {
            create: None,
            wait: Some(Duration::from_millis(wait)),
            recycle: None,
        }
    }
}

// Implemented manually to provide a custom documentation.
impl Default for Timeouts {
    /// Creates an empty [`Timeouts`] config (no timeouts set).
    fn default() -> Self {
        Self::new()
    }
}

/// Mode for dequeuing [`Object`]s from a [`Pool`].
///
/// [`Object`]: super::Object
/// [`Pool`]: super::Pool
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub enum QueueMode {
    /// Dequeue the object that was least recently added (first in first out).
    Fifo,
    /// Dequeue the object that was most recently added (last in first out).
    Lifo,
}

impl Default for QueueMode {
    fn default() -> Self {
        Self::Fifo
    }
}

/// This error is used when building pools via the config `create_pool`
/// methods.
#[derive(Debug)]
pub enum CreatePoolError<C> {
    /// This variant is used for configuration errors
    Config(C),
    /// This variant is used for errors while building the pool
    Build(BuildError),
}

impl<C> fmt::Display for CreatePoolError<C>
where
    C: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Config(e) => write!(f, "Config: {}", e),
            Self::Build(e) => write!(f, "Build: {}", e),
        }
    }
}

impl<C> std::error::Error for CreatePoolError<C> where C: std::error::Error {}