From 5eab21413e766e0eba500a8d7ff394f003d0b70a Mon Sep 17 00:00:00 2001 From: Vo Van Nghia Date: Fri, 20 Sep 2024 10:48:20 +0200 Subject: [PATCH] add support for time --- Cargo.toml | 3 +- src/derive/datetime.rs | 67 ++++++++++++++++++++++++++ src/derive/duration.rs | 19 +------- src/derive/mod.rs | 1 + src/ext/mod.rs | 2 + src/ext/time_crate/mod.rs | 1 + src/ext/time_crate/time.rs | 97 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 172 insertions(+), 18 deletions(-) create mode 100644 src/derive/datetime.rs create mode 100644 src/ext/time_crate/mod.rs create mode 100644 src/ext/time_crate/time.rs diff --git a/Cargo.toml b/Cargo.toml index 6cf91e2..8c4c9e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ bitcode_derive = { version = "0.6.3", path = "./bitcode_derive", optional = true bytemuck = { version = "1.14", features = [ "min_const_generics", "must_cast" ] } glam = { version = ">=0.21", default-features = false, optional = true } serde = { version = "1.0", default-features = false, features = [ "alloc" ], optional = true } +time = { version = "0.3", default-features = false, features = [ "alloc" ], optional = true } [dev-dependencies] arrayvec = { version = "0.7", features = [ "serde" ] } @@ -37,7 +38,7 @@ zstd = "0.13.0" [features] derive = [ "dep:bitcode_derive" ] -std = [ "serde?/std", "glam?/std", "arrayvec?/std" ] +std = [ "serde?/std", "glam?/std", "arrayvec?/std", "time?/std" ] default = [ "derive", "std" ] [package.metadata.docs.rs] diff --git a/src/derive/datetime.rs b/src/derive/datetime.rs new file mode 100644 index 0000000..63d8c8e --- /dev/null +++ b/src/derive/datetime.rs @@ -0,0 +1,67 @@ +use bytemuck::CheckedBitPattern; + +use super::Decode; + +/// A u8 guaranteed to be < 24. +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct Hour(pub u8); +// Safety: u8 and Hour have the same layout since Hour is #[repr(transparent)]. +unsafe impl CheckedBitPattern for Hour { + type Bits = u8; + #[inline(always)] + fn is_valid_bit_pattern(bits: &Self::Bits) -> bool { + *bits < 24 + } +} +impl<'a> Decode<'a> for Hour { + type Decoder = crate::int::CheckedIntDecoder<'a, Hour, u8>; +} + +/// A u8 guaranteed to be < 60. +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct Minute(pub u8); +// Safety: u8 and Minute have the same layout since Minute is #[repr(transparent)]. +unsafe impl CheckedBitPattern for Minute { + type Bits = u8; + #[inline(always)] + fn is_valid_bit_pattern(bits: &Self::Bits) -> bool { + *bits < 60 + } +} +impl<'a> Decode<'a> for Minute { + type Decoder = crate::int::CheckedIntDecoder<'a, Minute, u8>; +} + +/// A u8 guaranteed to be < 60. +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct Second(pub u8); +// Safety: u8 and Second have the same layout since Second is #[repr(transparent)]. +unsafe impl CheckedBitPattern for Second { + type Bits = u8; + #[inline(always)] + fn is_valid_bit_pattern(bits: &Self::Bits) -> bool { + *bits < 60 + } +} +impl<'a> Decode<'a> for Second { + type Decoder = crate::int::CheckedIntDecoder<'a, Second, u8>; +} + +/// A u32 guaranteed to be < 1 billion. +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct Nanoseconds(pub u32); +// Safety: u32 and Nanoseconds have the same layout since Nanoseconds is #[repr(transparent)]. +unsafe impl CheckedBitPattern for Nanoseconds { + type Bits = u32; + #[inline(always)] + fn is_valid_bit_pattern(bits: &Self::Bits) -> bool { + *bits < 1_000_000_000 + } +} +impl<'a> Decode<'a> for Nanoseconds { + type Decoder = crate::int::CheckedIntDecoder<'a, Nanoseconds, u32>; +} diff --git a/src/derive/duration.rs b/src/derive/duration.rs index 52664d4..84878a6 100644 --- a/src/derive/duration.rs +++ b/src/derive/duration.rs @@ -1,4 +1,5 @@ use crate::coder::{Buffer, Decoder, Encoder, Result, View}; +use crate::datetime::Nanoseconds; use crate::{Decode, Encode}; use alloc::vec::Vec; use bytemuck::CheckedBitPattern; @@ -32,22 +33,6 @@ impl Encode for Duration { type Encoder = DurationEncoder; } -/// A u32 guaranteed to be < 1 billion. Prevents Duration::new from panicking. -#[derive(Copy, Clone)] -#[repr(transparent)] -struct Nanoseconds(u32); -// Safety: u32 and Nanoseconds have the same layout since Nanoseconds is #[repr(transparent)]. -unsafe impl CheckedBitPattern for Nanoseconds { - type Bits = u32; - #[inline(always)] - fn is_valid_bit_pattern(bits: &Self::Bits) -> bool { - *bits < 1_000_000_000 - } -} -impl<'a> Decode<'a> for Nanoseconds { - type Decoder = crate::int::CheckedIntDecoder<'a, Nanoseconds, u32>; -} - #[derive(Default)] pub struct DurationDecoder<'a> { secs: >::Decoder, @@ -95,5 +80,5 @@ mod tests { .map(|(s, n): (_, u32)| Duration::new(s, n % 1_000_000_000)) .collect() } - crate::bench_encode_decode!(duration_vec: Vec<_>); + crate::bench_encode_decode!(duration_vec: Vec); } diff --git a/src/derive/mod.rs b/src/derive/mod.rs index fc4c6fc..999edb5 100644 --- a/src/derive/mod.rs +++ b/src/derive/mod.rs @@ -6,6 +6,7 @@ use core::num::NonZeroUsize; mod array; mod convert; +pub(crate) mod datetime; mod duration; mod empty; mod impls; diff --git a/src/ext/mod.rs b/src/ext/mod.rs index b7b26f1..684e3ae 100644 --- a/src/ext/mod.rs +++ b/src/ext/mod.rs @@ -3,6 +3,8 @@ mod arrayvec; #[cfg(feature = "glam")] #[rustfmt::skip] // Makes impl_struct! calls way longer. mod glam; +#[cfg(feature = "time")] +mod time_crate; #[allow(unused)] macro_rules! impl_struct { diff --git a/src/ext/time_crate/mod.rs b/src/ext/time_crate/mod.rs new file mode 100644 index 0000000..7d75173 --- /dev/null +++ b/src/ext/time_crate/mod.rs @@ -0,0 +1 @@ +mod time; diff --git a/src/ext/time_crate/time.rs b/src/ext/time_crate/time.rs new file mode 100644 index 0000000..7649c1d --- /dev/null +++ b/src/ext/time_crate/time.rs @@ -0,0 +1,97 @@ +use crate::coder::{Buffer, Decoder, Encoder, Result, View}; +use crate::datetime::{Hour, Minute, Nanoseconds, Second}; +use crate::{Decode, Encode}; +use alloc::vec::Vec; +use core::num::NonZeroUsize; +use time::Time; + +#[derive(Default)] +pub struct TimeEncoder { + hour: ::Encoder, + minute: ::Encoder, + second: ::Encoder, + nanosecond: ::Encoder, +} +impl Encoder