1use core::fmt;
4use serde::de::{self, Visitor};
5use serde::{self, Deserialize, Deserializer, Serialize, Serializer};
6use std::str::FromStr;
7use std::time::Duration as StdDuration;
8
9#[cfg(feature = "typeinfo")]
10use junction_typeinfo::TypeInfo;
11
12#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
14#[cfg_attr(feature = "typeinfo", derive(TypeInfo))]
15pub struct Fraction {
16 pub numerator: i32,
17
18 #[serde(default, skip_serializing_if = "Option::is_none")]
19 pub denominator: Option<i32>,
20}
21
22#[derive(Clone)]
26pub struct Regex(regex::Regex);
27
28impl PartialEq for Regex {
29 fn eq(&self, other: &Self) -> bool {
30 self.0.as_str() == other.0.as_str()
31 }
32}
33
34impl Eq for Regex {}
35
36impl std::fmt::Debug for Regex {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
38 f.write_str(self.0.as_str())
39 }
40}
41
42impl std::ops::Deref for Regex {
43 type Target = regex::Regex;
44
45 fn deref(&self) -> &Self::Target {
46 &self.0
47 }
48}
49
50impl AsRef<regex::Regex> for Regex {
51 fn as_ref(&self) -> ®ex::Regex {
52 &self.0
53 }
54}
55
56impl FromStr for Regex {
57 type Err = String;
58
59 fn from_str(s: &str) -> Result<Self, Self::Err> {
60 match regex::Regex::try_from(s) {
61 Ok(e) => Ok(Self(e)),
62 Err(e) => Err(e.to_string()),
63 }
64 }
65}
66
67#[cfg(feature = "typeinfo")]
68impl TypeInfo for Regex {
69 fn kind() -> junction_typeinfo::Kind {
70 junction_typeinfo::Kind::String
71 }
72}
73
74impl serde::Serialize for Regex {
75 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
76 where
77 S: serde::Serializer,
78 {
79 serializer.serialize_str(self.0.as_str())
80 }
81}
82
83impl<'de> Deserialize<'de> for Regex {
84 fn deserialize<D>(deserializer: D) -> Result<Regex, D::Error>
85 where
86 D: Deserializer<'de>,
87 {
88 struct RegexVisitor;
89
90 impl Visitor<'_> for RegexVisitor {
91 type Value = Regex;
92
93 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
94 formatter.write_str("a Regex")
95 }
96
97 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
98 where
99 E: de::Error,
100 {
101 match Regex::from_str(value) {
102 Ok(s) => Ok(s),
103 Err(e) => Err(E::custom(format!("could not parse {}: {}", value, e))),
104 }
105 }
106 }
107 deserializer.deserialize_string(RegexVisitor)
108 }
109}
110
111#[derive(Copy, Clone, PartialEq, Eq)]
114pub struct Duration(StdDuration);
115
116impl Duration {
117 pub const fn new(secs: u64, nanos: u32) -> Duration {
118 Duration(StdDuration::new(secs, nanos))
119 }
120}
121
122impl AsRef<StdDuration> for Duration {
123 fn as_ref(&self) -> &StdDuration {
124 &self.0
125 }
126}
127
128impl std::ops::Deref for Duration {
129 type Target = StdDuration;
130
131 fn deref(&self) -> &Self::Target {
132 &self.0
133 }
134}
135
136impl std::fmt::Debug for Duration {
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 self.0.fmt(f)
139 }
140}
141
142impl std::fmt::Display for Duration {
143 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144 write!(f, "{}", self.as_secs_f64())
145 }
146}
147
148#[cfg(feature = "typeinfo")]
149impl TypeInfo for Duration {
150 fn kind() -> junction_typeinfo::Kind {
151 junction_typeinfo::Kind::Duration
152 }
153}
154
155impl From<Duration> for StdDuration {
156 fn from(val: Duration) -> Self {
157 val.0
158 }
159}
160
161impl From<StdDuration> for Duration {
162 fn from(duration: StdDuration) -> Self {
163 Duration(duration)
164 }
165}
166
167macro_rules! duration_from {
168 ($($(#[$attr:meta])* $method:ident: $arg:ty),* $(,)*) => {
169 impl Duration {
170 $(
171 $(#[$attr])*
172 pub fn $method(val: $arg) -> Self {
173 Duration(StdDuration::$method(val))
174 }
175 )*
176 }
177 };
178}
179
180duration_from! {
181 from_secs: u64,
184
185 from_millis: u64,
188
189 from_micros: u64,
192
193 from_secs_f32: f32,
196
197
198 from_secs_f64: f64,
201}
202
203impl Serialize for Duration {
204 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
205 where
206 S: Serializer,
207 {
208 serializer.serialize_f64(self.as_secs_f64())
209 }
210}
211
212impl<'de> Deserialize<'de> for Duration {
213 fn deserialize<D>(deserializer: D) -> Result<Duration, D::Error>
214 where
215 D: Deserializer<'de>,
216 {
217 struct DurationVisitor;
221
222 impl Visitor<'_> for DurationVisitor {
223 type Value = Duration;
224
225 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
226 formatter.write_str("a Duration expressed as a number of seconds")
227 }
228
229 fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
230 where
231 E: de::Error,
232 {
233 Ok(Duration::from(StdDuration::from_secs_f64(v)))
234 }
235
236 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
237 where
238 E: de::Error,
239 {
240 Ok(Duration::from(StdDuration::from_secs(v)))
241 }
242
243 fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
244 where
245 E: de::Error,
246 {
247 let v: u64 = v
248 .try_into()
249 .map_err(|_| E::custom("Duration cannot be negative"))?;
250
251 Ok(Duration::from(StdDuration::from_secs(v)))
252 }
253 }
254
255 deserializer.deserialize_any(DurationVisitor)
256 }
257}
258
259#[cfg(test)]
260mod test_duration {
261 use super::*;
262
263 #[test]
264 fn test_duration_deserialize() {
267 #[derive(Debug, Deserialize, PartialEq, Eq)]
268 struct SomeValue {
269 float_duration: Duration,
270 int_duration: Duration,
271 }
272
273 let value = serde_json::json!({
274 "string_duration": "1h23m4s",
275 "float_duration": 1.234,
276 "int_duration": 1234,
277 });
278
279 assert_eq!(
280 serde_json::from_value::<SomeValue>(value).unwrap(),
281 SomeValue {
282 float_duration: Duration::from_millis(1234),
283 int_duration: Duration::from_secs(1234),
284 }
285 );
286 }
287
288 #[test]
289 fn test_duration_serialize() {
291 #[derive(Debug, Serialize, PartialEq, Eq)]
292 struct SomeValue {
293 duration: Duration,
294 }
295
296 assert_eq!(
297 serde_json::json!({
298 "duration": 123.456,
299 }),
300 serde_json::to_value(SomeValue {
301 duration: Duration::from_secs_f64(123.456),
302 })
303 .unwrap(),
304 );
305 }
306}