jito_bytemuck/
types.rs

1use std::fmt::{Debug, Formatter};
2
3// https://github.com/solana-labs/solana-program-library/tree/master/libraries/pod
4use bytemuck::{Pod, Zeroable};
5
6/// Simple macro for implementing conversion functions between Pod* ints and
7/// standard ints.
8///
9/// The standard int types can cause alignment issues when placed in a `Pod`,
10/// so these replacements are usable in all `Pod`s.
11#[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/// The standard `bool` is not a `Pod`, define a replacement that is
86#[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        // Test zero
133        let zero = PodU16::default();
134        assert_eq!(u16::from(zero), 0);
135
136        // Test conversion from u16
137        let n: u16 = 12345;
138        let pod = PodU16::from(n);
139        assert_eq!(u16::from(pod), n);
140
141        // Test reference conversion
142        let pod_from_ref = PodU16::from(&n);
143        assert_eq!(u16::from(pod_from_ref), n);
144
145        // Test max value
146        let max = PodU16::from(u16::MAX);
147        assert_eq!(u16::from(max), u16::MAX);
148    }
149
150    #[test]
151    fn test_pod_u32() {
152        // Test zero
153        let zero = PodU32::default();
154        assert_eq!(u32::from(zero), 0);
155
156        // Test conversion from u32
157        let n: u32 = 305_419_896;
158        let pod = PodU32::from(n);
159        assert_eq!(u32::from(pod), n);
160
161        // Test reference conversion
162        let pod_from_ref = PodU32::from(&n);
163        assert_eq!(u32::from(pod_from_ref), n);
164
165        // Test max value
166        let max = PodU32::from(u32::MAX);
167        assert_eq!(u32::from(max), u32::MAX);
168    }
169
170    #[test]
171    fn test_pod_u64() {
172        // Test zero
173        let zero = PodU64::default();
174        assert_eq!(u64::from(zero), 0);
175
176        // Test conversion from u64
177        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        // Test reference conversion
182        let pod_from_ref = PodU64::from(&n);
183        assert_eq!(u64::from(pod_from_ref), n);
184
185        // Test max value
186        let max = PodU64::from(u64::MAX);
187        assert_eq!(u64::from(max), u64::MAX);
188    }
189
190    #[test]
191    fn test_pod_u128() {
192        // Test zero
193        let zero = PodU128::default();
194        assert_eq!(u128::from(zero), 0);
195
196        // Test conversion from u128
197        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        // Test reference conversion
202        let pod_from_ref = PodU128::from(&n);
203        assert_eq!(u128::from(pod_from_ref), n);
204
205        // Test max value
206        let max = PodU128::from(u128::MAX);
207        assert_eq!(u128::from(max), u128::MAX);
208    }
209
210    #[test]
211    fn test_pod_bool() {
212        // Test default is false
213        let default_bool = PodBool::default();
214        assert_eq!(bool::from(default_bool), false);
215
216        // Test true conversion
217        let true_bool = PodBool::from(true);
218        assert_eq!(bool::from(true_bool), true);
219
220        // Test false conversion
221        let false_bool = PodBool::from(false);
222        assert_eq!(bool::from(false_bool), false);
223
224        // Test reference conversion
225        let true_ref = true;
226        let pod_from_ref = PodBool::from(&true_ref);
227        assert_eq!(bool::from(pod_from_ref), true);
228
229        // Test non-zero values are true
230        let non_zero = PodBool(2);
231        assert_eq!(bool::from(non_zero), true);
232    }
233
234    #[test]
235    fn test_debug_formatting() {
236        // Test debug formatting for all types
237        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        // Test that the byte representation is correct (little-endian)
260        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        // Test that Pod types implement expected traits
276        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}