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