Skip to main content

tpm2_protocol/macro/
integer.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2// Copyright (c) 2025 Opinsys Oy
3// Copyright (c) 2024-2025 Jarkko Sakkinen
4
5#[doc(hidden)]
6#[macro_export]
7macro_rules! integer {
8    ($name:ident, $raw:ty, $bytes:expr) => {
9        #[derive(Default, Clone, Copy, PartialEq, Eq, Hash)]
10        #[repr(transparent)]
11        pub struct $name([u8; $bytes]);
12
13        impl $name {
14            #[must_use]
15            pub const fn new(value: $raw) -> Self {
16                Self(value.to_be_bytes())
17            }
18
19            #[must_use]
20            pub const fn value(self) -> $raw {
21                <$raw>::from_be_bytes(self.0)
22            }
23
24            pub const fn set(&mut self, value: $raw) {
25                self.0 = value.to_be_bytes();
26            }
27
28            #[must_use]
29            pub const fn as_bytes(&self) -> &[u8; $bytes] {
30                &self.0
31            }
32
33            #[must_use]
34            pub fn as_bytes_mut(&mut self) -> &mut [u8; $bytes] {
35                &mut self.0
36            }
37
38            #[must_use]
39            pub fn to_be_bytes(self) -> [u8; $bytes] {
40                self.0
41            }
42
43            #[must_use]
44            pub const fn from_be_bytes(bytes: [u8; $bytes]) -> Self {
45                Self(bytes)
46            }
47
48            /// Casts a byte slice into a TPM integer wire view.
49            ///
50            /// # Errors
51            ///
52            /// Returns [`UnexpectedEnd`](crate::TpmError::UnexpectedEnd) when
53            /// `buf` is smaller than this integer's wire size.
54            /// Returns [`TrailingData`](crate::TpmError::TrailingData) when
55            /// `buf` is larger than this integer's wire size.
56            pub fn cast(buf: &[u8]) -> $crate::TpmResult<&Self> {
57                Self::validate(buf)?;
58
59                // SAFETY: The validation above guarantees the exact byte length
60                // required by this transparent integer view.
61                Ok(unsafe { Self::cast_unchecked(buf) })
62            }
63
64            /// Validates an exact TPM integer wire view.
65            ///
66            /// # Errors
67            ///
68            /// Returns [`UnexpectedEnd`](crate::TpmError::UnexpectedEnd) when
69            /// `buf` is smaller than this integer's wire size.
70            /// Returns [`TrailingData`](crate::TpmError::TrailingData) when
71            /// `buf` is larger than this integer's wire size.
72            pub fn validate(buf: &[u8]) -> $crate::TpmResult<()> {
73                $crate::TpmWireBytes::<$bytes>::validate(buf)
74            }
75
76            /// Validates that `buf` starts with a TPM integer wire view.
77            ///
78            /// # Errors
79            ///
80            /// Returns [`UnexpectedEnd`](crate::TpmError::UnexpectedEnd) when
81            /// `buf` is smaller than this integer's wire size.
82            pub fn validate_prefix(buf: &[u8]) -> $crate::TpmResult<()> {
83                $crate::TpmWireBytes::<$bytes>::validate_prefix(buf)
84            }
85
86            /// Casts the first bytes in a slice into a TPM integer wire view.
87            ///
88            /// # Errors
89            ///
90            /// Returns [`UnexpectedEnd`](crate::TpmError::UnexpectedEnd) when
91            /// `buf` is smaller than this integer's wire size.
92            pub fn cast_prefix(buf: &[u8]) -> $crate::TpmResult<(&Self, &[u8])> {
93                Self::validate_prefix(buf)?;
94                let (head, tail) = buf.split_at($bytes);
95
96                // SAFETY: The validation above guarantees that `head` has exactly
97                // the byte length required by this transparent integer view.
98                Ok((unsafe { Self::cast_unchecked(head) }, tail))
99            }
100
101            /// Casts a mutable byte slice into a mutable TPM integer wire view.
102            ///
103            /// # Errors
104            ///
105            /// Returns [`UnexpectedEnd`](crate::TpmError::UnexpectedEnd) when
106            /// `buf` is smaller than this integer's wire size.
107            /// Returns [`TrailingData`](crate::TpmError::TrailingData) when
108            /// `buf` is larger than this integer's wire size.
109            pub fn cast_mut(buf: &mut [u8]) -> $crate::TpmResult<&mut Self> {
110                Self::validate(buf)?;
111
112                // SAFETY: The validation above guarantees the exact
113                // byte length required by this transparent integer view.
114                Ok(unsafe { Self::cast_mut_unchecked(buf) })
115            }
116
117            /// Casts the first mutable bytes in a slice into a TPM integer wire view.
118            ///
119            /// # Errors
120            ///
121            /// Returns [`UnexpectedEnd`](crate::TpmError::UnexpectedEnd) when
122            /// `buf` is smaller than this integer's wire size.
123            pub fn cast_prefix_mut(buf: &mut [u8]) -> $crate::TpmResult<(&mut Self, &mut [u8])> {
124                Self::validate_prefix(buf)?;
125                let (head, tail) = buf.split_at_mut($bytes);
126
127                // SAFETY: The validation above guarantees that `head` has exactly
128                // the byte length required by this transparent integer view.
129                Ok((unsafe { Self::cast_mut_unchecked(head) }, tail))
130            }
131
132        }
133
134        $crate::tpm_byte_view!(array $name);
135
136        impl core::fmt::Debug for $name {
137            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
138                f.debug_tuple(stringify!($name)).field(&self.value()).finish()
139            }
140        }
141
142        impl core::cmp::PartialOrd for $name {
143            fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
144                Some(self.cmp(other))
145            }
146        }
147
148        impl core::cmp::Ord for $name {
149            fn cmp(&self, other: &Self) -> core::cmp::Ordering {
150                self.value().cmp(&other.value())
151            }
152        }
153
154        impl From<$raw> for $name {
155            fn from(value: $raw) -> Self {
156                Self::new(value)
157            }
158        }
159
160        impl From<$name> for $raw {
161            fn from(value: $name) -> $raw {
162                value.value()
163            }
164        }
165
166        impl core::fmt::Display for $name {
167            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
168                core::fmt::Display::fmt(&self.value(), f)
169            }
170        }
171
172        impl core::fmt::LowerHex for $name {
173            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
174                core::fmt::LowerHex::fmt(&self.value(), f)
175            }
176        }
177
178        impl core::fmt::UpperHex for $name {
179            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
180                core::fmt::UpperHex::fmt(&self.value(), f)
181            }
182        }
183
184        impl $crate::TpmSized for $name {
185            const SIZE: usize = $bytes;
186            fn len(&self) -> usize {
187                Self::SIZE
188            }
189        }
190
191        impl $crate::TpmMarshal for $name {
192            fn marshal(&self, writer: &mut $crate::TpmWriter) -> $crate::TpmResult<()> {
193                writer.write_bytes(self.as_bytes())
194            }
195        }
196
197        impl $crate::TpmCast for $name {
198            fn cast(buf: &[u8]) -> $crate::TpmResult<&Self> {
199                Self::cast(buf)
200            }
201
202            fn cast_prefix(buf: &[u8]) -> $crate::TpmResult<(&Self, &[u8])> {
203                Self::cast_prefix(buf)
204            }
205
206            unsafe fn cast_unchecked(buf: &[u8]) -> &Self {
207                // SAFETY: The caller upholds the unchecked cast contract for `$name`.
208                unsafe { Self::cast_unchecked(buf) }
209            }
210        }
211
212        impl $crate::TpmCastMut for $name {
213            fn cast_mut(buf: &mut [u8]) -> $crate::TpmResult<&mut Self> {
214                Self::cast_mut(buf)
215            }
216
217            fn cast_prefix_mut(buf: &mut [u8]) -> $crate::TpmResult<(&mut Self, &mut [u8])> {
218                Self::cast_prefix_mut(buf)
219            }
220
221            unsafe fn cast_mut_unchecked(buf: &mut [u8]) -> &mut Self {
222                // SAFETY: The caller upholds the unchecked mutable cast contract for `$name`.
223                unsafe { Self::cast_mut_unchecked(buf) }
224            }
225        }
226
227        impl TryFrom<usize> for $name
228        where
229            $raw: TryFrom<usize>,
230        {
231            type Error = <$raw as TryFrom<usize>>::Error;
232            fn try_from(value: usize) -> Result<Self, Self::Error> {
233                <$raw>::try_from(value).map(Self::new)
234            }
235        }
236    };
237}