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}