From 9336794e4dfe5c61bb3cb745ac200bb369ef800e Mon Sep 17 00:00:00 2001 From: Amin Faez Date: Sat, 14 Dec 2024 03:00:27 +0100 Subject: [PATCH 1/2] docs(util): add docs and examples to the zerocopy module --- util/src/zerocopy/mod.rs | 16 ++ util/src/zerocopy/ref_maker.rs | 233 ++++++++++++++++++++++-- util/src/zerocopy/zerocopy_ref_ext.rs | 55 +++++- util/src/zerocopy/zerocopy_slice_ext.rs | 171 ++++++++++++++++- 4 files changed, 448 insertions(+), 27 deletions(-) diff --git a/util/src/zerocopy/mod.rs b/util/src/zerocopy/mod.rs index 6856bea..27ed318 100644 --- a/util/src/zerocopy/mod.rs +++ b/util/src/zerocopy/mod.rs @@ -1,3 +1,19 @@ +//! This module provides utilities for working with zero-copy references +//! and slices. +//! +//! It offers the following primary abstractions and traits: +//! +//! - [`RefMaker`]: A helper structure for safely creating +//! [`Ref`](zerocopy::Ref) references from byte slices. +//! - [`ZerocopyEmancipateExt`]: A trait to convert `Ref` into a borrowed +//! `Ref<&[u8], T>`. +//! - [`ZerocopyEmancipateMutExt`]: A trait to convert `Ref` into a +//! borrowed mutable `Ref<&mut [u8], T>`. +//! - [`ZerocopySliceExt`]: Extension methods for parsing byte slices into +//! zero-copy references. +//! - [`ZerocopyMutSliceExt`]: Extension methods for parsing and zeroizing byte +//! slices into zero-copy references. + mod ref_maker; mod zerocopy_ref_ext; mod zerocopy_slice_ext; diff --git a/util/src/zerocopy/ref_maker.rs b/util/src/zerocopy/ref_maker.rs index 1ba24e8..3fcb0ed 100644 --- a/util/src/zerocopy/ref_maker.rs +++ b/util/src/zerocopy/ref_maker.rs @@ -1,74 +1,207 @@ -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 { buf: B, _phantom_t: PhantomData, } impl RefMaker { - /// 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] of `T`. pub const fn target_size() -> usize { std::mem::size_of::() } - /// 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 RefMaker { - /// Parses the buffer into a reference of type T + /// Parses the buffer into a [`zerocopy::Ref`]. + /// + /// This will fail if the buffer is smaller than `size_of::`. + /// + /// # 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!(format!("{:?}", parse_error), + /// "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!(format!("{:?}", parse_error), + /// "Parser error!"); + /// ``` pub fn parse(self) -> anyhow::Result> { self.ensure_fit()?; Ref::::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::()` 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::()` 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::()` 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 { 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::()` + /// 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 +209,22 @@ impl RefMaker { 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::()` 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 +232,46 @@ impl RefMaker { 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 { 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 +284,30 @@ impl RefMaker { } impl RefMaker { - /// 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> { 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() } diff --git a/util/src/zerocopy/zerocopy_ref_ext.rs b/util/src/zerocopy/zerocopy_ref_ext.rs index f8eecc7..aa50b11 100644 --- a/util/src/zerocopy/zerocopy_ref_ext.rs +++ b/util/src/zerocopy/zerocopy_ref_ext.rs @@ -1,14 +1,65 @@ +//! Extension traits for converting `Ref` into references backed by +//! standard slices. + use zerocopy::{ByteSlice, ByteSliceMut, Ref}; /// A trait for converting a `Ref` 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](zerocopy::Ref) of byte slices +/// (`&[u8]`). pub trait ZerocopyEmancipateExt { - /// 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` into a mutable `Ref<&mut [u8], T>`. +/// +/// Similar to [`ZerocopyEmancipateExt`], but for mutable references. +/// +/// Note: this trait is implemented to [Ref](zerocopy::Ref) of mutable byte +/// slices (`&mut [u8]`). pub trait ZerocopyEmancipateMutExt { - /// 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>; } diff --git a/util/src/zerocopy/zerocopy_slice_ext.rs b/util/src/zerocopy/zerocopy_slice_ext.rs index ef068d5..c6ab1ca 100644 --- a/util/src/zerocopy/zerocopy_slice_ext.rs +++ b/util/src/zerocopy/zerocopy_slice_ext.rs @@ -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`](zerocopy::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(self) -> RefMaker { RefMaker::::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::().unwrap(); + /// assert_eq!(data_ref.0, 0x0201); + /// assert_eq!(data_ref.1, 0x0403); + /// ``` fn zk_parse(self) -> anyhow::Result> { self.zk_ref_maker().parse() } /// Parses a prefix of the slice into a zero-copy reference. + /// + /// Uses only the first [std::mem::size_of::()] 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::
().unwrap(); + /// assert_eq!(header_ref.0, 0xDDCCBBAA); + /// ``` fn zk_parse_prefix(self) -> anyhow::Result> { 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::()] 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::
().unwrap(); + /// assert_eq!(header_ref.0, 0x30201000); + /// ``` fn zk_parse_suffix(self) -> anyhow::Result> { self.zk_ref_maker().from_suffix()?.parse() } @@ -27,19 +115,90 @@ pub trait ZerocopySliceExt: Sized + ByteSlice { impl 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::().unwrap(); + /// assert_eq!(data_ref.0, [0,0,0,0]); + /// assert_eq!(bytes.0, [0, 0, 0, 0]); + /// ``` fn zk_zeroized(self) -> anyhow::Result> { 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::().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(self) -> anyhow::Result> { 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::().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(self) -> anyhow::Result> { self.zk_ref_maker().from_suffix()?.make_zeroized() } From ef4f550abcc29c957ed3dc2699d84a7e01ff0ce4 Mon Sep 17 00:00:00 2001 From: Amin Faez Date: Sun, 15 Dec 2024 13:05:55 +0100 Subject: [PATCH 2/2] docs(util): fix doc reference in the zerocopy module --- util/src/zerocopy/mod.rs | 21 +++++++++++---------- util/src/zerocopy/ref_maker.rs | 7 +++---- util/src/zerocopy/zerocopy_ref_ext.rs | 5 ++--- util/src/zerocopy/zerocopy_slice_ext.rs | 6 +++--- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/util/src/zerocopy/mod.rs b/util/src/zerocopy/mod.rs index 27ed318..9711fe6 100644 --- a/util/src/zerocopy/mod.rs +++ b/util/src/zerocopy/mod.rs @@ -3,16 +3,17 @@ //! //! It offers the following primary abstractions and traits: //! -//! - [`RefMaker`]: A helper structure for safely creating -//! [`Ref`](zerocopy::Ref) references from byte slices. -//! - [`ZerocopyEmancipateExt`]: A trait to convert `Ref` into a borrowed -//! `Ref<&[u8], T>`. -//! - [`ZerocopyEmancipateMutExt`]: A trait to convert `Ref` into a -//! borrowed mutable `Ref<&mut [u8], T>`. -//! - [`ZerocopySliceExt`]: Extension methods for parsing byte slices into -//! zero-copy references. -//! - [`ZerocopyMutSliceExt`]: Extension methods for parsing and zeroizing byte -//! slices into zero-copy references. +//! - [`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` into a borrowed `Ref<&[u8], T>`. +//! - [`ZerocopyEmancipateMutExt`](crate::zerocopy::ZerocopyEmancipateMutExt): +//! A trait to convert `Ref` 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; diff --git a/util/src/zerocopy/ref_maker.rs b/util/src/zerocopy/ref_maker.rs index 3fcb0ed..f0c46ed 100644 --- a/util/src/zerocopy/ref_maker.rs +++ b/util/src/zerocopy/ref_maker.rs @@ -61,7 +61,7 @@ impl RefMaker { } /// Returns the size in bytes required by the target type `T`. - /// This is currently defined as [std::mem::size_of] of `T`. + /// This is currently defined as [`std::mem::size_of::`] of `T`. pub const fn target_size() -> usize { std::mem::size_of::() } @@ -109,15 +109,14 @@ impl RefMaker { /// let bytes: &[u8] = &[0x01, 0x02, 0x03]; /// let parse_error = RefMaker::<_, Data>::new(bytes).parse() /// .expect_err("Should error"); - /// assert_eq!(format!("{:?}", parse_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!(format!("{:?}", parse_error), - /// "Parser error!"); + /// assert_eq!(parse_error.to_string(), "Parser error!"); /// ``` pub fn parse(self) -> anyhow::Result> { self.ensure_fit()?; diff --git a/util/src/zerocopy/zerocopy_ref_ext.rs b/util/src/zerocopy/zerocopy_ref_ext.rs index aa50b11..fa3c1b3 100644 --- a/util/src/zerocopy/zerocopy_ref_ext.rs +++ b/util/src/zerocopy/zerocopy_ref_ext.rs @@ -8,8 +8,7 @@ use zerocopy::{ByteSlice, ByteSliceMut, Ref}; /// 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](zerocopy::Ref) of byte slices -/// (`&[u8]`). +/// Note: This trait is implemented to [`Ref`] of byte slices (`&[u8]`). pub trait ZerocopyEmancipateExt { /// Converts this reference into a reference backed by a plain byte slice. /// @@ -36,7 +35,7 @@ pub trait ZerocopyEmancipateExt { /// /// Similar to [`ZerocopyEmancipateExt`], but for mutable references. /// -/// Note: this trait is implemented to [Ref](zerocopy::Ref) of mutable byte +/// Note: this trait is implemented to [`Ref`] of mutable byte /// slices (`&mut [u8]`). pub trait ZerocopyEmancipateMutExt { /// Converts this reference into a mutable reference backed by a plain diff --git a/util/src/zerocopy/zerocopy_slice_ext.rs b/util/src/zerocopy/zerocopy_slice_ext.rs index c6ab1ca..3dd5393 100644 --- a/util/src/zerocopy/zerocopy_slice_ext.rs +++ b/util/src/zerocopy/zerocopy_slice_ext.rs @@ -7,7 +7,7 @@ use super::RefMaker; /// Extension trait for performing zero-copy parsing operations on byte slices. /// -/// This trait adds methods for creating [`Ref`](zerocopy::Ref) references from +/// 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. @@ -58,7 +58,7 @@ pub trait ZerocopySliceExt: Sized + ByteSlice { /// Parses a prefix of the slice into a zero-copy reference. /// - /// Uses only the first [std::mem::size_of::()] bytes of `T`. + /// Uses only the first [`std::mem::size_of::()`] bytes of `T`. /// /// # Errors /// @@ -86,7 +86,7 @@ pub trait ZerocopySliceExt: Sized + ByteSlice { /// Parses a suffix of the slice into a zero-copy reference. /// - /// Uses only the last [std::mem::size_of::()] bytes of `T`. + /// Uses only the last [`std::mem::size_of::()`] bytes of `T`. /// /// # Errors ///