| // Copyright 2024 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| // use this file except in compliance with the License. You may obtain a copy of |
| // the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| // License for the specific language governing permissions and limitations under |
| // the License. |
| |
| //! Types and functions to help with memory buffer management. |
| |
| use crate::constants::*; |
| use crate::error::{DpeResult, ErrCode}; |
| use heapless::Vec; |
| use zeroize::ZeroizeOnDrop; |
| |
| /// Creates a byte array wrapper type for the sake of precise typing. |
| #[macro_export] |
| macro_rules! byte_array_wrapper { |
| ($type_name:ident, $len:ident, $desc:expr) => { |
| #[doc = "A byte array wrapper to represent a "] |
| #[doc = $desc] |
| #[doc = "."] |
| #[derive(Clone, Debug, Eq, PartialEq, Hash, ZeroizeOnDrop)] |
| pub struct $type_name([u8; $len]); |
| impl $type_name { |
| #[doc = "Returns the length of the array."] |
| pub fn len(&self) -> usize { |
| self.0.len() |
| } |
| |
| #[doc = "Whether the array is empty."] |
| pub fn is_empty(&self) -> bool { |
| self.0.is_empty() |
| } |
| |
| #[doc = "Borrows the array as a slice."] |
| pub fn as_slice(&self) -> &[u8] { |
| self.0.as_slice() |
| } |
| |
| #[doc = "Mutably borrows the array as a slice."] |
| pub fn as_mut_slice(&mut self) -> &mut [u8] { |
| &mut self.0 |
| } |
| |
| #[doc = "Borrows the array."] |
| pub fn as_array(&self) -> &[u8; $len] { |
| &self.0 |
| } |
| |
| #[doc = "Creates a "] |
| #[doc = stringify!($type_name)] |
| #[doc = " from a slice. Fails if the slice length is not "] |
| #[doc = stringify!($len)] |
| #[doc = "."] |
| pub fn from_slice(s: &[u8]) -> DpeResult<Self> { |
| Self::try_from(s) |
| } |
| |
| #[doc = "Creates a "] |
| #[doc = stringify!($type_name)] |
| #[doc = " from a slice infallibly. If the length of the slice is less than "] |
| #[doc = stringify!($len)] |
| #[doc = ", the remainder of the array is the default value. If the length "] |
| #[doc = "of the slice is more than "] |
| #[doc = stringify!($len)] |
| #[doc = ", only the first "] |
| #[doc = stringify!($len)] |
| #[doc = " bytes are used. This method is infallible."] |
| pub fn from_slice_infallible(value: &[u8]) -> Self { |
| #![allow(clippy::indexing_slicing)] |
| let mut tmp: Self = Default::default(); |
| if value.len() < $len { |
| tmp.0[..value.len()].copy_from_slice(value); |
| } else { |
| tmp.0.copy_from_slice(&value[..$len]); |
| } |
| tmp |
| } |
| |
| #[doc = "Creates a "] |
| #[doc = stringify!($type_name)] |
| #[doc = " from an array."] |
| pub fn from_array(value: &[u8; $len]) -> Self { |
| Self(*value) |
| } |
| } |
| |
| impl Default for $type_name { |
| fn default() -> Self { |
| Self([0; $len]) |
| } |
| } |
| |
| impl TryFrom<&[u8]> for $type_name { |
| type Error = $crate::error::ErrCode; |
| |
| fn try_from(value: &[u8]) -> Result<Self, Self::Error> { |
| value.try_into().map(Self).map_err(|_| { |
| log::error!("Invalid length for fixed length value: {}", $desc); |
| $crate::error::ErrCode::InvalidArgument |
| }) |
| } |
| } |
| |
| impl From<[u8; $len]> for $type_name { |
| fn from(value: [u8; $len]) -> Self { |
| Self(value) |
| } |
| } |
| }; |
| } |
| |
| /// Wraps a [heapless::Vec] of bytes and provides various convenience methods |
| /// that are useful when processing DPE messages. The inner `vec` is also |
| /// accessible directly. |
| #[derive(Clone, Debug, Default, Eq, PartialEq, Hash, ZeroizeOnDrop)] |
| pub struct SizedMessage<const S: usize> { |
| /// The wrapped Vec. |
| pub vec: Vec<u8, S>, |
| } |
| |
| impl<const S: usize> SizedMessage<S> { |
| /// Creates a new, empty instance. |
| /// |
| /// # Example |
| /// |
| /// ```rust |
| /// type MyMessage = dpe_rs::memory::SizedMessage<200>; |
| /// |
| /// assert_eq!(MyMessage::new().len(), 0); |
| /// ``` |
| pub fn new() -> Self { |
| Default::default() |
| } |
| |
| /// Creates a new instance from a slice. |
| /// |
| /// # Errors |
| /// |
| /// If `value` exceeds the available capacity, returns an OutOfMemory error. |
| /// |
| /// # Example |
| /// |
| /// ```rust |
| /// type MyMessage = dpe_rs::memory::SizedMessage<200>; |
| /// |
| /// assert_eq!(MyMessage::from_slice(&[0; 12]).unwrap().as_slice(), &[0; 12]); |
| /// ``` |
| pub fn from_slice(value: &[u8]) -> DpeResult<Self> { |
| Ok(Self { |
| vec: Vec::from_slice(value).map_err(|_| ErrCode::OutOfMemory)?, |
| }) |
| } |
| |
| /// Clones `slice`, replacing any existing content. |
| /// |
| /// # Errors |
| /// |
| /// If `slice` exceeds the available capacity, returns an OutOfMemory error. |
| /// |
| /// # Example |
| /// |
| /// ```rust |
| /// type MyMessage = dpe_rs::memory::SizedMessage<200>; |
| /// |
| /// let mut m = MyMessage::from_slice(&[0; 12]).unwrap(); |
| /// m.clone_from_slice(&[1; 3]).unwrap(); |
| /// assert_eq!(m.as_slice(), &[1; 3]); |
| /// ``` |
| pub fn clone_from_slice(&mut self, slice: &[u8]) -> DpeResult<()> { |
| self.clear(); |
| self.vec.extend_from_slice(slice).map_err(|_| ErrCode::OutOfMemory) |
| } |
| |
| /// Borrows the inner byte array. |
| pub fn as_slice(&self) -> &[u8] { |
| self.vec.as_slice() |
| } |
| |
| /// Mutably borrows the inner byte array after resizing. This is useful when |
| /// using the type as an output buffer. |
| /// |
| /// # Errors |
| /// |
| /// If `size` exceeds the available capacity, returns an OutOfMemory error. |
| /// |
| /// # Example |
| /// |
| /// ```rust |
| /// use rand_core::{RngCore, SeedableRng}; |
| /// |
| /// type MyMessage = dpe_rs::memory::SizedMessage<200>; |
| /// |
| /// let mut buffer = MyMessage::new(); |
| /// <rand_chacha::ChaCha12Rng as SeedableRng>::seed_from_u64(0) |
| /// .fill_bytes(buffer.as_mut_sized(100).unwrap()); |
| /// assert_eq!(buffer.len(), 100); |
| /// ``` |
| pub fn as_mut_sized(&mut self, size: usize) -> DpeResult<&mut [u8]> { |
| self.vec.resize_default(size).map_err(|_| ErrCode::OutOfMemory)?; |
| Ok(self.vec.as_mut()) |
| } |
| |
| /// Returns the length of the inner vec. |
| pub fn len(&self) -> usize { |
| self.vec.len() |
| } |
| |
| /// Whether the inner vec is empty. |
| pub fn is_empty(&self) -> bool { |
| self.vec.is_empty() |
| } |
| |
| /// Clears the inner vec. |
| pub fn clear(&mut self) { |
| self.vec.clear() |
| } |
| |
| /// Removes the first `prefix_size` bytes from the message. This carries the |
| /// cost of moving the remaining bytes to the front of the buffer. |
| /// |
| /// # Errors |
| /// |
| /// If `prefix_size` is larger than the current length, returns an |
| /// InternalError error. |
| /// |
| /// # Example |
| /// |
| /// ```rust |
| /// type MyMessage = dpe_rs::memory::SizedMessage<200>; |
| /// |
| /// let mut m = MyMessage::from_slice("prefixdata".as_bytes()).unwrap(); |
| /// m.remove_prefix(6).unwrap(); |
| /// assert_eq!(m.as_slice(), "data".as_bytes()); |
| /// ``` |
| pub fn remove_prefix(&mut self, prefix_size: usize) -> DpeResult<()> { |
| if prefix_size > self.len() { |
| return Err(ErrCode::InternalError); |
| } |
| if prefix_size == self.len() { |
| self.clear(); |
| } else if prefix_size > 0 { |
| let slice: &mut [u8] = self.vec.as_mut(); |
| slice.copy_within(prefix_size.., 0); |
| self.vec.truncate(self.len() - prefix_size); |
| } |
| Ok(()) |
| } |
| |
| /// Inserts `prefix` at the start of the message. This carries the cost of |
| /// moving the existing bytes to make room for the prefix. |
| /// |
| /// # Errors |
| /// |
| /// If inserting `prefix` overflows the available capacity, returns an |
| /// OutOfMemory error. |
| /// |
| /// # Example |
| /// |
| /// ```rust |
| /// type MyMessage = dpe_rs::memory::SizedMessage<200>; |
| /// |
| /// let mut m = MyMessage::from_slice("data".as_bytes()).unwrap(); |
| /// m.insert_prefix("prefix".as_bytes()).unwrap(); |
| /// assert_eq!(m.as_slice(), "prefixdata".as_bytes()); |
| /// ``` |
| pub fn insert_prefix(&mut self, prefix: &[u8]) -> DpeResult<()> { |
| let old_len = self.len(); |
| self.vec |
| .resize_default(self.len() + prefix.len()) |
| .map_err(|_| ErrCode::OutOfMemory)?; |
| let slice: &mut [u8] = self.vec.as_mut(); |
| slice.copy_within(0..old_len, prefix.len()); |
| slice |
| .get_mut(..prefix.len()) |
| .ok_or(ErrCode::InternalError)? |
| .copy_from_slice(prefix); |
| Ok(()) |
| } |
| } |
| |
| /// Represents a DPE command/response message. This type is large and should not |
| /// be instantiated unnecessarily. |
| pub type Message = SizedMessage<MAX_MESSAGE_SIZE>; |