|  | // 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>; |