nntp_proxy/types/config/
limits.rs

1//! Connection and error limit configuration types
2
3use serde::{Deserialize, Serialize};
4use std::fmt;
5use std::num::{NonZeroU32, NonZeroUsize};
6
7/// A non-zero maximum connections limit
8///
9/// Ensures connection pools always have at least 1 connection allowed.
10///
11/// # Examples
12/// ```
13/// use nntp_proxy::types::MaxConnections;
14///
15/// let max = MaxConnections::new(10).unwrap();
16/// assert_eq!(max.get(), 10);
17///
18/// // Zero connections is invalid
19/// assert!(MaxConnections::new(0).is_none());
20/// ```
21#[doc(alias = "pool_size")]
22#[doc(alias = "connection_limit")]
23#[repr(transparent)]
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
25pub struct MaxConnections(NonZeroUsize);
26
27impl MaxConnections {
28    /// Create a new MaxConnections, returning None if value is 0
29    #[must_use]
30    pub const fn new(value: usize) -> Option<Self> {
31        match NonZeroUsize::new(value) {
32            Some(nz) => Some(Self(nz)),
33            None => None,
34        }
35    }
36
37    /// Get the value as usize
38    #[must_use]
39    #[inline]
40    pub const fn get(&self) -> usize {
41        self.0.get()
42    }
43
44    /// Default maximum connections per backend
45    pub const DEFAULT: Self = Self(NonZeroUsize::new(10).unwrap());
46}
47
48impl fmt::Display for MaxConnections {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        write!(f, "{}", self.get())
51    }
52}
53
54impl From<MaxConnections> for usize {
55    fn from(max: MaxConnections) -> Self {
56        max.get()
57    }
58}
59
60impl Serialize for MaxConnections {
61    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
62    where
63        S: serde::Serializer,
64    {
65        serializer.serialize_u64(self.get() as u64)
66    }
67}
68
69impl<'de> Deserialize<'de> for MaxConnections {
70    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
71    where
72        D: serde::Deserializer<'de>,
73    {
74        let value = usize::deserialize(deserializer)?;
75        Self::new(value).ok_or_else(|| serde::de::Error::custom("max_connections cannot be 0"))
76    }
77}
78
79/// A non-zero maximum errors threshold.
80///
81/// Used to specify the maximum number of errors allowed before taking action.
82///
83/// This type is used in two primary contexts:
84/// - **Health check error thresholds:** Ensures that health checks require at least one error before marking a service as unhealthy.
85/// - **Retry logic:** Specifies the maximum number of retry attempts after errors.
86///
87/// By enforcing a non-zero value, this type ensures that both health check and retry thresholds are always meaningful (at least 1 error required).
88///
89/// # Examples
90/// ```
91/// use nntp_proxy::types::MaxErrors;
92///
93/// let max = MaxErrors::new(3).unwrap();
94/// assert_eq!(max.get(), 3);
95///
96/// // Zero errors is invalid
97/// assert!(MaxErrors::new(0).is_none());
98/// ```
99#[repr(transparent)]
100#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
101pub struct MaxErrors(NonZeroU32);
102
103impl MaxErrors {
104    /// Create a new MaxErrors, returning None if value is 0
105    #[must_use]
106    pub const fn new(value: u32) -> Option<Self> {
107        match NonZeroU32::new(value) {
108            Some(nz) => Some(Self(nz)),
109            None => None,
110        }
111    }
112
113    /// Get the value as u32
114    #[must_use]
115    #[inline]
116    pub const fn get(&self) -> u32 {
117        self.0.get()
118    }
119
120    /// Default retry attempts
121    pub const DEFAULT: Self = Self(NonZeroU32::new(3).unwrap());
122}
123
124impl fmt::Display for MaxErrors {
125    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126        write!(f, "{}", self.get())
127    }
128}
129
130impl From<MaxErrors> for u32 {
131    fn from(max: MaxErrors) -> Self {
132        max.get()
133    }
134}
135
136impl Serialize for MaxErrors {
137    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
138    where
139        S: serde::Serializer,
140    {
141        serializer.serialize_u32(self.get())
142    }
143}
144
145impl<'de> Deserialize<'de> for MaxErrors {
146    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
147    where
148        D: serde::Deserializer<'de>,
149    {
150        let value = u32::deserialize(deserializer)?;
151        Self::new(value).ok_or_else(|| serde::de::Error::custom("max_errors cannot be 0"))
152    }
153}