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}