Module zerovec::ule::custom[][src]

Expand description

This module contains utilities that help define custom VarULE types, especially those using complex custom dynamically sized types.

Example

For example, if your regular stack type is:


struct Foo<'a> {
   field1: char,
   field2: u32,
   field3: ZeroVec<'a, u32>   
}

then the ULE type will be implemented as follows:

use zerovec::{ZeroVec, VarZeroVec};
use zerovec::ule::custom::EncodeAsVarULE;
use zerovec::ule::*;
use core::mem;


// Must be repr(packed) for safety of VarULE!
// Must also only contain ULE types
#[repr(packed)]
struct FooULE {
    field1: <char as AsULE>::ULE,   
    field2: <u32 as AsULE>::ULE,
    field3: [<u32 as AsULE>::ULE],
}

unsafe impl VarULE for FooULE {
    type Error = &'static str; // use strings for simplicity
    fn validate_byte_slice(bytes: &[u8]) -> Result<(), Self::Error> {
        // validate each field
        <char as AsULE>::ULE::validate_byte_slice(&bytes[0..4]).map_err(|_| "validating char failed")?;
        <char as AsULE>::ULE::validate_byte_slice(&bytes[4..8]).map_err(|_| "validating u32 failed")?;
        let _ = ZeroVec::<u32>::parse_byte_slice(&bytes[8..]).map_err(|_| "validating ZeroVec failed")?;
        Ok(())
    }
    unsafe fn from_byte_slice_unchecked(bytes: &[u8]) -> &Self {
        let ptr = bytes.as_ptr();
        let len = bytes.len();
        // subtract the length of the char and u32 to get the length of the array
        let len_new = (len - 8) / 4;
        // it's hard constructing custom DSTs, we fake a pointer/length construction
        // eventually we can use the Pointer::Metadata APIs when they stabilize
        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 {
       // take each field, convert to ULE byte slices, and pass them through
       cb(&[<char as AsULE>::ULE::as_byte_slice(&[self.field1.as_unaligned()]),
            <u32 as AsULE>::ULE::as_byte_slice(&[self.field2.as_unaligned()]),
            // the ZeroVec is already in the correct slice format
            self.field3.as_bytes()])
   }
}

fn main() {
    let mut foos = vec![Foo {field1: 'u', field2: 983, field3: ZeroVec::clone_from_slice(&[1212,2309,500,7000])},
                        Foo {field1: 'l', field2: 1010, field3: ZeroVec::clone_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::clone_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::clone_from_slice(&[1932, 0, 8888, 91237]).as_slice());
}

Traits

Allows types to be encoded as VarULEs. This is highly useful for implementing VarULE on custom DSTs where the type cannot be obtained as a reference to some other type.