dyn provider works great
Some checks failed
Rust/spacepackets/pipeline/head There was a failure building this commit

This commit is contained in:
Robin Müller 2023-01-15 11:54:23 +01:00
parent 39bf0c6a61
commit 22f3b72faf
No known key found for this signature in database
GPG Key ID: 71B58F8A3CDFA9AC

View File

@ -7,6 +7,7 @@ use crate::private::Sealed;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
use chrono::Datelike;
use core::any::Any;
use core::fmt::Debug;
use core::ops::Add;
use core::time::Duration;
@ -147,11 +148,22 @@ pub struct TimeProvider<DaysLen: ProvidesDaysLength = DaysLen16Bits> {
unix_seconds: i64,
}
/// Private trait which serves as an abstraction for different converters.
trait CdsConverter {
/// Common properties for all CDS time providers.
///
/// Also exists to encapsulate properties used by private converters.
pub trait CdsCommon {
fn submillis_precision(&self) -> Option<SubmillisPrecision>;
fn ms_of_day(&self) -> u32;
fn ccsds_days(&self) -> u32;
fn ccsds_days_as_u32(&self) -> u32;
}
/// Generic properties for all CDS time providers.
pub trait CdsTimeStamp: CdsCommon {
fn len_of_day_seg(&self) -> LengthOfDaySegment;
}
/// Private trait which serves as an abstraction for different converters.
trait CdsConverter: CdsCommon {
fn unix_days_seconds(&self) -> i64;
}
@ -185,7 +197,7 @@ impl ConversionFromUnix {
}
}
impl CdsConverter for ConversionFromUnix {
impl CdsCommon for ConversionFromUnix {
fn submillis_precision(&self) -> Option<SubmillisPrecision> {
None
}
@ -194,22 +206,23 @@ impl CdsConverter for ConversionFromUnix {
self.ms_of_day
}
fn ccsds_days(&self) -> u32 {
fn ccsds_days_as_u32(&self) -> u32 {
self.ccsds_days
}
}
impl CdsConverter for ConversionFromUnix {
fn unix_days_seconds(&self) -> i64 {
self.unix_days_seconds
}
}
/// Helper struct which generates fields for the CDS time provider from a datetime.
struct ConversionFromDatetime {
unix_conversion: ConversionFromUnix,
submillis_prec: Option<SubmillisPrecision>,
}
impl CdsConverter for ConversionFromDatetime {
impl CdsCommon for ConversionFromDatetime {
fn submillis_precision(&self) -> Option<SubmillisPrecision> {
self.submillis_prec
}
@ -217,12 +230,15 @@ impl CdsConverter for ConversionFromDatetime {
delegate! {
to self.unix_conversion {
fn ms_of_day(&self) -> u32;
fn ccsds_days(&self) -> u32;
fn unix_days_seconds(&self) -> i64;
fn ccsds_days_as_u32(&self) -> u32;
}
}
}
impl CdsConverter for ConversionFromDatetime {
delegate! {to self.unix_conversion { fn unix_days_seconds(&self) -> i64; }}
}
#[inline]
fn calc_unix_days_and_secs_of_day(unix_seconds: i64) -> (i64, u32) {
let mut secs_of_day = unix_seconds % SECONDS_PER_DAY as i64;
@ -332,22 +348,25 @@ impl ConversionFromNow {
}
#[cfg(feature = "std")]
impl CdsConverter for ConversionFromNow {
impl CdsCommon for ConversionFromNow {
fn submillis_precision(&self) -> Option<SubmillisPrecision> {
self.submillis_prec
}
delegate! {
to self.unix_conversion {
fn ms_of_day(&self) -> u32;
fn ccsds_days(&self) -> u32;
fn unix_days_seconds(&self) -> i64;
fn ccsds_days_as_u32(&self) -> u32;
}
}
}
#[cfg(feature = "std")]
impl CdsConverter for ConversionFromNow {
delegate! {to self.unix_conversion { fn unix_days_seconds(&self) -> i64; }}
}
#[cfg(feature = "alloc")]
pub trait DynCdsTimeProvider: CcsdsTimeProvider + TimeWriter {}
pub trait DynCdsTimeProvider: CcsdsTimeProvider + CdsTimeStamp + TimeWriter + Any {}
#[cfg(feature = "alloc")]
impl DynCdsTimeProvider for TimeProvider<DaysLen16Bits> {}
#[cfg(feature = "alloc")]
@ -379,7 +398,31 @@ pub fn get_dyn_time_provider_from_bytes(
}
}
impl<ProvidesDaysLen: ProvidesDaysLength> CdsCommon for TimeProvider<ProvidesDaysLen> {
fn submillis_precision(&self) -> Option<SubmillisPrecision> {
self.submillis_precision
}
fn ms_of_day(&self) -> u32 {
self.ms_of_day
}
fn ccsds_days_as_u32(&self) -> u32 {
self.ccsds_days.into()
}
}
impl<ProvidesDaysLen: ProvidesDaysLength> TimeProvider<ProvidesDaysLen> {
/// This function returns the correct [TimeProvider] instance from a raw byte array
/// by checking the days of length field. It also checks the CCSDS time code for correctness.
///
/// The time provider instance is returned as a [DynCdsTimeProvider] trait object.
/// This function also simply calls [`get_dyn_time_provider_from_bytes`].
#[cfg(feature = "alloc")]
pub fn from_bytes_dyn(buf: &[u8]) -> Result<Box<dyn DynCdsTimeProvider>, TimestampError> {
get_dyn_time_provider_from_bytes(buf)
}
pub fn set_submillis_precision(&mut self, prec: SubmillisPrecision) {
self.pfield &= !(0b11);
if let SubmillisPrecision::Absent = prec {
@ -407,18 +450,6 @@ impl<ProvidesDaysLen: ProvidesDaysLength> TimeProvider<ProvidesDaysLen> {
self.ccsds_days
}
fn ccsds_days_as_u32(&self) -> u32 {
self.ccsds_days.into()
}
pub fn submillis_precision(&self) -> Option<SubmillisPrecision> {
self.submillis_precision
}
pub fn ms_of_day(&self) -> u32 {
self.ms_of_day
}
fn generic_raw_read_checks(
buf: &[u8],
days_len: LengthOfDaySegment,
@ -603,8 +634,10 @@ impl<ProvidesDaysLen: ProvidesDaysLength> TimeProvider<ProvidesDaysLen> {
converter: C,
) -> Result<Self, TimestampError> {
let ccsds_days: ProvidesDaysLen::FieldType =
converter.ccsds_days().try_into().map_err(|_| {
TimestampError::CdsError(CdsError::InvalidCcsdsDays(converter.ccsds_days().into()))
converter.ccsds_days_as_u32().try_into().map_err(|_| {
TimestampError::CdsError(CdsError::InvalidCcsdsDays(
converter.ccsds_days_as_u32().into(),
))
})?;
let mut provider = Self {
pfield: Self::generate_p_field(days_len, converter.submillis_precision()),
@ -908,6 +941,18 @@ fn add_for_max_ccsds_days_val<T: ProvidesDaysLength>(
(next_ccsds_days, next_ms_of_day, precision)
}
impl CdsTimeStamp for TimeProvider<DaysLen16Bits> {
fn len_of_day_seg(&self) -> LengthOfDaySegment {
LengthOfDaySegment::Short16Bits
}
}
impl CdsTimeStamp for TimeProvider<DaysLen24Bits> {
fn len_of_day_seg(&self) -> LengthOfDaySegment {
LengthOfDaySegment::Long24Bits
}
}
/// Allows adding an duration in form of an offset. Please note that the CCSDS days will rollover
/// when they overflow, because addition needs to be infallible. The user needs to check for a
/// days overflow when this is a possibility and might be a problem.
@ -1443,7 +1488,7 @@ mod tests {
let time_provider = TimeProvider::from_dt_with_u16_days(&datetime_utc).unwrap();
// https://www.timeanddate.com/date/durationresult.html?d1=01&m1=01&y1=1958&d2=14&m2=01&y2=2023
// Leap years need to be accounted for as well.
assert_eq!(time_provider.ccsds_days, 23754);
assert_eq!(time_provider.ccsds_days(), 23754);
assert_eq!(
time_provider.ms_of_day,
30 * 1000 + 49 * 60 * 1000 + 16 * 60 * 60 * 1000 + subsec_millis
@ -1662,6 +1707,46 @@ mod tests {
assert_eq!(provider2.ms_of_day, 5000);
}
#[test]
fn test_dyn_creation_u24_days() {
let stamp = TimeProvider::new_with_u24_days(u16::MAX as u32 + 1, 24).unwrap();
let mut buf: [u8; 32] = [0; 32];
stamp.write_to_bytes(&mut buf).unwrap();
let dyn_provider = get_dyn_time_provider_from_bytes(&buf);
assert!(dyn_provider.is_ok());
let dyn_provider = dyn_provider.unwrap();
assert_eq!(dyn_provider.ccdsd_time_code(), CcsdsTimeCodes::Cds);
assert_eq!(dyn_provider.ccsds_days_as_u32(), u16::MAX as u32 + 1);
assert_eq!(dyn_provider.ms_of_day(), 24);
assert_eq!(dyn_provider.submillis_precision(), None);
assert_eq!(
dyn_provider.len_of_day_seg(),
LengthOfDaySegment::Long24Bits
);
}
#[test]
fn test_dyn_creation_u16_days_with_precision() {
let mut stamp = TimeProvider::new_with_u16_days(24, 24);
stamp.set_submillis_precision(SubmillisPrecision::Microseconds(666));
let mut buf: [u8; 32] = [0; 32];
stamp.write_to_bytes(&mut buf).unwrap();
let dyn_provider = get_dyn_time_provider_from_bytes(&buf);
assert!(dyn_provider.is_ok());
let dyn_provider = dyn_provider.unwrap();
assert_eq!(dyn_provider.ccdsd_time_code(), CcsdsTimeCodes::Cds);
assert_eq!(dyn_provider.ccsds_days_as_u32(), 24);
assert_eq!(dyn_provider.ms_of_day(), 24);
assert_eq!(
dyn_provider.len_of_day_seg(),
LengthOfDaySegment::Short16Bits
);
assert!(dyn_provider.submillis_precision().is_some());
if let SubmillisPrecision::Microseconds(us) = dyn_provider.submillis_precision().unwrap() {
assert_eq!(us, 666);
}
}
#[test]
#[cfg(feature = "serde")]
fn test_serialization() {