Merge pull request 'simplified CDS short impl' (#169) from simplify-cds-timestamp-impl into main

Reviewed-on: #169
This commit was merged in pull request #169.
This commit is contained in:
2025-10-15 15:01:06 +02:00
3 changed files with 38 additions and 61 deletions

View File

@@ -8,6 +8,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
# [unreleased] # [unreleased]
## Changed
- `CdsCommon` renamed to `CdsBase`
- Simplified CDS short timestamp, contains one less field which reduced serialization length.
# [v0.16.1] 2025-09-26 # [v0.16.1] 2025-09-26
## Fixed ## Fixed

View File

@@ -50,6 +50,7 @@ pub trait ProvidesDaysLength: Sealed + Clone {
+ Eq + Eq
+ TryFrom<i32> + TryFrom<i32>
+ TryFrom<u32> + TryFrom<u32>
+ TryFrom<i64>
+ From<u16> + From<u16>
+ Into<u32> + Into<u32>
+ Into<i64>; + Into<i64>;
@@ -173,15 +174,12 @@ pub struct CdsTime<DaysLen: ProvidesDaysLength = DaysLen16Bits> {
ccsds_days: DaysLen::FieldType, ccsds_days: DaysLen::FieldType,
ms_of_day: u32, ms_of_day: u32,
submillis: u32, submillis: u32,
/// This is not strictly necessary but still cached because it significantly simplifies the
/// calculation of [`DateTime<Utc>`].
unix_time: UnixTime,
} }
/// Common properties for all CDS time providers. /// Base properties for all CDS time providers.
/// ///
/// Also exists to encapsulate properties used by private converters. /// Also exists to encapsulate properties used by private converters.
pub trait CdsCommon { pub trait CdsBase {
fn submillis_precision(&self) -> SubmillisPrecision; fn submillis_precision(&self) -> SubmillisPrecision;
fn submillis(&self) -> u32; fn submillis(&self) -> u32;
fn ms_of_day(&self) -> u32; fn ms_of_day(&self) -> u32;
@@ -189,23 +187,18 @@ pub trait CdsCommon {
} }
/// Generic properties for all CDS time providers. /// Generic properties for all CDS time providers.
pub trait CdsTimestamp: CdsCommon { pub trait CdsTimestamp: CdsBase {
fn len_of_day_seg(&self) -> LengthOfDaySegment; fn len_of_day_seg(&self) -> LengthOfDaySegment;
} }
/// Private trait which serves as an abstraction for different converters. /// Private trait which serves as an abstraction for different converters.
trait CdsConverter: CdsCommon { trait CdsConverter: CdsBase {}
fn unix_days_seconds(&self) -> i64;
}
struct ConversionFromUnix { struct ConversionFromUnix {
ccsds_days: u32, ccsds_days: u32,
ms_of_day: u32, ms_of_day: u32,
submilis_prec: SubmillisPrecision, submilis_prec: SubmillisPrecision,
submillis: u32, submillis: u32,
/// This is a side-product of the calculation of the CCSDS days. It is useful for
/// re-calculating the datetime at a later point and therefore supplied as well.
unix_days_seconds: i64,
} }
impl ConversionFromUnix { impl ConversionFromUnix {
@@ -232,14 +225,13 @@ impl ConversionFromUnix {
Ok(Self { Ok(Self {
ccsds_days: unix_to_ccsds_days(unix_days) as u32, ccsds_days: unix_to_ccsds_days(unix_days) as u32,
ms_of_day, ms_of_day,
unix_days_seconds: unix_days * SECONDS_PER_DAY as i64,
submilis_prec: precision, submilis_prec: precision,
submillis, submillis,
}) })
} }
} }
impl CdsCommon for ConversionFromUnix { impl CdsBase for ConversionFromUnix {
#[inline] #[inline]
fn submillis_precision(&self) -> SubmillisPrecision { fn submillis_precision(&self) -> SubmillisPrecision {
self.submilis_prec self.submilis_prec
@@ -261,12 +253,7 @@ impl CdsCommon for ConversionFromUnix {
} }
} }
impl CdsConverter for ConversionFromUnix { impl CdsConverter for ConversionFromUnix {}
#[inline]
fn unix_days_seconds(&self) -> i64 {
self.unix_days_seconds
}
}
/// Helper struct which generates fields for the CDS time provider from a datetime. /// Helper struct which generates fields for the CDS time provider from a datetime.
#[cfg(feature = "chrono")] #[cfg(feature = "chrono")]
@@ -277,7 +264,7 @@ struct ConversionFromChronoDatetime {
} }
#[cfg(feature = "chrono")] #[cfg(feature = "chrono")]
impl CdsCommon for ConversionFromChronoDatetime { impl CdsBase for ConversionFromChronoDatetime {
#[inline] #[inline]
fn submillis_precision(&self) -> SubmillisPrecision { fn submillis_precision(&self) -> SubmillisPrecision {
self.submillis_prec self.submillis_prec
@@ -299,12 +286,7 @@ impl CdsCommon for ConversionFromChronoDatetime {
} }
#[cfg(feature = "chrono")] #[cfg(feature = "chrono")]
impl CdsConverter for ConversionFromChronoDatetime { impl CdsConverter for ConversionFromChronoDatetime {}
delegate::delegate! {to self.unix_conversion {
#[inline]
fn unix_days_seconds(&self) -> i64;
}}
}
#[inline] #[inline]
fn calc_unix_days_and_secs_of_day(unix_seconds: i64) -> (i64, u32) { fn calc_unix_days_and_secs_of_day(unix_seconds: i64) -> (i64, u32) {
@@ -414,7 +396,7 @@ impl ConversionFromNow {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl CdsCommon for ConversionFromNow { impl CdsBase for ConversionFromNow {
fn submillis_precision(&self) -> SubmillisPrecision { fn submillis_precision(&self) -> SubmillisPrecision {
self.submillis_prec self.submillis_prec
} }
@@ -431,9 +413,7 @@ impl CdsCommon for ConversionFromNow {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl CdsConverter for ConversionFromNow { impl CdsConverter for ConversionFromNow {}
delegate::delegate! {to self.unix_conversion { fn unix_days_seconds(&self) -> i64; }}
}
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub trait DynCdsTimeProvider: CcsdsTimeProvider + CdsTimestamp + TimeWriter + Any {} pub trait DynCdsTimeProvider: CcsdsTimeProvider + CdsTimestamp + TimeWriter + Any {}
@@ -493,7 +473,7 @@ pub fn get_dyn_time_provider_from_bytes(
} }
} }
impl<ProvidesDaysLen: ProvidesDaysLength> CdsCommon for CdsTime<ProvidesDaysLen> { impl<ProvidesDaysLen: ProvidesDaysLength> CdsBase for CdsTime<ProvidesDaysLen> {
fn submillis_precision(&self) -> SubmillisPrecision { fn submillis_precision(&self) -> SubmillisPrecision {
precision_from_pfield(self.pfield) precision_from_pfield(self.pfield)
} }
@@ -623,12 +603,14 @@ impl<ProvidesDaysLen: ProvidesDaysLength> CdsTime<ProvidesDaysLen> {
init_len init_len
} }
fn setup(&mut self, unix_days_seconds: i64, ms_of_day: u32) {
self.calc_unix_seconds(unix_days_seconds, ms_of_day);
}
#[inline] #[inline]
fn calc_unix_seconds(&mut self, mut unix_days_seconds: i64, ms_of_day: u32) { fn calc_unix_seconds(&self) -> UnixTime {
let unix_days_seconds =
ccsds_to_unix_days(i64::try_from(self.ccsds_days()).unwrap()) * SECONDS_PER_DAY as i64;
self.calc_unix_seconds_internal(unix_days_seconds, self.ms_of_day())
}
#[inline]
fn calc_unix_seconds_internal(&self, mut unix_days_seconds: i64, ms_of_day: u32) -> UnixTime {
let seconds_of_day = (ms_of_day / 1000) as i64; let seconds_of_day = (ms_of_day / 1000) as i64;
if unix_days_seconds < 0 { if unix_days_seconds < 0 {
unix_days_seconds -= seconds_of_day; unix_days_seconds -= seconds_of_day;
@@ -639,7 +621,7 @@ impl<ProvidesDaysLen: ProvidesDaysLength> CdsTime<ProvidesDaysLen> {
if let Some(precision) = self.precision_as_ns() { if let Some(precision) = self.precision_as_ns() {
subsec_nanos += precision; subsec_nanos += precision;
} }
self.unix_time = UnixTime::new(unix_days_seconds, subsec_nanos); UnixTime::new(unix_days_seconds, subsec_nanos)
} }
fn length_check(&self, buf: &[u8], len_as_bytes: usize) -> Result<(), ByteConversionError> { fn length_check(&self, buf: &[u8], len_as_bytes: usize) -> Result<(), ByteConversionError> {
@@ -660,15 +642,12 @@ impl<ProvidesDaysLen: ProvidesDaysLength> CdsTime<ProvidesDaysLen> {
where where
i64: From<ProvidesDaysLen::FieldType>, i64: From<ProvidesDaysLen::FieldType>,
{ {
let mut provider = Self { let provider = Self {
pfield: Self::generate_p_field(days_len, SubmillisPrecision::Absent), pfield: Self::generate_p_field(days_len, SubmillisPrecision::Absent),
ccsds_days, ccsds_days,
ms_of_day, ms_of_day,
unix_time: Default::default(),
submillis: 0, submillis: 0,
}; };
let unix_days_seconds = ccsds_to_unix_days(i64::from(ccsds_days)) * SECONDS_PER_DAY as i64;
provider.setup(unix_days_seconds, ms_of_day);
Ok(provider) Ok(provider)
} }
@@ -738,14 +717,12 @@ impl<ProvidesDaysLen: ProvidesDaysLength> CdsTime<ProvidesDaysLen> {
.ccsds_days_as_u32() .ccsds_days_as_u32()
.try_into() .try_into()
.map_err(|_| CdsError::InvalidCcsdsDays(converter.ccsds_days_as_u32().into()))?; .map_err(|_| CdsError::InvalidCcsdsDays(converter.ccsds_days_as_u32().into()))?;
let mut provider = Self { let provider = Self {
pfield: Self::generate_p_field(days_len, converter.submillis_precision()), pfield: Self::generate_p_field(days_len, converter.submillis_precision()),
ccsds_days, ccsds_days,
ms_of_day: converter.ms_of_day(), ms_of_day: converter.ms_of_day(),
unix_time: Default::default(),
submillis: converter.submillis(), submillis: converter.submillis(),
}; };
provider.setup(converter.unix_days_seconds(), converter.ms_of_day());
Ok(provider) Ok(provider)
} }
@@ -786,10 +763,6 @@ impl<ProvidesDaysLen: ProvidesDaysLength> CdsTime<ProvidesDaysLen> {
})?; })?;
self.ccsds_days = ccsds_days; self.ccsds_days = ccsds_days;
self.ms_of_day = conversion_from_now.unix_conversion.ms_of_day; self.ms_of_day = conversion_from_now.unix_conversion.ms_of_day;
self.setup(
conversion_from_now.unix_conversion.unix_days_seconds,
conversion_from_now.unix_conversion.ms_of_day,
);
Ok(()) Ok(())
} }
} }
@@ -1186,30 +1159,24 @@ impl TryFrom<chrono::DateTime<chrono::Utc>> for CdsTime<DaysLen24Bits> {
} }
impl<ProvidesDaysLen: ProvidesDaysLength> CcsdsTimeProvider for CdsTime<ProvidesDaysLen> { impl<ProvidesDaysLen: ProvidesDaysLength> CcsdsTimeProvider for CdsTime<ProvidesDaysLen> {
#[inline]
fn len_as_bytes(&self) -> usize { fn len_as_bytes(&self) -> usize {
Self::calc_stamp_len(self.pfield) Self::calc_stamp_len(self.pfield)
} }
#[inline]
fn p_field(&self) -> (usize, [u8; 2]) { fn p_field(&self) -> (usize, [u8; 2]) {
(1, [self.pfield, 0]) (1, [self.pfield, 0])
} }
#[inline]
fn ccdsd_time_code(&self) -> CcsdsTimeCode { fn ccdsd_time_code(&self) -> CcsdsTimeCode {
CcsdsTimeCode::Cds CcsdsTimeCode::Cds
} }
#[inline]
fn unix_secs(&self) -> i64 {
self.unix_time.secs
}
#[inline]
fn subsec_nanos(&self) -> u32 {
self.unix_time.subsec_nanos
}
#[inline] #[inline]
fn unix_time(&self) -> UnixTime { fn unix_time(&self) -> UnixTime {
self.unix_time self.calc_unix_seconds()
} }
} }

View File

@@ -183,8 +183,13 @@ pub trait CcsdsTimeProvider {
fn p_field(&self) -> (usize, [u8; 2]); fn p_field(&self) -> (usize, [u8; 2]);
fn ccdsd_time_code(&self) -> CcsdsTimeCode; fn ccdsd_time_code(&self) -> CcsdsTimeCode;
fn unix_secs(&self) -> i64; fn unix_secs(&self) -> i64 {
fn subsec_nanos(&self) -> u32; self.unix_time().secs
}
fn subsec_nanos(&self) -> u32 {
self.unix_time().subsec_nanos
}
fn subsec_millis(&self) -> u16 { fn subsec_millis(&self) -> u16 {
(self.subsec_nanos() / 1_000_000) as u16 (self.subsec_nanos() / 1_000_000) as u16