blob: 905b136feacdbee62563a27379924da7439c33a0 [file] [log] [blame]
// 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>;