feat: kick off zerocopy with TpmView trait
Take the first steps towards zero copy architecture and introduce `TpmView`
for encapsulating a slice:
```
pub trait TpmView<'a>: Sized {
fn from_slice(slice: &'a [u8]) -> TpmResult<Self>;
fn as_slice(&self) -> &'a [u8];
}
```
Implement this first for `tpm_integer!` as this overhaul needs to start
from the bottom.
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
diff --git a/src/lib.rs b/src/lib.rs
index eb99dbc..cedd368 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -32,13 +32,14 @@
use crate::data::TpmAlgId;
pub use buffer::TpmBuffer;
+use list::TpmList;
+
use core::{
convert::{From, TryFrom},
fmt,
mem::size_of,
result::Result,
};
-pub use list::TpmList;
tpm_handle! {
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
@@ -184,6 +185,21 @@
}
}
+/// Represents the core trait types for the TPM2 types in the byte stream. This
+/// is early drafting.
+pub trait TpmView<'a>: Sized {
+ /// Creates a new `TpmView` from a slice.
+ ///
+ /// # Errors
+ ///
+ /// `TpmErrorKind::ParseUnderflow` while running out of bytes.
+ /// `TpmErrorKind::ParseCapacity` when a property exceeds specification constants.
+ fn from_slice(slice: &'a [u8]) -> TpmResult<Self>;
+
+ /// Returns the underlying byte slice of the view.
+ fn as_slice(&self) -> &'a [u8];
+}
+
/// Provides two ways to determine the size of an object: a compile-time maximum
/// and a runtime exact size.
pub trait TpmSized {
@@ -245,12 +261,12 @@
<Self as TpmTagged>::Tag: TpmParse + TpmBuild;
}
-tpm_integer!(u8, Unsigned);
-tpm_integer!(i8, Signed);
-tpm_integer!(i32, Signed);
-tpm_integer!(u16, Unsigned);
-tpm_integer!(u32, Unsigned);
-tpm_integer!(u64, Unsigned);
+tpm_integer!(u8, TpmViewU8, Unsigned);
+tpm_integer!(i8, TpmViewI8, Signed);
+tpm_integer!(u16, TpmViewU16, Unsigned);
+tpm_integer!(i32, TpmViewI32, Signed);
+tpm_integer!(u32, TpmViewU32, Unsigned);
+tpm_integer!(u64, TpmViewU64, Unsigned);
/// Builds a TPM2B sized buffer.
///
diff --git a/src/macro/integer.rs b/src/macro/integer.rs
index e1c66f1..cc6bace 100644
--- a/src/macro/integer.rs
+++ b/src/macro/integer.rs
@@ -4,7 +4,60 @@
#[macro_export]
macro_rules! tpm_integer {
- ($ty:ty, $variant:ident) => {
+ ($ty:ty, $view_name:ident, $variant:ident) => {
+ #[derive(Clone, Copy)]
+ pub struct $view_name<'a> {
+ slice: &'a [u8],
+ }
+
+ impl<'a> $view_name<'a> {
+ /// Reads the integer value from the slice.
+ ///
+ /// # Panics
+ ///
+ /// `TpmView::from_slice` provides a guard that the slice length is
+ /// expected to be correct.
+ #[must_use]
+ pub fn get(&self) -> $ty {
+ let array = self.slice.try_into().unwrap();
+ <$ty>::from_be_bytes(array)
+ }
+ }
+
+ impl<'a> $crate::TpmView<'a> for $view_name<'a> {
+ fn from_slice(slice: &'a [u8]) -> TpmResult<Self> {
+ let size = size_of::<$ty>();
+ if slice.len() < size {
+ return Err($crate::TpmErrorKind::ParseUnderflow);
+ }
+ Ok(Self {
+ slice: &slice[..size],
+ })
+ }
+
+ fn as_slice(&self) -> &'a [u8] {
+ self.slice
+ }
+ }
+
+ impl<'a> core::fmt::Debug for $view_name<'a> {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ core::fmt::Debug::fmt(&self.get(), f)
+ }
+ }
+
+ impl<'a> core::fmt::Display for $view_name<'a> {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ core::fmt::Display::fmt(&self.get(), f)
+ }
+ }
+
+ impl<'a> PartialEq<$ty> for $view_name<'a> {
+ fn eq(&self, other: &$ty) -> bool {
+ self.get() == *other
+ }
+ }
+
impl TpmParse for $ty {
fn parse(buf: &[u8]) -> TpmResult<(Self, &[u8])> {
let size = size_of::<$ty>();