Documentation on implementing custom VarULE types.
This module contains documentation for defining custom VarULE types,
especially those using complex custom dynamically sized types.
In most cases you should be able to create custom VarULE types using
#[make_varule].
Example
For example, if your regular stack type is:
use zerofrom::ZeroFrom;
use zerovec::ule::*;
use zerovec::ZeroVec;
#[derive(serde::Serialize, serde::Deserialize)]
struct Foo<'a> {
field1: char,
field2: u32,
#[serde(borrow)]
field3: ZeroVec<'a, u32>,
}
then the ULE type will be implemented as follows. Ideally, you should have
EncodeAsVarULE and ZeroFrom implementations on Foo pertaining to FooULE,
as well as a Serialize impl on FooULE and a Deserialize impl on Box<FooULE>
to enable human-readable serialization and deserialization.
use zerovec::{ZeroVec, VarZeroVec, ZeroSlice};
use zerovec::ule::*;
use zerofrom::ZeroFrom;
use core::mem;
# #[derive(serde::Serialize, serde::Deserialize)]
# struct Foo<'a> {
# field1: char,
# field2: u32,
# #[serde(borrow)]
# field3: ZeroVec<'a, u32>
# }
#[repr(C, packed)]
struct FooULE {
field1: <char as AsULE>::ULE,
field2: <u32 as AsULE>::ULE,
field3: ZeroSlice<u32>,
}
unsafe impl VarULE for FooULE {
fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
<char as AsULE>::ULE::validate_bytes(&bytes[0..3]).map_err(|_| UleError::parse::<Self>())?;
<u32 as AsULE>::ULE::validate_bytes(&bytes[3..7]).map_err(|_| UleError::parse::<Self>())?;
let _ = ZeroVec::<u32>::parse_bytes(&bytes[7..]).map_err(|_| UleError::parse::<Self>())?;
Ok(())
}
unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
let ptr = bytes.as_ptr();
let len = bytes.len();
let len_new = (len - 7) / 4;
let fake_slice = core::ptr::slice_from_raw_parts(ptr as *const <u32 as AsULE>::ULE, len_new);
&*(fake_slice as *const Self)
}
}
unsafe impl EncodeAsVarULE<FooULE> for Foo<'_> {
fn encode_var_ule_as_slices<R>(&self, cb: impl FnOnce(&[&[u8]]) -> R) -> R {
cb(&[<char as AsULE>::ULE::slice_as_bytes(&[self.field1.to_unaligned()]),
<u32 as AsULE>::ULE::slice_as_bytes(&[self.field2.to_unaligned()]),
self.field3.as_bytes()])
}
}
impl<'a> ZeroFrom<'a, FooULE> for Foo<'a> {
fn zero_from(other: &'a FooULE) -> Self {
Self {
field1: AsULE::from_unaligned(other.field1),
field2: AsULE::from_unaligned(other.field2),
field3: ZeroFrom::zero_from(&other.field3),
}
}
}
impl serde::Serialize for FooULE
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
Foo::zero_from(self).serialize(serializer)
}
}
impl<'de> serde::Deserialize<'de> for Box<FooULE>
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let mut foo = Foo::deserialize(deserializer)?;
Ok(encode_varule_to_box(&foo))
}
}
fn main() {
let mut foos = [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 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, &[1212,2309,500,7000][..]);
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, &[1932, 0, 8888, 91237][..]);
}