1use std::fmt;
2
3use serde::{
4 de::{self, MapAccess, Unexpected, Visitor},
5 Deserialize, Deserializer,
6};
7
8use crate::time_types::{NtpDuration, PollInterval, PollIntervalLimits};
9
10fn deserialize_option_accumulated_step_panic_threshold<'de, D>(
11 deserializer: D,
12) -> Result<Option<NtpDuration>, D::Error>
13where
14 D: Deserializer<'de>,
15{
16 let duration: NtpDuration = Deserialize::deserialize(deserializer)?;
17 Ok(if duration == NtpDuration::ZERO {
18 None
19 } else {
20 Some(duration)
21 })
22}
23
24#[derive(Debug, Default, Copy, Clone)]
25pub struct ReferenceIdConfig {
26 id: u32,
27}
28
29impl ReferenceIdConfig {
30 pub(crate) fn to_reference_id(self) -> crate::ReferenceId {
31 crate::ReferenceId::from_int(self.id)
32 }
33}
34
35impl<'de> Deserialize<'de> for ReferenceIdConfig {
37 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
38 where
39 D: Deserializer<'de>,
40 {
41 struct ReferenceIdConfigVisitor;
42
43 impl Visitor<'_> for ReferenceIdConfigVisitor {
44 type Value = ReferenceIdConfig;
45
46 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
47 formatter.write_str("up to 4-character string")
48 }
49
50 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
51 where
52 E: de::Error,
53 {
54 let mut chars: Vec<char> = v.chars().collect();
55 if chars.len() > 4 {
56 return Err(E::invalid_length(chars.len(), &self));
57 }
58
59 while chars.len() < 4 {
61 chars.push(' ');
62 }
63
64 let encoded = chars.iter().fold(0u32, |acc, &c| (acc << 8) | (c as u32));
65
66 Ok(ReferenceIdConfig { id: encoded })
67 }
68 }
69
70 deserializer.deserialize_str(ReferenceIdConfigVisitor)
71 }
72}
73
74#[derive(Debug, Default, Copy, Clone)]
75pub struct StepThreshold {
76 pub forward: Option<NtpDuration>,
77 pub backward: Option<NtpDuration>,
78}
79
80impl StepThreshold {
81 pub fn is_within(&self, duration: NtpDuration) -> bool {
82 self.forward.map(|v| duration < v).unwrap_or(true)
83 && self.backward.map(|v| duration > -v).unwrap_or(true)
84 }
85}
86
87#[derive(Debug, Copy, Clone)]
88struct ThresholdPart(Option<NtpDuration>);
89
90impl<'de> Deserialize<'de> for ThresholdPart {
91 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
92 where
93 D: Deserializer<'de>,
94 {
95 struct ThresholdPartVisitor;
96
97 impl Visitor<'_> for ThresholdPartVisitor {
98 type Value = ThresholdPart;
99
100 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
101 formatter.write_str("float or \"inf\"")
102 }
103
104 fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
105 where
106 E: de::Error,
107 {
108 Ok(ThresholdPart(Some(NtpDuration::from_seconds(v))))
109 }
110
111 fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
112 where
113 E: de::Error,
114 {
115 self.visit_f64(v as f64)
116 }
117
118 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
119 where
120 E: de::Error,
121 {
122 self.visit_f64(v as f64)
123 }
124
125 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
126 where
127 E: de::Error,
128 {
129 if v != "inf" {
130 return Err(de::Error::invalid_value(
131 de::Unexpected::Str(v),
132 &"float or \"inf\"",
133 ));
134 }
135 Ok(ThresholdPart(None))
136 }
137 }
138
139 deserializer.deserialize_any(ThresholdPartVisitor)
140 }
141}
142
143impl<'de> Deserialize<'de> for StepThreshold {
146 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
147 where
148 D: Deserializer<'de>,
149 {
150 struct StepThresholdVisitor;
151
152 impl<'de> Visitor<'de> for StepThresholdVisitor {
153 type Value = StepThreshold;
154
155 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
156 formatter.write_str("float, map or \"inf\"")
157 }
158
159 fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
160 where
161 E: de::Error,
162 {
163 if v.is_nan() || v.is_infinite() || v < 0.0 {
164 return Err(serde::de::Error::invalid_value(
165 Unexpected::Float(v),
166 &"a positive number",
167 ));
168 }
169
170 let duration = NtpDuration::from_seconds(v);
171
172 Ok(StepThreshold {
173 forward: Some(duration),
174 backward: Some(duration),
175 })
176 }
177
178 fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
179 where
180 E: de::Error,
181 {
182 self.visit_f64(v as f64)
183 }
184
185 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
186 where
187 E: de::Error,
188 {
189 self.visit_f64(v as f64)
190 }
191
192 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
193 where
194 E: de::Error,
195 {
196 if v != "inf" {
197 return Err(de::Error::invalid_value(
198 de::Unexpected::Str(v),
199 &"float, map or \"inf\"",
200 ));
201 }
202 Ok(StepThreshold {
203 forward: None,
204 backward: None,
205 })
206 }
207
208 fn visit_map<M: MapAccess<'de>>(self, mut map: M) -> Result<StepThreshold, M::Error> {
209 let mut forward = None;
210 let mut backward = None;
211
212 while let Some(key) = map.next_key::<String>()? {
213 match key.as_str() {
214 "forward" => {
215 if forward.is_some() {
216 return Err(de::Error::duplicate_field("forward"));
217 }
218 let raw: ThresholdPart = map.next_value()?;
219 forward = Some(raw.0);
220 }
221 "backward" => {
222 if backward.is_some() {
223 return Err(de::Error::duplicate_field("backward"));
224 }
225 let raw: ThresholdPart = map.next_value()?;
226 backward = Some(raw.0);
227 }
228 _ => {
229 return Err(de::Error::unknown_field(
230 key.as_str(),
231 &["forward", "backward"],
232 ));
233 }
234 }
235 }
236
237 Ok(StepThreshold {
238 forward: forward.flatten(),
239 backward: backward.flatten(),
240 })
241 }
242 }
243
244 deserializer.deserialize_any(StepThresholdVisitor)
245 }
246}
247
248#[derive(Deserialize, Debug, Clone, Copy)]
249#[serde(rename_all = "kebab-case", deny_unknown_fields)]
250pub struct SourceConfig {
251 #[serde(default)]
253 pub poll_interval_limits: PollIntervalLimits,
254
255 #[serde(default = "default_initial_poll_interval")]
257 pub initial_poll_interval: PollInterval,
258}
259
260impl Default for SourceConfig {
261 fn default() -> Self {
262 Self {
263 poll_interval_limits: Default::default(),
264 initial_poll_interval: default_initial_poll_interval(),
265 }
266 }
267}
268
269fn default_initial_poll_interval() -> PollInterval {
270 PollIntervalLimits::default().min
271}
272
273#[derive(Deserialize, Debug, Clone, Copy)]
274#[serde(rename_all = "kebab-case", deny_unknown_fields)]
275pub struct SynchronizationConfig {
276 #[serde(default = "default_minimum_agreeing_sources")]
285 pub minimum_agreeing_sources: usize,
286
287 #[serde(default = "default_single_step_panic_threshold")]
295 pub single_step_panic_threshold: StepThreshold,
296
297 #[serde(default = "default_startup_step_panic_threshold")]
301 pub startup_step_panic_threshold: StepThreshold,
302
303 #[serde(
306 deserialize_with = "deserialize_option_accumulated_step_panic_threshold",
307 default
308 )]
309 pub accumulated_step_panic_threshold: Option<NtpDuration>,
310
311 #[serde(default = "default_local_stratum")]
315 pub local_stratum: u8,
316
317 #[serde(default = "default_reference_id")]
355 pub reference_id: ReferenceIdConfig,
356
357 #[serde(default = "default_warn_on_jump")]
359 pub warn_on_jump: bool,
360}
361
362impl Default for SynchronizationConfig {
363 fn default() -> Self {
364 Self {
365 minimum_agreeing_sources: default_minimum_agreeing_sources(),
366
367 single_step_panic_threshold: default_single_step_panic_threshold(),
368 startup_step_panic_threshold: default_startup_step_panic_threshold(),
369 accumulated_step_panic_threshold: None,
370
371 local_stratum: default_local_stratum(),
372 reference_id: default_reference_id(),
373
374 warn_on_jump: default_warn_on_jump(),
375 }
376 }
377}
378
379fn default_minimum_agreeing_sources() -> usize {
380 3
381}
382
383fn default_reference_id() -> ReferenceIdConfig {
384 ReferenceIdConfig {
385 id: ['X', 'N', 'O', 'N']
386 .iter()
387 .fold(0u32, |acc, &c| (acc << 8) | (c as u32)),
388 }
389}
390
391fn default_single_step_panic_threshold() -> StepThreshold {
392 let raw = NtpDuration::from_seconds(1000.);
393 StepThreshold {
394 forward: Some(raw),
395 backward: Some(raw),
396 }
397}
398
399fn default_startup_step_panic_threshold() -> StepThreshold {
400 StepThreshold {
402 forward: None,
403 backward: Some(NtpDuration::from_seconds(86400.)),
404 }
405}
406
407fn default_local_stratum() -> u8 {
408 16
409}
410
411fn default_warn_on_jump() -> bool {
412 true
413}