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