From e6ac7b1643e01764c5fccddee985d25bf53494e2 Mon Sep 17 00:00:00 2001 From: Tomasz Kramkowski Date: Sat, 19 Jul 2025 21:25:35 +0100 Subject: Shorter helpers --- src/config/helpers.rs | 163 +++++++++++++++++--------------------------------- 1 file changed, 56 insertions(+), 107 deletions(-) (limited to 'src/config/helpers.rs') 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 // 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, { - 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(self, v: i64) -> Result - 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(self, v: f64) -> Result - 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, D::Error> @@ -94,94 +81,56 @@ where impl<'de> Deserialize<'de> for super::Program { fn deserialize>(deserializer: D) -> Result { - 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(self, seq: A) -> Result - 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(self, map: A) -> Result - where - A: serde::de::MapAccess<'de>, - { - #[derive(Deserialize)] - struct Helper { - command: Box<[String]>, - #[serde(default, deserialize_with = "deserialize_timeout_opt")] - timeout: Option, - } + #[derive(Deserialize)] + #[serde(remote = "super::Program")] + struct Helper { + command: Box<[String]>, + #[serde(default, deserialize_with = "deserialize_timeout_opt")] + timeout: Option, + } - 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>(deserializer: D) -> Result { - 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(self, seq: A) -> Result - 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(self, map: A) -> Result - where - A: serde::de::MapAccess<'de>, - { - #[derive(Deserialize)] - struct Helper { - programs: Box<[super::Program]>, - #[serde(default, deserialize_with = "deserialize_qos_opt")] - qos: Option, - } + #[derive(Deserialize)] + #[serde(remote = "super::Route")] + struct Helper { + programs: Box<[super::Program]>, + #[serde(default, deserialize_with = "deserialize_qos_opt")] + qos: Option, + } - 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, + }) } } -- cgit v1.2.3-70-g09d2