atrium_api/types/
integer.rs1use std::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8};
4
5use serde::{de::Error, Deserialize};
6
7macro_rules! uint {
8 ($primitive:ident, $nz:ident, $lim:ident, $lim_nz:ident, $bounded:ident) => {
9 #[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, Hash)]
11 #[repr(transparent)]
12 #[serde(transparent)]
13 pub struct $lim<const MAX: $primitive>($primitive);
14
15 impl<const MAX: $primitive> $lim<MAX> {
16 pub const MIN: Self = Self(<$primitive>::MIN);
18
19 pub const MAX: Self = Self(MAX);
21
22 fn new(value: $primitive) -> Result<Self, String> {
23 if value > MAX {
24 Err(format!("value is greater than {}", MAX))
25 } else {
26 Ok(Self(value))
27 }
28 }
29 }
30
31 impl<const MAX: $primitive> TryFrom<$primitive> for $lim<MAX> {
32 type Error = String;
33
34 fn try_from(value: $primitive) -> Result<Self, Self::Error> {
35 Self::new(value)
36 }
37 }
38
39 impl<'de, const MAX: $primitive> Deserialize<'de> for $lim<MAX> {
40 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
41 where
42 D: serde::Deserializer<'de>,
43 {
44 let value = Deserialize::deserialize(deserializer)?;
45 Self::new(value).map_err(D::Error::custom)
46 }
47 }
48
49 impl<const MAX: $primitive> From<$lim<MAX>> for $primitive {
50 fn from(value: $lim<MAX>) -> Self {
51 value.0
52 }
53 }
54
55 #[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, Hash)]
57 #[repr(transparent)]
58 #[serde(transparent)]
59 pub struct $lim_nz<const MAX: $primitive>($nz);
60
61 impl<const MAX: $primitive> $lim_nz<MAX> {
62 pub const MIN: Self = Self($nz::MIN);
65
66 pub const MAX: Self = Self(unsafe { $nz::new_unchecked(MAX) });
69
70 fn new(value: $primitive) -> Result<Self, String> {
71 if value > MAX {
72 Err(format!("value is greater than {}", MAX))
73 } else if let Some(value) = $nz::new(value) {
74 Ok(Self(value))
75 } else {
76 Err("value is zero".into())
77 }
78 }
79 }
80
81 impl<const MAX: $primitive> TryFrom<$primitive> for $lim_nz<MAX> {
82 type Error = String;
83
84 fn try_from(value: $primitive) -> Result<Self, Self::Error> {
85 Self::new(value)
86 }
87 }
88
89 impl<'de, const MAX: $primitive> Deserialize<'de> for $lim_nz<MAX> {
90 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
91 where
92 D: serde::Deserializer<'de>,
93 {
94 let value = Deserialize::deserialize(deserializer)?;
95 Self::new(value).map_err(D::Error::custom)
96 }
97 }
98
99 impl<const MAX: $primitive> From<$lim_nz<MAX>> for $nz {
100 fn from(value: $lim_nz<MAX>) -> Self {
101 value.0
102 }
103 }
104
105 impl<const MAX: $primitive> From<$lim_nz<MAX>> for $primitive {
106 fn from(value: $lim_nz<MAX>) -> Self {
107 value.0.into()
108 }
109 }
110
111 #[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, Hash)]
115 #[repr(transparent)]
116 #[serde(transparent)]
117 pub struct $bounded<const MIN: $primitive, const MAX: $primitive>($nz);
118
119 impl<const MIN: $primitive, const MAX: $primitive> $bounded<MIN, MAX> {
120 pub const MIN: Self = Self(unsafe { $nz::new_unchecked(MIN) });
122
123 pub const MAX: Self = Self(unsafe { $nz::new_unchecked(MAX) });
125
126 fn new(value: $primitive) -> Result<Self, String> {
127 if value < MIN {
128 Err(format!("value is less than {}", MIN))
129 } else if value > MAX {
130 Err(format!("value is greater than {}", MAX))
131 } else if let Some(value) = $nz::new(value) {
132 Ok(Self(value))
133 } else {
134 Err("value is zero".into())
135 }
136 }
137 }
138
139 impl<const MIN: $primitive, const MAX: $primitive> TryFrom<$primitive>
140 for $bounded<MIN, MAX>
141 {
142 type Error = String;
143
144 fn try_from(value: $primitive) -> Result<Self, Self::Error> {
145 Self::new(value)
146 }
147 }
148
149 impl<'de, const MIN: $primitive, const MAX: $primitive> Deserialize<'de>
150 for $bounded<MIN, MAX>
151 {
152 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
153 where
154 D: serde::Deserializer<'de>,
155 {
156 let value = Deserialize::deserialize(deserializer)?;
157 Self::new(value).map_err(D::Error::custom)
158 }
159 }
160
161 impl<const MIN: $primitive, const MAX: $primitive> From<$bounded<MIN, MAX>> for $nz {
162 fn from(value: $bounded<MIN, MAX>) -> Self {
163 value.0
164 }
165 }
166
167 impl<const MIN: $primitive, const MAX: $primitive> From<$bounded<MIN, MAX>> for $primitive {
168 fn from(value: $bounded<MIN, MAX>) -> Self {
169 value.0.into()
170 }
171 }
172 };
173}
174
175uint!(u8, NonZeroU8, LimitedU8, LimitedNonZeroU8, BoundedU8);
176uint!(u16, NonZeroU16, LimitedU16, LimitedNonZeroU16, BoundedU16);
177uint!(u32, NonZeroU32, LimitedU32, LimitedNonZeroU32, BoundedU32);
178uint!(u64, NonZeroU64, LimitedU64, LimitedNonZeroU64, BoundedU64);
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183
184 #[test]
185 fn u8_min_max() {
186 assert_eq!(Ok(LimitedU8::<10>::MIN), 0.try_into());
187 assert_eq!(Ok(LimitedU8::<10>::MAX), 10.try_into());
188 assert_eq!(Ok(LimitedNonZeroU8::<10>::MIN), 1.try_into());
189 assert_eq!(Ok(LimitedNonZeroU8::<10>::MAX), 10.try_into());
190 assert_eq!(Ok(BoundedU8::<7, 10>::MIN), 7.try_into());
191 assert_eq!(Ok(BoundedU8::<7, 10>::MAX), 10.try_into());
192 }
193}