diff options
Diffstat (limited to 'src/config')
-rw-r--r-- | src/config/helpers.rs | 163 |
1 files changed, 56 insertions, 107 deletions
diff --git a/src/config/helpers.rs b/src/config/helpers.rs index 17dbe35..ddf29ad 100644 --- a/src/config/helpers.rs +++ b/src/config/helpers.rs @@ -1,13 +1,10 @@ // SPDX-FileCopyrightText: 2025 Tomasz Kramkowski <tomasz@kramkow.ski> // SPDX-License-Identifier: GPL-3.0-or-later -use std::{fmt, time::Duration}; +use std::time::Duration; use rumqttc::QoS; -use serde::{ - de::{self, Visitor}, - Deserialize, Deserializer, -}; +use serde::{de, Deserialize, Deserializer}; #[allow(clippy::enum_variant_names)] #[derive(Deserialize, Debug)] @@ -34,19 +31,15 @@ pub fn deserialize_timeout<'de, D>(deserializer: D) -> Result<Duration, D::Error where D: Deserializer<'de>, { - struct DurationVisitor; - - impl<'de> de::Visitor<'de> for DurationVisitor { - type Value = Duration; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a positive number") - } + #[derive(Deserialize)] + #[serde(untagged)] + enum Untagged { + Int(i64), + Float(f64), + } - fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E> - where - E: de::Error, - { + Ok(match Untagged::deserialize(deserializer)? { + Untagged::Int(v) => { if v < 0 { return Err(de::Error::invalid_value( de::Unexpected::Signed(v), @@ -54,16 +47,12 @@ where )); } if v == 0 { - Ok(Duration::MAX) + Duration::MAX } else { - Ok(Duration::from_secs(v as u64)) + Duration::from_secs(v as u64) } } - - fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E> - where - E: de::Error, - { + Untagged::Float(v) => { if v < 0.0 { return Err(de::Error::invalid_value( de::Unexpected::Float(v), @@ -71,14 +60,12 @@ where )); } if v == 0.0 { - Ok(Duration::MAX) + Duration::MAX } else { - Ok(Duration::from_secs_f64(v)) + Duration::from_secs_f64(v) } } - } - - deserializer.deserialize_any(DurationVisitor) + }) } pub fn deserialize_timeout_opt<'de, D>(deserializer: D) -> Result<Option<Duration>, D::Error> @@ -94,94 +81,56 @@ where impl<'de> Deserialize<'de> for super::Program { fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { - struct VecOrProgram; - - impl<'de> Visitor<'de> for VecOrProgram { - type Value = super::Program; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("map or seq") - } - - fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error> - where - A: serde::de::SeqAccess<'de>, - { - let vec: Box<[String]> = - Deserialize::deserialize(de::value::SeqAccessDeserializer::new(seq))?; - Ok(super::Program { - command: vec, - timeout: None, - }) - } - - fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error> - where - A: serde::de::MapAccess<'de>, - { - #[derive(Deserialize)] - struct Helper { - command: Box<[String]>, - #[serde(default, deserialize_with = "deserialize_timeout_opt")] - timeout: Option<Duration>, - } + #[derive(Deserialize)] + #[serde(remote = "super::Program")] + struct Helper { + command: Box<[String]>, + #[serde(default, deserialize_with = "deserialize_timeout_opt")] + timeout: Option<Duration>, + } - let helper: Helper = - Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))?; - Ok(super::Program { - command: helper.command, - timeout: helper.timeout, - }) - } + #[derive(Deserialize)] + #[serde(untagged)] + enum Untagged { + Short(Box<[String]>), + #[serde(with = "Helper")] + Full(super::Program), } - deserializer.deserialize_any(VecOrProgram) + Ok(match Untagged::deserialize(deserializer)? { + Untagged::Short(command) => super::Program { + command, + timeout: None, + }, + Untagged::Full(program) => program, + }) } } impl<'de> Deserialize<'de> for super::Route { fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { - struct VecOrRoute; - - impl<'de> Visitor<'de> for VecOrRoute { - type Value = super::Route; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("map or seq") - } - - fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error> - where - A: serde::de::SeqAccess<'de>, - { - let vec: Box<[super::Program]> = - Deserialize::deserialize(de::value::SeqAccessDeserializer::new(seq))?; - Ok(super::Route { - programs: vec, - qos: None, - }) - } - - fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error> - where - A: serde::de::MapAccess<'de>, - { - #[derive(Deserialize)] - struct Helper { - programs: Box<[super::Program]>, - #[serde(default, deserialize_with = "deserialize_qos_opt")] - qos: Option<QoS>, - } + #[derive(Deserialize)] + #[serde(remote = "super::Route")] + struct Helper { + programs: Box<[super::Program]>, + #[serde(default, deserialize_with = "deserialize_qos_opt")] + qos: Option<QoS>, + } - let helper: Helper = - Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))?; - Ok(super::Route { - programs: helper.programs, - qos: helper.qos, - }) - } + #[derive(Deserialize)] + #[serde(untagged)] + enum Untagged { + Short(Box<[super::Program]>), + #[serde(with = "Helper")] + Full(super::Route), } - deserializer.deserialize_any(VecOrRoute) + Ok(match Untagged::deserialize(deserializer)? { + Untagged::Short(programs) => super::Route { + programs, + qos: None, + }, + Untagged::Full(route) => route, + }) } } |