statime_config/tree/
modifiers.rs1use serde::{Deserialize, Serialize, de};
2
3use crate::{ConfigurableAtomic, serde_util::Content};
4
5pub trait IsPositive {
6 fn is_positive(&self) -> bool;
7}
8
9macro_rules! is_positive_int {
10 ($int_type:ident) => {
11 impl IsPositive for $int_type {
12 fn is_positive(&self) -> bool {
13 *self > 0
14 }
15 }
16 };
17}
18
19macro_rules! is_positive_float {
20 ($float_type:ident) => {
21 impl IsPositive for $float_type {
22 fn is_positive(&self) -> bool {
23 *self > 0.0
24 }
25 }
26 };
27}
28
29is_positive_int!(u8);
30is_positive_int!(u16);
31is_positive_int!(u32);
32is_positive_int!(u64);
33is_positive_int!(u128);
34is_positive_int!(usize);
35is_positive_int!(i8);
36is_positive_int!(i16);
37is_positive_int!(i32);
38is_positive_int!(i64);
39is_positive_int!(i128);
40is_positive_int!(isize);
41is_positive_float!(f32);
42is_positive_float!(f64);
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
45pub struct Positive<T>(T);
46
47impl<T> Positive<T> {
48 pub fn into_inner(self) -> T {
49 self.0
50 }
51
52 pub fn unchecked_new(value: T) -> Self {
53 Positive(value)
54 }
55}
56
57impl<'de, T: Deserialize<'de> + IsPositive> Deserialize<'de> for Positive<T> {
58 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
59 where
60 D: serde::Deserializer<'de>,
61 {
62 let value = T::deserialize(deserializer)?;
63 if T::is_positive(&value) {
64 Ok(Positive(value))
65 } else {
66 Err(de::Error::custom("value should be positive."))
67 }
68 }
69}
70
71impl<T: Serialize> Serialize for Positive<T> {
72 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
73 where
74 S: serde::Serializer,
75 {
76 self.0.serialize(serializer)
77 }
78}
79
80impl<T: ConfigurableAtomic + IsPositive> ConfigurableAtomic for Positive<T> {}
81impl ConfigurableAtomic for Positive<f32> {}
82impl ConfigurableAtomic for Positive<f64> {}
83
84pub trait IsNonNegative {
85 fn is_non_negative(&self) -> bool;
86}
87
88macro_rules! is_nonnegative_float {
89 ($float_type:ident) => {
90 impl IsNonNegative for $float_type {
91 fn is_non_negative(&self) -> bool {
92 *self >= 0.0
93 }
94 }
95 };
96}
97
98is_nonnegative_float!(f32);
99is_nonnegative_float!(f64);
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
102pub struct NonNegative<T>(T);
103
104impl<T> NonNegative<T> {
105 pub fn into_inner(self) -> T {
106 self.0
107 }
108
109 pub fn unchecked_new(value: T) -> Self {
110 NonNegative(value)
111 }
112}
113
114impl<'de, T: Deserialize<'de> + IsNonNegative> Deserialize<'de> for NonNegative<T> {
115 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
116 where
117 D: serde::Deserializer<'de>,
118 {
119 let value = T::deserialize(deserializer)?;
120 if T::is_non_negative(&value) {
121 Ok(NonNegative(value))
122 } else {
123 Err(de::Error::custom("value should be positive."))
124 }
125 }
126}
127
128impl<T: Serialize> Serialize for NonNegative<T> {
129 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
130 where
131 S: serde::Serializer,
132 {
133 self.0.serialize(serializer)
134 }
135}
136
137impl<T: ConfigurableAtomic + IsNonNegative> ConfigurableAtomic for NonNegative<T> {}
138impl ConfigurableAtomic for NonNegative<f32> {}
139impl ConfigurableAtomic for NonNegative<f64> {}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
142pub enum InfiniteOr<T> {
143 Infinite,
144 Finite(T),
145}
146
147impl<'de, T: Deserialize<'de>> Deserialize<'de> for InfiniteOr<T> {
148 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
149 where
150 D: de::Deserializer<'de>,
151 {
152 let is_human_readable = deserializer.is_human_readable();
153 let content = Content::deserialize(deserializer)?;
154 match content {
155 Content::String(ref v) if v == "inf" => Ok(InfiniteOr::Infinite),
156 Content::BorrowedString("inf") => Ok(InfiniteOr::Infinite),
157 _ => Ok(InfiniteOr::Finite(T::deserialize(
158 content.into_deserializer(is_human_readable),
159 )?)),
160 }
161 }
162}
163
164impl<T: Serialize> Serialize for InfiniteOr<T> {
165 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
166 where
167 S: serde::Serializer,
168 {
169 match self {
170 InfiniteOr::Infinite => serializer.serialize_str("inf"),
171 InfiniteOr::Finite(v) => v.serialize(serializer),
172 }
173 }
174}
175
176impl<T: ConfigurableAtomic> ConfigurableAtomic for InfiniteOr<T> {}
177impl ConfigurableAtomic for InfiniteOr<f32> {}
178impl ConfigurableAtomic for InfiniteOr<f64> {}
179
180#[cfg(test)]
181mod test {
182 use serde::{Deserialize, Serialize};
183
184 use crate::InfiniteOr;
185
186 #[test]
187 fn test_infinite_or_finite() {
188 #[derive(Deserialize, Serialize)]
189 struct Test {
190 test: InfiniteOr<u8>,
191 }
192
193 let parsed: Test = toml::from_str(
194 r"#
195 test = 5
196 ",
197 )
198 .unwrap();
199
200 assert_eq!(parsed.test, InfiniteOr::Finite(5));
201
202 let serialized = toml::to_string(&parsed).unwrap();
203 assert_eq!(serialized, "test = 5\n");
204 }
205
206 #[test]
207 fn test_infinite_or_inf() {
208 #[derive(Deserialize, Serialize)]
209 struct Test {
210 test: InfiniteOr<u8>,
211 }
212
213 let parsed: Test = toml::from_str(
214 r#"
215 test = "inf"
216 "#,
217 )
218 .unwrap();
219
220 assert_eq!(parsed.test, InfiniteOr::Infinite);
221
222 let serialized = toml::to_string(&parsed).unwrap();
223 assert_eq!(serialized, "test = \"inf\"\n");
224 }
225}