1use serde::Deserialize as _;
4
5#[expect(
14 clippy::cast_possible_truncation,
15 clippy::as_conversions,
16 reason = "intentional conversion from f64 unix timestamp seconds to i128 nanoseconds for the Icinga API"
17)]
18pub fn deserialize_icinga_timestamp<'de, D>(
19 deserializer: D,
20) -> Result<time::OffsetDateTime, D::Error>
21where
22 D: serde::Deserializer<'de>,
23{
24 let f: f64 = f64::deserialize(deserializer)?;
25
26 let i = (f * 1_000_000_000f64) as i128;
27
28 time::OffsetDateTime::from_unix_timestamp_nanos(i).map_err(serde::de::Error::custom)
29}
30
31#[expect(
37 clippy::cast_precision_loss,
38 clippy::as_conversions,
39 reason = "intentional conversion from i128 nanoseconds to f64 unix timestamp seconds for the Icinga API"
40)]
41pub fn serialize_icinga_timestamp<S>(
42 v: &time::OffsetDateTime,
43 serializer: S,
44) -> Result<S::Ok, S::Error>
45where
46 S: serde::Serializer,
47{
48 let ts = (v.unix_timestamp_nanos() as f64) / 1_000_000_000_f64;
49 <f64 as serde::Serialize>::serialize(&ts, serializer)
50}
51
52#[expect(
62 clippy::cast_possible_truncation,
63 clippy::as_conversions,
64 reason = "intentional conversion from f64 unix timestamp seconds to i128 nanoseconds for the Icinga API"
65)]
66pub fn deserialize_optional_icinga_timestamp<'de, D>(
67 deserializer: D,
68) -> Result<Option<time::OffsetDateTime>, D::Error>
69where
70 D: serde::Deserializer<'de>,
71{
72 let f: f64 = f64::deserialize(deserializer)?;
73
74 if f == 0.0f64 {
75 Ok(None)
76 } else {
77 let i = (f * 1_000_000_000f64) as i128;
78
79 Ok(Some(
80 time::OffsetDateTime::from_unix_timestamp_nanos(i).map_err(serde::de::Error::custom)?,
81 ))
82 }
83}
84
85#[expect(
92 clippy::cast_precision_loss,
93 clippy::as_conversions,
94 reason = "intentional conversion from i128 nanoseconds to f64 unix timestamp seconds for the Icinga API"
95)]
96pub fn serialize_optional_icinga_timestamp<S>(
97 v: &Option<time::OffsetDateTime>,
98 serializer: S,
99) -> Result<S::Ok, S::Error>
100where
101 S: serde::Serializer,
102{
103 let mut ts = 0f64;
104 if let Some(v) = v {
105 ts = (v.unix_timestamp_nanos() as f64) / 1_000_000_000_f64;
106 }
107 <f64 as serde::Serialize>::serialize(&ts, serializer)
108}
109
110pub fn deserialize_empty_string_or_string<'de, D>(
117 deserializer: D,
118) -> Result<Option<String>, D::Error>
119where
120 D: serde::Deserializer<'de>,
121{
122 let s: Option<String> = Option::deserialize(deserializer)?;
123
124 if let Some(s) = s {
125 if s.is_empty() { Ok(None) } else { Ok(Some(s)) }
126 } else {
127 Ok(None)
128 }
129}
130
131pub fn serialize_none_as_empty_string<S>(
138 v: &Option<String>,
139 serializer: S,
140) -> Result<S::Ok, S::Error>
141where
142 S: serde::Serializer,
143{
144 let mut s = &"".to_string();
145 if let Some(v) = v {
146 s = v;
147 }
148 <String as serde::Serialize>::serialize(s, serializer)
149}
150
151pub fn deserialize_empty_string_or_parse<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
158where
159 D: serde::Deserializer<'de>,
160 T: std::str::FromStr,
161 T::Err: std::fmt::Display,
162{
163 let s: Option<String> = Option::deserialize(deserializer)?;
164
165 if let Some(s) = s {
166 if s.is_empty() {
167 Ok(None)
168 } else {
169 Ok(Some(s.parse().map_err(serde::de::Error::custom)?))
170 }
171 } else {
172 Ok(None)
173 }
174}
175
176pub fn serialize_none_as_empty_string_or_to_string<T, S>(
183 v: &Option<T>,
184 serializer: S,
185) -> Result<S::Ok, S::Error>
186where
187 S: serde::Serializer,
188 T: std::string::ToString,
189{
190 let mut s = "".to_string();
191 if let Some(v) = v {
192 s = v.to_string();
193 }
194 <String as serde::Serialize>::serialize(&s, serializer)
195}
196
197pub fn deserialize_seconds_as_duration<'de, D>(deserializer: D) -> Result<time::Duration, D::Error>
203where
204 D: serde::Deserializer<'de>,
205{
206 let i: i64 = i64::deserialize(deserializer)?;
207 Ok(time::Duration::seconds(i))
208}
209
210pub fn serialize_duration_as_seconds<S>(
216 v: &time::Duration,
217 serializer: S,
218) -> Result<S::Ok, S::Error>
219where
220 S: serde::Serializer,
221{
222 let d = v.whole_seconds();
223 <i64 as serde::Serialize>::serialize(&d, serializer)
224}
225
226pub fn deserialize_optional_seconds_as_duration<'de, D>(
232 deserializer: D,
233) -> Result<Option<time::Duration>, D::Error>
234where
235 D: serde::Deserializer<'de>,
236{
237 let i: Option<i64> = Option::deserialize(deserializer)?;
238 if let Some(i) = i {
239 Ok(Some(time::Duration::seconds(i)))
240 } else {
241 Ok(None)
242 }
243}
244
245pub fn serialize_optional_duration_as_seconds<S>(
251 v: &Option<time::Duration>,
252 serializer: S,
253) -> Result<S::Ok, S::Error>
254where
255 S: serde::Serializer,
256{
257 let mut d: Option<i64> = None;
258 if let Some(v) = v {
259 d = Some(v.whole_seconds());
260 }
261 <Option<i64> as serde::Serialize>::serialize(&d, serializer)
262}