From 8f36504745cf7ac88a68081011777ea0bc45468a Mon Sep 17 00:00:00 2001 From: Jannik Beyerstedt Date: Fri, 24 Jul 2026 16:49:34 +0200 Subject: [PATCH] feat(conversions): Add conversion for PathDeltaTime to and from millis --- src/standards/conversions.rs | 46 ++++++++++++++++++++++++++++++++++++ tests/conversion_tests.rs | 26 ++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/src/standards/conversions.rs b/src/standards/conversions.rs index 76a1ee5..90bd279 100644 --- a/src/standards/conversions.rs +++ b/src/standards/conversions.rs @@ -1134,6 +1134,52 @@ impl From for u32 { } } +/// Create conversions for PathDeltaTime +/// +/// Value range is 1..65535 (extensible), so u16 fits currently, but u32 should have enough space for extensions +#[cfg(any(feature = "_cdd_2_2_1", feature = "_cdd_1_3_1_1"))] +macro_rules! path_delta_time_to_millis { + ($t:ty) => { + impl $t { + const ETSI_TO_MS_FACTOR: u32 = 10; // unit: 10 milliseconds + + /// convert ETSI PathDeltaTime to milliseconds + #[must_use] + pub fn as_millis(&self) -> u32 { + let etsi_val: i64 = (&self.0).try_into().unwrap_or_default(); + + #[allow(clippy::cast_possible_truncation)] + let etsi_val = etsi_val as u32; + etsi_val * Self::ETSI_TO_MS_FACTOR + } + + /// create ETSI PathDeltaTime from milliseconds + /// + /// # Errors + /// human-readable string when input value is out of bounds + pub fn from_millis(value: u32) -> Result { + use rasn::AsnType; + + #[allow(clippy::cast_possible_truncation)] + let etsi_val = value / Self::ETSI_TO_MS_FACTOR; + + if let Some(constraints) = Self::CONSTRAINTS.value() { + if !constraints.constraint.in_bound(&etsi_val) { + return Err(alloc::format!("Value out of bounds")); + } + } + + Ok(Self(etsi_val.into())) + } + } + }; +} + +#[cfg(feature = "_cdd_1_3_1_1")] +path_delta_time_to_millis!(cdd_1_3_1_1::its_container::PathDeltaTime); +#[cfg(feature = "_cdd_2_2_1")] +path_delta_time_to_millis!(cdd_2_2_1::etsi_its_cdd::PathDeltaTime); + // MinuteOfTheYear: unit minute, 527040 for invalid #[cfg(feature = "_dsrc_2_2_1")] impl dsrc_2_2_1::etsi_its_dsrc::MinuteOfTheYear { diff --git a/tests/conversion_tests.rs b/tests/conversion_tests.rs index 67f9056..e6a130d 100644 --- a/tests/conversion_tests.rs +++ b/tests/conversion_tests.rs @@ -500,4 +500,30 @@ mod tests { assert!(dsrc_2_2_1::etsi_its_dsrc::DSecond::from_millis(60999).is_ok()); assert!(dsrc_2_2_1::etsi_its_dsrc::DSecond::from_millis(61000).is_err()); } + + #[test] + #[cfg(feature = "_cdd_2_2_1")] + fn path_delta_time_test() { + use c_its_parser::standards::cdd_2_2_1; + + // from ETSI to millis + let test = cdd_2_2_1::etsi_its_cdd::PathDeltaTime(100.into()); + assert_eq!(1000, test.as_millis()); + let test = cdd_2_2_1::etsi_its_cdd::PathDeltaTime(1.into()); + assert_eq!(10, test.as_millis()); + + // from millis to ETSI + assert_eq!( + cdd_2_2_1::etsi_its_cdd::PathDeltaTime(100.into()), + cdd_2_2_1::etsi_its_cdd::PathDeltaTime::from_millis(1000).unwrap() + ); + + assert_eq!( + cdd_2_2_1::etsi_its_cdd::PathDeltaTime(1.into()), + cdd_2_2_1::etsi_its_cdd::PathDeltaTime::from_millis(10).unwrap() + ); + + assert!(cdd_2_2_1::etsi_its_cdd::PathDeltaTime::from_millis(655350).is_ok()); + assert!(cdd_2_2_1::etsi_its_cdd::PathDeltaTime::from_millis(655360).is_err()); + } }