use std::fmt;
use serde::{
de::{self, MapAccess, Unexpected, Visitor},
Deserialize, Deserializer,
};
use crate::{time_types::PollIntervalLimits, NtpDuration, PollInterval};
fn deserialize_option_threshold<'de, D>(deserializer: D) -> Result<Option<NtpDuration>, D::Error>
where
D: Deserializer<'de>,
{
let duration: NtpDuration = Deserialize::deserialize(deserializer)?;
Ok(if duration == NtpDuration::ZERO {
None
} else {
Some(duration)
})
}
#[derive(Debug, Default, Copy, Clone)]
pub struct StepThreshold {
pub forward: Option<NtpDuration>,
pub backward: Option<NtpDuration>,
}
impl StepThreshold {
pub fn is_within(&self, duration: NtpDuration) -> bool {
self.forward.map(|v| duration < v).unwrap_or(true)
&& self.backward.map(|v| duration > -v).unwrap_or(true)
}
}
#[derive(Debug, Copy, Clone)]
struct ThresholdPart(Option<NtpDuration>);
impl<'de> Deserialize<'de> for ThresholdPart {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct ThresholdPartVisitor;
impl<'de> Visitor<'de> for ThresholdPartVisitor {
type Value = ThresholdPart;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("float or \"inf\"")
}
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(ThresholdPart(Some(NtpDuration::from_seconds(v))))
}
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where
E: de::Error,
{
self.visit_f64(v as f64)
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
self.visit_f64(v as f64)
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
if v != "inf" {
return Err(de::Error::invalid_value(
de::Unexpected::Str(v),
&"float or \"inf\"",
));
}
Ok(ThresholdPart(None))
}
}
deserializer.deserialize_any(ThresholdPartVisitor)
}
}
impl<'de> Deserialize<'de> for StepThreshold {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct StepThresholdVisitor;
impl<'de> Visitor<'de> for StepThresholdVisitor {
type Value = StepThreshold;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("float, map or \"inf\"")
}
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
where
E: de::Error,
{
if v.is_nan() || v.is_infinite() || v < 0.0 {
return Err(serde::de::Error::invalid_value(
Unexpected::Float(v),
&"a positive number",
));
}
let duration = NtpDuration::from_seconds(v);
Ok(StepThreshold {
forward: Some(duration),
backward: Some(duration),
})
}
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where
E: de::Error,
{
self.visit_f64(v as f64)
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
self.visit_f64(v as f64)
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
if v != "inf" {
return Err(de::Error::invalid_value(
de::Unexpected::Str(v),
&"float, map or \"inf\"",
));
}
Ok(StepThreshold {
forward: None,
backward: None,
})
}
fn visit_map<M: MapAccess<'de>>(self, mut map: M) -> Result<StepThreshold, M::Error> {
let mut forward = None;
let mut backward = None;
while let Some(key) = map.next_key::<String>()? {
match key.as_str() {
"forward" => {
if forward.is_some() {
return Err(de::Error::duplicate_field("forward"));
}
let raw: ThresholdPart = map.next_value()?;
forward = Some(raw.0);
}
"backward" => {
if backward.is_some() {
return Err(de::Error::duplicate_field("backward"));
}
let raw: ThresholdPart = map.next_value()?;
backward = Some(raw.0);
}
_ => {
return Err(de::Error::unknown_field(key.as_str(), &["addr", "mode"]));
}
}
}
Ok(StepThreshold {
forward: forward.flatten(),
backward: backward.flatten(),
})
}
}
deserializer.deserialize_any(StepThresholdVisitor)
}
}
#[derive(Deserialize, Debug, Clone, Copy)]
#[serde(rename_all = "kebab-case", deny_unknown_fields)]
pub struct SystemConfig {
#[serde(default = "default_min_intersection_survivors")]
pub min_intersection_survivors: usize,
#[serde(default = "default_panic_threshold")]
pub panic_threshold: StepThreshold,
#[serde(default = "startup_panic_threshold")]
pub startup_panic_threshold: StepThreshold,
#[serde(deserialize_with = "deserialize_option_threshold", default)]
pub accumulated_threshold: Option<NtpDuration>,
#[serde(default = "default_local_stratum")]
pub local_stratum: u8,
#[serde(default)]
pub poll_limits: PollIntervalLimits,
#[serde(default = "default_initial_poll")]
pub initial_poll: PollInterval,
}
impl Default for SystemConfig {
fn default() -> Self {
Self {
min_intersection_survivors: default_min_intersection_survivors(),
panic_threshold: default_panic_threshold(),
startup_panic_threshold: startup_panic_threshold(),
accumulated_threshold: None,
local_stratum: default_local_stratum(),
poll_limits: Default::default(),
initial_poll: default_initial_poll(),
}
}
}
fn default_min_intersection_survivors() -> usize {
3
}
fn default_panic_threshold() -> StepThreshold {
let raw = NtpDuration::from_seconds(1000.);
StepThreshold {
forward: Some(raw),
backward: Some(raw),
}
}
fn startup_panic_threshold() -> StepThreshold {
StepThreshold {
forward: None,
backward: Some(NtpDuration::from_seconds(1800.)),
}
}
fn default_local_stratum() -> u8 {
16
}
fn default_initial_poll() -> PollInterval {
PollIntervalLimits::default().min
}