mirror of
https://github.com/rosenpass/rosenpass.git
synced 2026-02-04 19:11:52 -08:00
docs(util): add docs and examples to the zerocopy module (#532)
This commit is contained in:
@@ -1,3 +1,20 @@
|
||||
//! This module provides utilities for working with zero-copy references
|
||||
//! and slices.
|
||||
//!
|
||||
//! It offers the following primary abstractions and traits:
|
||||
//!
|
||||
//! - [`RefMaker`](crate::zerocopy::RefMaker): A helper structure for safely
|
||||
//! creating `zerocopy::Ref` references from byte slices.
|
||||
//! - [`ZerocopyEmancipateExt`](crate::zerocopy::ZerocopyEmancipateExt):
|
||||
//! A trait to convert `Ref<B, T>` into a borrowed `Ref<&[u8], T>`.
|
||||
//! - [`ZerocopyEmancipateMutExt`](crate::zerocopy::ZerocopyEmancipateMutExt):
|
||||
//! A trait to convert `Ref<B, T>` into a borrowed mutable `Ref<&mut [u8], T>`.
|
||||
//! - [`ZerocopySliceExt`](crate::zerocopy::ZerocopySliceExt): Extension methods
|
||||
//! for parsing byte slices into zero-copy references.
|
||||
//! - [`ZerocopyMutSliceExt`](crate::zerocopy::ZerocopyMutSliceExt):
|
||||
//! Extension methods for parsing and zeroizing byte slices into zero-copy
|
||||
//! references.
|
||||
|
||||
mod ref_maker;
|
||||
mod zerocopy_ref_ext;
|
||||
mod zerocopy_slice_ext;
|
||||
|
||||
@@ -1,74 +1,206 @@
|
||||
use std::marker::PhantomData;
|
||||
//! A module providing the [`RefMaker`] type and its associated methods for constructing
|
||||
//! [`zerocopy::Ref`] references from byte buffers.
|
||||
|
||||
use anyhow::{ensure, Context};
|
||||
use std::marker::PhantomData;
|
||||
use zerocopy::{ByteSlice, ByteSliceMut, Ref};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use crate::zeroize::ZeroizedExt;
|
||||
|
||||
/// A convenience type for working with buffers and extracting [`zerocopy::Ref`]
|
||||
/// references.
|
||||
///
|
||||
/// `RefMaker` holds a buffer and a target type parameter `T`. Using `RefMaker`,
|
||||
/// you can validate that the provided buffer is large enough for `T` and then
|
||||
/// parse out a strongly-typed reference (`Ref`) to that data. It also provides
|
||||
/// methods for extracting prefixes and suffixes from the buffer.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use zerocopy::{AsBytes, FromBytes, FromZeroes, Ref};///
|
||||
/// # use rosenpass_util::zerocopy::RefMaker;
|
||||
///
|
||||
/// #[derive(FromBytes, FromZeroes, AsBytes)]
|
||||
/// #[repr(C)]
|
||||
/// struct Header {
|
||||
/// field1: u32,
|
||||
/// field2: u16,
|
||||
/// field3: u16,
|
||||
/// }
|
||||
/// #[repr(align(4))]
|
||||
/// struct AlignedBuf([u8; 8]);
|
||||
/// let bytes = AlignedBuf([0xAA, 0xBB, 0xCC, 0xDD,
|
||||
/// 0x00, 0x10, 0x20, 0x30]);
|
||||
/// let rm = RefMaker::<&[u8], Header>::new(&bytes.0);
|
||||
/// let header_ref: Ref<&[u8], Header> = rm.parse().unwrap();
|
||||
/// assert_eq!(header_ref.field1, 0xDDCCBBAA);
|
||||
/// assert_eq!(header_ref.field2, 0x1000);
|
||||
/// assert_eq!(header_ref.field3, 0x3020);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
/// A convenience type for working with mutable references to a buffer and an
|
||||
/// expected target type.
|
||||
pub struct RefMaker<B: Sized, T> {
|
||||
buf: B,
|
||||
_phantom_t: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<B, T> RefMaker<B, T> {
|
||||
/// Creates a new RefMaker with the given buffer
|
||||
/// Creates a new `RefMaker` with the given buffer.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use rosenpass_util::zerocopy::RefMaker;
|
||||
/// let buffer = [0u8; 10];
|
||||
/// let rm: RefMaker<_, u32> = RefMaker::new(buffer);
|
||||
/// ```
|
||||
pub fn new(buf: B) -> Self {
|
||||
let _phantom_t = PhantomData;
|
||||
Self { buf, _phantom_t }
|
||||
}
|
||||
|
||||
/// Returns the size in bytes needed for target type T
|
||||
/// Returns the size in bytes required by the target type `T`.
|
||||
/// This is currently defined as [`std::mem::size_of::<T>`] of `T`.
|
||||
pub const fn target_size() -> usize {
|
||||
std::mem::size_of::<T>()
|
||||
}
|
||||
|
||||
/// Consumes this RefMaker and returns the inner buffer
|
||||
/// Consumes this `RefMaker` and returns the inner buffer.
|
||||
pub fn into_buf(self) -> B {
|
||||
self.buf
|
||||
}
|
||||
|
||||
/// Returns a reference to the inner buffer
|
||||
/// Returns a reference to the inner buffer.
|
||||
pub fn buf(&self) -> &B {
|
||||
&self.buf
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the inner buffer
|
||||
/// Returns a mutable reference to the inner buffer.
|
||||
pub fn buf_mut(&mut self) -> &mut B {
|
||||
&mut self.buf
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: ByteSlice, T> RefMaker<B, T> {
|
||||
/// Parses the buffer into a reference of type T
|
||||
/// Parses the buffer into a [`zerocopy::Ref<B, T>`].
|
||||
///
|
||||
/// This will fail if the buffer is smaller than `size_of::<T>`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the buffer is undersized or if parsing fails.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use zerocopy::{AsBytes, FromBytes, FromZeroes, Ref};
|
||||
/// # use rosenpass_util::zerocopy::RefMaker;
|
||||
///
|
||||
/// #[derive(FromBytes, FromZeroes, AsBytes, Debug)]
|
||||
/// #[repr(C)]
|
||||
/// struct Data(u32);
|
||||
///
|
||||
/// let bytes: &[u8] = &[0x01, 0x00, 0x00, 0x00];
|
||||
/// let data_ref: Ref<&[u8], Data> = RefMaker::<_, Data>::new(bytes).parse().unwrap();
|
||||
/// assert_eq!(data_ref.0, 1);
|
||||
///
|
||||
/// // errors if buffer is undersized
|
||||
/// let bytes: &[u8] = &[0x01, 0x02, 0x03];
|
||||
/// let parse_error = RefMaker::<_, Data>::new(bytes).parse()
|
||||
/// .expect_err("Should error");
|
||||
/// assert_eq!(parse_error.to_string(),
|
||||
/// "Buffer is undersized at 3 bytes (need 4 bytes)!");
|
||||
///
|
||||
/// // errors if the byte buffer is misaligned
|
||||
/// let bytes = [1u8, 2, 3, 4, 5, 6, 7, 8];
|
||||
/// let parse_error = RefMaker::<_, Data>::new(&bytes[1..5]).parse()
|
||||
/// .expect_err("Should error");
|
||||
/// assert_eq!(parse_error.to_string(), "Parser error!");
|
||||
/// ```
|
||||
pub fn parse(self) -> anyhow::Result<Ref<B, T>> {
|
||||
self.ensure_fit()?;
|
||||
Ref::<B, T>::new(self.buf).context("Parser error!")
|
||||
}
|
||||
|
||||
/// Splits the buffer into a RefMaker containing the first `target_size` bytes and the remaining tail
|
||||
/// Splits the internal buffer into a `RefMaker` containing a buffer with
|
||||
/// exactly `size_of::<T>()` bytes and the remaining tail of the previous
|
||||
/// internal buffer.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the buffer is undersized.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use rosenpass_util::zerocopy::RefMaker;
|
||||
/// let bytes: &[u8] = &[1,2,3,4,5,6,7,8];
|
||||
/// let (prefix_rm, tail) = RefMaker::<_, u32>::new(bytes).from_prefix_with_tail().unwrap();
|
||||
/// assert_eq!(prefix_rm.bytes(), &[1,2,3,4]);
|
||||
/// assert_eq!(tail, &[5,6,7,8]);
|
||||
/// ```
|
||||
pub fn from_prefix_with_tail(self) -> anyhow::Result<(Self, B)> {
|
||||
self.ensure_fit()?;
|
||||
let (head, tail) = self.buf.split_at(Self::target_size());
|
||||
Ok((Self::new(head), tail))
|
||||
}
|
||||
|
||||
/// Splits the buffer into two RefMakers, with the first containing the first `target_size` bytes
|
||||
/// Splits the buffer into two `RefMaker`s, with the first containing the
|
||||
/// first `size_of::<T>()` bytes and the second containing the remaining
|
||||
/// tail buffer.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the buffer is undersized.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use rosenpass_util::zerocopy::RefMaker;
|
||||
/// let bytes: &[u8] = &[1,2,3,4,5,6,7,8,9,10];
|
||||
/// let (prefix_rm, tail) = RefMaker::<_, u32>::new(bytes).split_prefix().unwrap();
|
||||
/// assert_eq!(prefix_rm.bytes(), &[1,2,3,4]);
|
||||
/// assert_eq!(tail.bytes(), &[5,6,7,8,9,10]);
|
||||
/// ```
|
||||
pub fn split_prefix(self) -> anyhow::Result<(Self, Self)> {
|
||||
self.ensure_fit()?;
|
||||
let (head, tail) = self.buf.split_at(Self::target_size());
|
||||
Ok((Self::new(head), Self::new(tail)))
|
||||
}
|
||||
|
||||
/// Returns a RefMaker containing only the first `target_size` bytes
|
||||
/// Returns a `RefMaker` containing only the first `size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the buffer is undersized.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use rosenpass_util::zerocopy::RefMaker;
|
||||
/// let bytes: &[u8] = &[1,2,3,4,5,6,7,8,9,10];
|
||||
/// let prefix_rm = RefMaker::<_, u32>::new(bytes).from_prefix().unwrap();
|
||||
/// assert_eq!(prefix_rm.bytes(), &[1,2,3,4]);
|
||||
/// ```
|
||||
pub fn from_prefix(self) -> anyhow::Result<Self> {
|
||||
Ok(Self::from_prefix_with_tail(self)?.0)
|
||||
}
|
||||
|
||||
/// Splits the buffer into a RefMaker containing the last `target_size` bytes and the preceding head
|
||||
/// Splits the buffer into a `RefMaker` containing the last `size_of::<T>()`
|
||||
/// bytes as [RefMaker] and the preceding bytes as a buffer.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the buffer is undersized.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use rosenpass_util::zerocopy::RefMaker;
|
||||
/// let bytes: &[u8] = &[1,2,3,4,5,6,7,8,9,10];
|
||||
/// let (suffix_rm, head) = RefMaker::<_, u32>::new(bytes).from_suffix_with_head().unwrap();
|
||||
/// assert_eq!(suffix_rm.bytes(), &[7,8,9,10]);
|
||||
/// assert_eq!(head, &[1,2,3,4,5,6]);
|
||||
/// ```
|
||||
pub fn from_suffix_with_head(self) -> anyhow::Result<(Self, B)> {
|
||||
self.ensure_fit()?;
|
||||
let point = self.bytes().len() - Self::target_size();
|
||||
@@ -76,7 +208,22 @@ impl<B: ByteSlice, T> RefMaker<B, T> {
|
||||
Ok((Self::new(tail), head))
|
||||
}
|
||||
|
||||
/// Splits the buffer into two RefMakers, with the second containing the last `target_size` bytes
|
||||
/// Splits the buffer into two `RefMaker`s, with the second containing the
|
||||
/// last `size_of::<T>()` bytes, and the first containing the remaining
|
||||
/// preceding bytes.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the buffer is undersized.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use rosenpass_util::zerocopy::RefMaker;
|
||||
/// let bytes: &[u8] = &[1,2,3,4,5,6,7,8,9,10];
|
||||
/// let (head, tail) = RefMaker::<_, u32>::new(bytes).split_suffix().unwrap();
|
||||
/// assert_eq!(head.bytes(), &[1,2,3,4,5,6]);
|
||||
/// assert_eq!(tail.bytes(), &[7,8,9,10]);
|
||||
/// ```
|
||||
pub fn split_suffix(self) -> anyhow::Result<(Self, Self)> {
|
||||
self.ensure_fit()?;
|
||||
let point = self.bytes().len() - Self::target_size();
|
||||
@@ -84,17 +231,46 @@ impl<B: ByteSlice, T> RefMaker<B, T> {
|
||||
Ok((Self::new(head), Self::new(tail)))
|
||||
}
|
||||
|
||||
/// Returns a RefMaker containing only the last `target_size` bytes
|
||||
/// Returns a `RefMaker` containing only the last `target_size()` bytes.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the buffer is undersized.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use rosenpass_util::zerocopy::RefMaker;
|
||||
/// let bytes: &[u8] = &[1,2,3,4,5,6,7,8,9,10];
|
||||
/// let suffix_rm = RefMaker::<_, u32>::new(bytes).from_suffix().unwrap();
|
||||
/// assert_eq!(suffix_rm.bytes(), &[7,8,9,10]);
|
||||
/// ```
|
||||
pub fn from_suffix(self) -> anyhow::Result<Self> {
|
||||
Ok(Self::from_suffix_with_head(self)?.0)
|
||||
}
|
||||
|
||||
/// Returns a reference to the underlying bytes
|
||||
/// Returns a reference to the underlying bytes.
|
||||
pub fn bytes(&self) -> &[u8] {
|
||||
self.buf().deref()
|
||||
}
|
||||
|
||||
/// Ensures the buffer is large enough to hold type T
|
||||
/// Ensures that the buffer is large enough to hold a `T`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the buffer is undersized.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use rosenpass_util::zerocopy::RefMaker;
|
||||
/// let bytes: &[u8] = &[1,2,3,4,5,6,7,8,9,10];
|
||||
/// let rm = RefMaker::<_, u32>::new(bytes);
|
||||
/// rm.ensure_fit().unwrap();
|
||||
///
|
||||
/// let bytes: &[u8] = &[1,2,3];
|
||||
/// let rm = RefMaker::<_, u32>::new(bytes);
|
||||
/// assert!(rm.ensure_fit().is_err());
|
||||
/// ```
|
||||
pub fn ensure_fit(&self) -> anyhow::Result<()> {
|
||||
let have = self.bytes().len();
|
||||
let need = Self::target_size();
|
||||
@@ -107,12 +283,30 @@ impl<B: ByteSlice, T> RefMaker<B, T> {
|
||||
}
|
||||
|
||||
impl<B: ByteSliceMut, T> RefMaker<B, T> {
|
||||
/// Creates a zeroed reference of type T from the buffer
|
||||
/// Creates a zeroized reference of type `T` from the buffer.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the buffer is undersized.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use zerocopy::{AsBytes, FromBytes, FromZeroes, Ref}; ///
|
||||
/// # use rosenpass_util::zerocopy::RefMaker;
|
||||
/// #[derive(FromBytes, FromZeroes, AsBytes)]
|
||||
/// #[repr(C)]
|
||||
/// struct Data([u8; 4]);
|
||||
///
|
||||
/// let mut bytes = [0xFF; 4];
|
||||
/// let data_ref: Ref<&mut [u8], Data> = RefMaker::<_, Data>::new(&mut bytes[..]).make_zeroized().unwrap();
|
||||
/// assert_eq!(data_ref.0, [0,0,0,0]);
|
||||
/// ```
|
||||
pub fn make_zeroized(self) -> anyhow::Result<Ref<B, T>> {
|
||||
self.zeroized().parse()
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the underlying bytes
|
||||
/// Returns a mutable reference to the underlying bytes.
|
||||
pub fn bytes_mut(&mut self) -> &mut [u8] {
|
||||
self.buf_mut().deref_mut()
|
||||
}
|
||||
|
||||
@@ -1,14 +1,64 @@
|
||||
//! Extension traits for converting `Ref<B, T>` into references backed by
|
||||
//! standard slices.
|
||||
|
||||
use zerocopy::{ByteSlice, ByteSliceMut, Ref};
|
||||
|
||||
/// A trait for converting a `Ref<B, T>` into a `Ref<&[u8], T>`.
|
||||
///
|
||||
/// This can be useful when you need a reference that is tied to a slice rather
|
||||
/// than the original buffer type `B`.
|
||||
///
|
||||
/// Note: This trait is implemented to [`Ref`] of byte slices (`&[u8]`).
|
||||
pub trait ZerocopyEmancipateExt<B, T> {
|
||||
/// Converts this reference into a reference backed by a byte slice.
|
||||
/// Converts this reference into a reference backed by a plain byte slice.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use std::ops::Deref;
|
||||
/// # use zerocopy::{AsBytes, ByteSlice, FromBytes, FromZeroes, Ref};
|
||||
/// # use rosenpass_util::zerocopy::ZerocopyEmancipateExt;
|
||||
/// #[derive(FromBytes, FromZeroes, AsBytes)]
|
||||
/// #[repr(C)]
|
||||
/// struct Data(u32);
|
||||
/// #[repr(align(4))]
|
||||
/// struct AlignedBuf([u8; 4]);
|
||||
/// let bytes = AlignedBuf([0xAA, 0xBB, 0xCC, 0xDD]);
|
||||
/// let r = Ref::<&[u8], Data>::new(&bytes.0).unwrap();
|
||||
/// let emancipated: Ref<&[u8], Data> = r.emancipate(); // same data, but guaranteed &[u8] backing
|
||||
/// assert_eq!(emancipated.0, 0xDDCCBBAA);
|
||||
/// ```
|
||||
fn emancipate(&self) -> Ref<&[u8], T>;
|
||||
}
|
||||
|
||||
/// A trait for converting a `Ref<B, T>` into a mutable `Ref<&mut [u8], T>`.
|
||||
///
|
||||
/// Similar to [`ZerocopyEmancipateExt`], but for mutable references.
|
||||
///
|
||||
/// Note: this trait is implemented to [`Ref`] of mutable byte
|
||||
/// slices (`&mut [u8]`).
|
||||
pub trait ZerocopyEmancipateMutExt<B, T> {
|
||||
/// Converts this reference into a mutable reference backed by a byte slice.
|
||||
/// Converts this reference into a mutable reference backed by a plain
|
||||
/// mutable byte slice.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use zerocopy::{AsBytes, FromBytes, FromZeroes, Ref};
|
||||
/// # use rosenpass_util::zerocopy::{ZerocopyEmancipateMutExt};
|
||||
/// #[derive(FromBytes, FromZeroes, AsBytes)]
|
||||
/// #[repr(C)]
|
||||
/// struct Data(u32);
|
||||
/// #[repr(align(4))]
|
||||
/// struct AlignedBuf([u8; 4]);
|
||||
/// let mut bytes = AlignedBuf([0xAA, 0xBB, 0xCC, 0xDD]);
|
||||
/// let mut r = Ref::<&mut [u8], Data>::new(&mut bytes.0).unwrap();
|
||||
/// let mut emancipated: Ref<&mut [u8], Data> = r.emancipate_mut(); // same data, but guaranteed &[u8] backing
|
||||
/// assert_eq!(emancipated.0, 0xDDCCBBAA);
|
||||
/// emancipated.0 = 0x33221100;
|
||||
/// drop(emancipated);
|
||||
/// assert_eq!(bytes.0, [0x00, 0x11, 0x22, 0x33]);
|
||||
/// ```
|
||||
fn emancipate_mut(&mut self) -> Ref<&mut [u8], T>;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +1,113 @@
|
||||
//! Extension traits for parsing slices into [`zerocopy::Ref`] values using the
|
||||
//! [`RefMaker`] abstraction.
|
||||
|
||||
use zerocopy::{ByteSlice, ByteSliceMut, Ref};
|
||||
|
||||
use super::RefMaker;
|
||||
|
||||
/// Extension trait for zero-copy slice operations.
|
||||
/// Extension trait for performing zero-copy parsing operations on byte slices.
|
||||
///
|
||||
/// This trait adds methods for creating [`Ref`] references from
|
||||
/// slices by using the [`RefMaker`] type internally.
|
||||
pub trait ZerocopySliceExt: Sized + ByteSlice {
|
||||
/// Creates a new `RefMaker` for the given slice.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use zerocopy::{AsBytes, FromBytes, FromZeroes};
|
||||
/// # use rosenpass_util::zerocopy::{RefMaker, ZerocopySliceExt};
|
||||
///
|
||||
/// #[derive(FromBytes, FromZeroes, AsBytes)]
|
||||
/// #[repr(C)]
|
||||
/// struct Data(u32);
|
||||
///
|
||||
/// let rm: RefMaker<&[u8], Data> = [3,0,0,0].zk_ref_maker();
|
||||
/// assert_eq!(rm.bytes(), &[3,0,0,0]);
|
||||
/// assert_eq!(rm.parse().unwrap().0, 3);
|
||||
/// ```
|
||||
fn zk_ref_maker<T>(self) -> RefMaker<Self, T> {
|
||||
RefMaker::<Self, T>::new(self)
|
||||
}
|
||||
|
||||
/// Parses the slice into a zero-copy reference.
|
||||
/// Parses the given slice into a zero-copy reference of the given type `T`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the slice is too small.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use zerocopy::{AsBytes, FromBytes, FromZeroes};
|
||||
/// # use rosenpass_util::zerocopy::ZerocopySliceExt;
|
||||
///
|
||||
/// #[derive(FromBytes, FromZeroes, AsBytes)]
|
||||
/// #[repr(C)]
|
||||
/// struct Data(u16, u16);
|
||||
/// #[repr(align(4))]
|
||||
/// struct AlignedBuf([u8; 4]);
|
||||
/// let bytes = AlignedBuf([0x01,0x02,0x03,0x04]);
|
||||
/// let data_ref = bytes.0.zk_parse::<Data>().unwrap();
|
||||
/// assert_eq!(data_ref.0, 0x0201);
|
||||
/// assert_eq!(data_ref.1, 0x0403);
|
||||
/// ```
|
||||
fn zk_parse<T>(self) -> anyhow::Result<Ref<Self, T>> {
|
||||
self.zk_ref_maker().parse()
|
||||
}
|
||||
|
||||
/// Parses a prefix of the slice into a zero-copy reference.
|
||||
///
|
||||
/// Uses only the first [`std::mem::size_of::<T>()`] bytes of `T`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the slice is too small.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use zerocopy::{AsBytes, FromBytes, FromZeroes};
|
||||
/// # use rosenpass_util::zerocopy::ZerocopySliceExt;
|
||||
/// #[derive(FromBytes, FromZeroes, AsBytes)]
|
||||
/// #[repr(C)]
|
||||
/// struct Header(u32);
|
||||
/// #[repr(align(4))]
|
||||
/// struct AlignedBuf([u8; 8]);
|
||||
/// let bytes = AlignedBuf([0xAA, 0xBB, 0xCC, 0xDD,
|
||||
/// 0x00, 0x10, 0x20, 0x30]);
|
||||
///
|
||||
/// let header_ref = bytes.0.zk_parse_prefix::<Header>().unwrap();
|
||||
/// assert_eq!(header_ref.0, 0xDDCCBBAA);
|
||||
/// ```
|
||||
fn zk_parse_prefix<T>(self) -> anyhow::Result<Ref<Self, T>> {
|
||||
self.zk_ref_maker().from_prefix()?.parse()
|
||||
}
|
||||
|
||||
/// Parses a suffix of the slice into a zero-copy reference.
|
||||
///
|
||||
/// Uses only the last [`std::mem::size_of::<T>()`] bytes of `T`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the slice is too small.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use zerocopy::{AsBytes, FromBytes, FromZeroes};
|
||||
/// # use rosenpass_util::zerocopy::ZerocopySliceExt;
|
||||
/// #[derive(FromBytes, FromZeroes, AsBytes)]
|
||||
/// #[repr(C)]
|
||||
/// struct Header(u32);
|
||||
/// #[repr(align(4))]
|
||||
/// struct AlignedBuf([u8; 8]);
|
||||
/// let bytes = AlignedBuf([0xAA, 0xBB, 0xCC, 0xDD,
|
||||
/// 0x00, 0x10, 0x20, 0x30]);
|
||||
///
|
||||
/// let header_ref = bytes.0.zk_parse_suffix::<Header>().unwrap();
|
||||
/// assert_eq!(header_ref.0, 0x30201000);
|
||||
/// ```
|
||||
fn zk_parse_suffix<T>(self) -> anyhow::Result<Ref<Self, T>> {
|
||||
self.zk_ref_maker().from_suffix()?.parse()
|
||||
}
|
||||
@@ -27,19 +115,90 @@ pub trait ZerocopySliceExt: Sized + ByteSlice {
|
||||
|
||||
impl<B: ByteSlice> ZerocopySliceExt for B {}
|
||||
|
||||
/// Extension trait for zero-copy slice operations with mutable slices.
|
||||
/// Extension trait for zero-copy parsing of mutable slices with zeroization
|
||||
/// capabilities.
|
||||
///
|
||||
/// Provides convenience methods to create zero-initialized references.
|
||||
pub trait ZerocopyMutSliceExt: ZerocopySliceExt + Sized + ByteSliceMut {
|
||||
/// Creates a new zeroed reference from the entire slice.
|
||||
/// Creates a new zeroized reference from the entire slice.
|
||||
///
|
||||
/// This zeroizes the slice first, then provides a `Ref`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the slice is too small.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use zerocopy::{AsBytes, FromBytes, FromZeroes};
|
||||
/// # use rosenpass_util::zerocopy::ZerocopyMutSliceExt;
|
||||
/// #[derive(FromBytes, FromZeroes, AsBytes)]
|
||||
/// #[repr(C)]
|
||||
/// struct Data([u8; 4]);
|
||||
/// #[repr(align(4))]
|
||||
/// struct AlignedBuf([u8; 4]);
|
||||
/// let mut bytes = AlignedBuf([0xFF; 4]);
|
||||
/// let data_ref = bytes.0.zk_zeroized::<Data>().unwrap();
|
||||
/// assert_eq!(data_ref.0, [0,0,0,0]);
|
||||
/// assert_eq!(bytes.0, [0, 0, 0, 0]);
|
||||
/// ```
|
||||
fn zk_zeroized<T>(self) -> anyhow::Result<Ref<Self, T>> {
|
||||
self.zk_ref_maker().make_zeroized()
|
||||
}
|
||||
|
||||
/// Creates a new zeroed reference from a prefix of the slice.
|
||||
/// Creates a new zeroized reference from the prefix of the slice.
|
||||
///
|
||||
/// Zeroizes the first `target_size()` bytes of the slice, then returns a
|
||||
/// `Ref`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the slice is too small.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use zerocopy::{AsBytes, FromBytes, FromZeroes};
|
||||
/// # use rosenpass_util::zerocopy::ZerocopyMutSliceExt;
|
||||
/// #[derive(FromBytes, FromZeroes, AsBytes)]
|
||||
/// #[repr(C)]
|
||||
/// struct Data([u8; 4]);
|
||||
/// #[repr(align(4))]
|
||||
/// struct AlignedBuf([u8; 6]);
|
||||
/// let mut bytes = AlignedBuf([0xFF; 6]);
|
||||
/// let data_ref = bytes.0.zk_zeroized_from_prefix::<Data>().unwrap();
|
||||
/// assert_eq!(data_ref.0, [0,0,0,0]);
|
||||
/// assert_eq!(bytes.0, [0, 0, 0, 0, 0xFF, 0xFF]);
|
||||
/// ```
|
||||
fn zk_zeroized_from_prefix<T>(self) -> anyhow::Result<Ref<Self, T>> {
|
||||
self.zk_ref_maker().from_prefix()?.make_zeroized()
|
||||
}
|
||||
|
||||
/// Creates a new zeroed reference from a suffix of the slice.
|
||||
/// Creates a new zeroized reference from the suffix of the slice.
|
||||
///
|
||||
/// Zeroizes the last `target_size()` bytes of the slice, then returns a
|
||||
/// `Ref`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the slice is too small.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use zerocopy::{AsBytes, FromBytes, FromZeroes};
|
||||
/// # use rosenpass_util::zerocopy::ZerocopyMutSliceExt;
|
||||
/// #[derive(FromBytes, FromZeroes, AsBytes)]
|
||||
/// #[repr(C)]
|
||||
/// struct Data([u8; 4]);
|
||||
/// #[repr(align(4))]
|
||||
/// struct AlignedBuf([u8; 6]);
|
||||
/// let mut bytes = AlignedBuf([0xFF; 6]);
|
||||
/// let data_ref = bytes.0.zk_zeroized_from_suffix::<Data>().unwrap();
|
||||
/// assert_eq!(data_ref.0, [0,0,0,0]);
|
||||
/// assert_eq!(bytes.0, [0xFF, 0xFF, 0, 0, 0, 0]);
|
||||
/// ```
|
||||
fn zk_zeroized_from_suffix<T>(self) -> anyhow::Result<Ref<Self, T>> {
|
||||
self.zk_ref_maker().from_suffix()?.make_zeroized()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user