1use std::fmt::{Debug, Formatter};
2
3use bytemuck::{Pod, Zeroable};
5
6#[macro_export]
12macro_rules! impl_int_conversion {
13 ($P:ty, $I:ty) => {
14 impl From<$I> for $P {
15 fn from(n: $I) -> Self {
16 Self(n.to_le_bytes())
17 }
18 }
19 impl From<&$I> for $P {
20 fn from(n: &$I) -> Self {
21 Self(n.to_le_bytes())
22 }
23 }
24 impl From<$P> for $I {
25 fn from(pod: $P) -> Self {
26 Self::from_le_bytes(pod.0)
27 }
28 }
29 impl From<&$P> for $I {
30 fn from(pod: &$P) -> Self {
31 Self::from_le_bytes(pod.0)
32 }
33 }
34 };
35}
36
37#[derive(Clone, Copy, Default, PartialEq, Pod, Zeroable, Eq)]
38#[repr(transparent)]
39pub struct PodU16([u8; 2]);
40impl_int_conversion!(PodU16, u16);
41
42impl Debug for PodU16 {
43 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
44 let v: u16 = u16::from(self);
45 f.debug_tuple("PodU16").field(&v).finish()
46 }
47}
48
49#[derive(Clone, Copy, Default, PartialEq, Pod, Zeroable, Eq)]
50#[repr(transparent)]
51pub struct PodU32([u8; 4]);
52impl_int_conversion!(PodU32, u32);
53
54impl Debug for PodU32 {
55 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
56 let v: u32 = u32::from(self);
57 f.debug_tuple("PodU32").field(&v).finish()
58 }
59}
60
61#[derive(Clone, Copy, Default, PartialEq, Pod, Zeroable, Eq)]
62#[repr(transparent)]
63pub struct PodU64([u8; 8]);
64impl_int_conversion!(PodU64, u64);
65
66impl Debug for PodU64 {
67 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
68 let v: u64 = u64::from(self);
69 f.debug_tuple("PodU64").field(&v).finish()
70 }
71}
72
73#[derive(Clone, Copy, Default, PartialEq, Pod, Zeroable, Eq)]
74#[repr(transparent)]
75pub struct PodU128([u8; 16]);
76impl_int_conversion!(PodU128, u128);
77
78impl Debug for PodU128 {
79 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
80 let v: u128 = u128::from(self);
81 f.debug_tuple("PodU128").field(&v).finish()
82 }
83}
84
85#[derive(Clone, Copy, Default, PartialEq, Eq, Pod, Zeroable)]
87#[repr(transparent)]
88pub struct PodBool(pub u8);
89impl PodBool {
90 pub const fn from_bool(b: bool) -> Self {
91 Self(if b { 1 } else { 0 })
92 }
93}
94
95impl From<bool> for PodBool {
96 fn from(b: bool) -> Self {
97 Self::from_bool(b)
98 }
99}
100
101impl From<&bool> for PodBool {
102 fn from(b: &bool) -> Self {
103 Self(if *b { 1 } else { 0 })
104 }
105}
106
107impl From<&PodBool> for bool {
108 fn from(b: &PodBool) -> Self {
109 b.0 != 0
110 }
111}
112
113impl From<PodBool> for bool {
114 fn from(b: PodBool) -> Self {
115 b.0 != 0
116 }
117}
118
119impl Debug for PodBool {
120 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
121 let v: bool = bool::from(self);
122 f.debug_tuple("PodBool").field(&v).finish()
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 #[test]
131 fn test_pod_u16() {
132 let zero = PodU16::default();
134 assert_eq!(u16::from(zero), 0);
135
136 let n: u16 = 12345;
138 let pod = PodU16::from(n);
139 assert_eq!(u16::from(pod), n);
140
141 let pod_from_ref = PodU16::from(&n);
143 assert_eq!(u16::from(pod_from_ref), n);
144
145 let max = PodU16::from(u16::MAX);
147 assert_eq!(u16::from(max), u16::MAX);
148 }
149
150 #[test]
151 fn test_pod_u32() {
152 let zero = PodU32::default();
154 assert_eq!(u32::from(zero), 0);
155
156 let n: u32 = 305_419_896;
158 let pod = PodU32::from(n);
159 assert_eq!(u32::from(pod), n);
160
161 let pod_from_ref = PodU32::from(&n);
163 assert_eq!(u32::from(pod_from_ref), n);
164
165 let max = PodU32::from(u32::MAX);
167 assert_eq!(u32::from(max), u32::MAX);
168 }
169
170 #[test]
171 fn test_pod_u64() {
172 let zero = PodU64::default();
174 assert_eq!(u64::from(zero), 0);
175
176 let n: u64 = 1_311_768_467_294_899_695;
178 let pod = PodU64::from(n);
179 assert_eq!(u64::from(pod), n);
180
181 let pod_from_ref = PodU64::from(&n);
183 assert_eq!(u64::from(pod_from_ref), n);
184
185 let max = PodU64::from(u64::MAX);
187 assert_eq!(u64::from(max), u64::MAX);
188 }
189
190 #[test]
191 fn test_pod_u128() {
192 let zero = PodU128::default();
194 assert_eq!(u128::from(zero), 0);
195
196 let n: u128 = 170_141_183_460_469_231_731_687_303_715_884_105_727;
198 let pod = PodU128::from(n);
199 assert_eq!(u128::from(pod), n);
200
201 let pod_from_ref = PodU128::from(&n);
203 assert_eq!(u128::from(pod_from_ref), n);
204
205 let max = PodU128::from(u128::MAX);
207 assert_eq!(u128::from(max), u128::MAX);
208 }
209
210 #[test]
211 fn test_pod_bool() {
212 let default_bool = PodBool::default();
214 assert_eq!(bool::from(default_bool), false);
215
216 let true_bool = PodBool::from(true);
218 assert_eq!(bool::from(true_bool), true);
219
220 let false_bool = PodBool::from(false);
222 assert_eq!(bool::from(false_bool), false);
223
224 let true_ref = true;
226 let pod_from_ref = PodBool::from(&true_ref);
227 assert_eq!(bool::from(pod_from_ref), true);
228
229 let non_zero = PodBool(2);
231 assert_eq!(bool::from(non_zero), true);
232 }
233
234 #[test]
235 fn test_debug_formatting() {
236 assert_eq!(format!("{:?}", PodU16::from(12345)), "PodU16(12345)");
238 assert_eq!(
239 format!("{:?}", PodU32::from(305419896)),
240 "PodU32(305419896)"
241 );
242 assert_eq!(
243 format!("{:?}", PodU64::from(1311768467294899695)),
244 "PodU64(1311768467294899695)"
245 );
246 assert_eq!(
247 format!(
248 "{:?}",
249 PodU128::from(170141183460469231731687303715884105727)
250 ),
251 "PodU128(170141183460469231731687303715884105727)"
252 );
253 assert_eq!(format!("{:?}", PodBool::from(true)), "PodBool(true)");
254 assert_eq!(format!("{:?}", PodBool::from(false)), "PodBool(false)");
255 }
256
257 #[test]
258 fn test_byte_representation() {
259 let n: u16 = 0x1234;
261 let pod = PodU16::from(n);
262 assert_eq!(pod.0, [0x34, 0x12]);
263
264 let n: u32 = 0x12345678;
265 let pod = PodU32::from(n);
266 assert_eq!(pod.0, [0x78, 0x56, 0x34, 0x12]);
267
268 let n: u64 = 0x1234567890ABCDEF;
269 let pod = PodU64::from(n);
270 assert_eq!(pod.0, [0xEF, 0xCD, 0xAB, 0x90, 0x78, 0x56, 0x34, 0x12]);
271 }
272
273 #[test]
274 fn test_pod_properties() {
275 fn assert_pod<T: Pod + Default + Copy + Clone + PartialEq + Eq>() {}
277
278 assert_pod::<PodU16>();
279 assert_pod::<PodU32>();
280 assert_pod::<PodU64>();
281 assert_pod::<PodU128>();
282 assert_pod::<PodBool>();
283 }
284}