Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SignedPlainOldULE, add serialize impls for ULE types (also missing Eq impl for VZV) #1356

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions utils/zerovec/src/ule/chars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,25 @@ impl AsULE for char {
// as CharULE on little-endian platforms.
unsafe impl EqULE for char {}

#[cfg(feature = "serde")]
impl serde::Serialize for CharULE {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
char::from_unaligned(*self).serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for CharULE {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(char::as_unaligned(char::deserialize(deserializer)?))
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
8 changes: 4 additions & 4 deletions utils/zerovec/src/ule/custom/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,18 +88,18 @@
//! }
//!
//! fn main() {
//! let mut foos = vec![Foo {field1: 'u', field2: 983, field3: ZeroVec::alloc_from_slice(&[1212,2309,500,7000])},
//! Foo {field1: 'l', field2: 1010, field3: ZeroVec::alloc_from_slice(&[1932, 0, 8888, 91237])}];
//! let mut foos = vec![Foo {field1: 'u', field2: 983, field3: ZeroVec::<u32>::alloc_from_slice(&[1212,2309,500,7000])},
//! Foo {field1: 'l', field2: 1010, field3: ZeroVec::<u32>::alloc_from_slice(&[1932, 0, 8888, 91237])}];
//!
//! let vzv = VarZeroVec::from(&*foos);
//!
//! assert_eq!(char::from_unaligned(vzv.get(0).unwrap().field1), 'u');
//! assert_eq!(u32::from_unaligned(vzv.get(0).unwrap().field2), 983);
//! assert_eq!(&vzv.get(0).unwrap().field3, ZeroVec::alloc_from_slice(&[1212,2309,500,7000]).as_slice());
//! assert_eq!(&vzv.get(0).unwrap().field3, ZeroVec::<u32>::alloc_from_slice(&[1212,2309,500,7000]).as_slice());
//!
//! assert_eq!(char::from_unaligned(vzv.get(1).unwrap().field1), 'l');
//! assert_eq!(u32::from_unaligned(vzv.get(1).unwrap().field2), 1010);
//! assert_eq!(&vzv.get(1).unwrap().field3, ZeroVec::alloc_from_slice(&[1932, 0, 8888, 91237]).as_slice());
//! assert_eq!(&vzv.get(1).unwrap().field3, ZeroVec::<u32>::alloc_from_slice(&[1932, 0, 8888, 91237]).as_slice());
//! }
//! ```

Expand Down
7 changes: 6 additions & 1 deletion utils/zerovec/src/ule/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ mod vec;
pub use chars::CharULE;
pub use error::ULEError;
pub use pair::{PairULE, PairULEError};
pub use plain::PlainOldULE;
pub use plain::{PlainOldULE, SignedPlainOldULE};

use alloc::alloc::Layout;
use alloc::borrow::ToOwned;
Expand Down Expand Up @@ -149,6 +149,11 @@ pub trait AsULE: Copy {
/// `PlainOldULE` with the desired width; for example, `u32` uses `PlainOldULE<4>`.
///
/// Types that are not well-defined for all bit values should implement a custom ULE.
///
/// If this ULE type is being used in `VarZeroVec<[ULE]>` and you want human readable
/// serialization to work identically to that of the `Self`,
/// make sure that the serializer impls on the `ULE` type are the same as those
/// on `Self`. If not, it might be worth using a wrapped type for the `ULE` type.
type ULE: ULE;

/// Converts from `&Self` to `Self::ULE`.
Expand Down
86 changes: 72 additions & 14 deletions utils/zerovec/src/ule/plain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,28 @@ use super::*;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct PlainOldULE<const N: usize>(pub [u8; N]);

/// A signed version of [`PlainOldULE`]. This primarily exists so that complex types
/// like `VarZeroVec<[SignedPlainOldULE]>` will correctly serialize in a human-readable
/// fashion.
#[repr(transparent)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct SignedPlainOldULE<const N: usize>(pub PlainOldULE<N>);

// These impls exist to make the macros simpler
impl<const N: usize> PlainOldULE<N> {
#[inline]
fn into_bytes(self) -> [u8; N] {
self.0
}
}

impl<const N: usize> SignedPlainOldULE<N> {
#[inline]
fn into_bytes(self) -> [u8; N] {
self.0 .0
}
}

macro_rules! impl_byte_slice_size {
($size:literal) => {
impl From<[u8; $size]> for PlainOldULE<$size> {
Expand All @@ -20,6 +42,12 @@ macro_rules! impl_byte_slice_size {
Self(le_bytes)
}
}
impl From<[u8; $size]> for SignedPlainOldULE<$size> {
#[inline]
fn from(le_bytes: [u8; $size]) -> Self {
Self(le_bytes.into())
}
}
impl PlainOldULE<$size> {
#[inline]
pub fn as_bytes(&self) -> &[u8] {
Expand Down Expand Up @@ -52,6 +80,16 @@ macro_rules! impl_byte_slice_size {
}
}

/// Forwards to above impl and is safe for the same reason
unsafe impl ULE for SignedPlainOldULE<$size> {
type Error = ULEError<core::convert::Infallible>;

#[inline]
fn validate_byte_slice(bytes: &[u8]) -> Result<(), Self::Error> {
PlainOldULE::<$size>::validate_byte_slice(bytes)
}
}

impl PlainOldULE<$size> {
#[inline]
pub fn from_byte_slice_unchecked_mut(bytes: &mut [u8]) -> &mut [Self] {
Expand All @@ -65,27 +103,47 @@ macro_rules! impl_byte_slice_size {
}

macro_rules! impl_byte_slice_type {
($type:ty, $size:literal) => {
impl From<$type> for PlainOldULE<$size> {
($type:ty, $ule_type:ty) => {
impl From<$type> for $ule_type {
#[inline]
fn from(value: $type) -> Self {
Self(value.to_le_bytes())
value.to_le_bytes().into()
}
}
impl AsULE for $type {
type ULE = PlainOldULE<$size>;
type ULE = $ule_type;
#[inline]
fn as_unaligned(self) -> Self::ULE {
PlainOldULE(self.to_le_bytes())
self.to_le_bytes().into()
}
#[inline]
fn from_unaligned(unaligned: Self::ULE) -> Self {
<$type>::from_le_bytes(unaligned.0)
<$type>::from_le_bytes(unaligned.into_bytes())
}
}
// EqULE is true because $type and PlainOldULE<$size>
// have the same byte sequence on little-endian
unsafe impl EqULE for $type {}

#[cfg(feature = "serde")]
impl serde::Serialize for $ule_type {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
<$type>::from_unaligned(*self).serialize(serializer)
}
}

#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for $ule_type {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(<$type>::as_unaligned(<$type>::deserialize(deserializer)?))
}
}
};
}

Expand All @@ -94,15 +152,15 @@ impl_byte_slice_size!(4);
impl_byte_slice_size!(8);
impl_byte_slice_size!(16);

impl_byte_slice_type!(u16, 2);
impl_byte_slice_type!(u32, 4);
impl_byte_slice_type!(u64, 8);
impl_byte_slice_type!(u128, 16);
impl_byte_slice_type!(u16, PlainOldULE<2>);
impl_byte_slice_type!(u32, PlainOldULE<4>);
impl_byte_slice_type!(u64, PlainOldULE<8>);
impl_byte_slice_type!(u128, PlainOldULE<16>);

impl_byte_slice_type!(i16, 2);
impl_byte_slice_type!(i32, 4);
impl_byte_slice_type!(i64, 8);
impl_byte_slice_type!(i128, 16);
impl_byte_slice_type!(i16, SignedPlainOldULE<2>);
impl_byte_slice_type!(i32, SignedPlainOldULE<4>);
impl_byte_slice_type!(i64, SignedPlainOldULE<8>);
impl_byte_slice_type!(i128, SignedPlainOldULE<16>);

// Safety (based on the safety checklist on the ULE trait):
// 1. u8 does not include any uninitialized or padding bytes.
Expand Down
8 changes: 8 additions & 0 deletions utils/zerovec/src/varzerovec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,14 @@ where
}
}

impl<'a, T> Eq for VarZeroVec<'a, T>
where
T: VarULE,
T: ?Sized,
T: PartialEq,
{
}

impl<T, A> PartialEq<&'_ [A]> for VarZeroVec<'_, T>
where
T: VarULE + ?Sized,
Expand Down