spl_pod/
primitives.rs

1//! primitive types that can be used in `Pod`s
2#[cfg(feature = "borsh")]
3use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
4use bytemuck_derive::{Pod, Zeroable};
5#[cfg(feature = "serde-traits")]
6use serde::{Deserialize, Serialize};
7
8/// The standard `bool` is not a `Pod`, define a replacement that is
9#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
10#[cfg_attr(feature = "serde-traits", serde(from = "bool", into = "bool"))]
11#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
12#[repr(transparent)]
13pub struct PodBool(pub u8);
14impl PodBool {
15    pub const fn from_bool(b: bool) -> Self {
16        Self(if b { 1 } else { 0 })
17    }
18}
19
20impl From<bool> for PodBool {
21    fn from(b: bool) -> Self {
22        Self::from_bool(b)
23    }
24}
25
26impl From<&bool> for PodBool {
27    fn from(b: &bool) -> Self {
28        Self(if *b { 1 } else { 0 })
29    }
30}
31
32impl From<&PodBool> for bool {
33    fn from(b: &PodBool) -> Self {
34        b.0 != 0
35    }
36}
37
38impl From<PodBool> for bool {
39    fn from(b: PodBool) -> Self {
40        b.0 != 0
41    }
42}
43
44/// Simple macro for implementing conversion functions between Pod* integers and
45/// standard integers.
46///
47/// The standard integer types can cause alignment issues when placed in a `Pod`,
48/// so these replacements are usable in all `Pod`s.
49#[macro_export]
50macro_rules! impl_int_conversion {
51    ($P:ty, $I:ty) => {
52        impl $P {
53            pub const fn from_primitive(n: $I) -> Self {
54                Self(n.to_le_bytes())
55            }
56        }
57        impl From<$I> for $P {
58            fn from(n: $I) -> Self {
59                Self::from_primitive(n)
60            }
61        }
62        impl From<$P> for $I {
63            fn from(pod: $P) -> Self {
64                Self::from_le_bytes(pod.0)
65            }
66        }
67    };
68}
69
70/// `u16` type that can be used in `Pod`s
71#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
72#[cfg_attr(feature = "serde-traits", serde(from = "u16", into = "u16"))]
73#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
74#[repr(transparent)]
75pub struct PodU16(pub [u8; 2]);
76impl_int_conversion!(PodU16, u16);
77
78/// `i16` type that can be used in Pods
79#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
80#[cfg_attr(feature = "serde-traits", serde(from = "i16", into = "i16"))]
81#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
82#[repr(transparent)]
83pub struct PodI16(pub [u8; 2]);
84impl_int_conversion!(PodI16, i16);
85
86/// `u32` type that can be used in `Pod`s
87#[cfg_attr(
88    feature = "borsh",
89    derive(BorshDeserialize, BorshSerialize, BorshSchema)
90)]
91#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
92#[cfg_attr(feature = "serde-traits", serde(from = "u32", into = "u32"))]
93#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
94#[repr(transparent)]
95pub struct PodU32(pub [u8; 4]);
96impl_int_conversion!(PodU32, u32);
97
98/// `u64` type that can be used in Pods
99#[cfg_attr(
100    feature = "borsh",
101    derive(BorshDeserialize, BorshSerialize, BorshSchema)
102)]
103#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
104#[cfg_attr(feature = "serde-traits", serde(from = "u64", into = "u64"))]
105#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
106#[repr(transparent)]
107pub struct PodU64(pub [u8; 8]);
108impl_int_conversion!(PodU64, u64);
109
110/// `i64` type that can be used in Pods
111#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
112#[cfg_attr(feature = "serde-traits", serde(from = "i64", into = "i64"))]
113#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
114#[repr(transparent)]
115pub struct PodI64([u8; 8]);
116impl_int_conversion!(PodI64, i64);
117
118/// `u128` type that can be used in Pods
119#[cfg_attr(
120    feature = "borsh",
121    derive(BorshDeserialize, BorshSerialize, BorshSchema)
122)]
123#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
124#[cfg_attr(feature = "serde-traits", serde(from = "u128", into = "u128"))]
125#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
126#[repr(transparent)]
127pub struct PodU128(pub [u8; 16]);
128impl_int_conversion!(PodU128, u128);
129
130#[cfg(test)]
131mod tests {
132    use {super::*, crate::bytemuck::pod_from_bytes};
133
134    #[test]
135    fn test_pod_bool() {
136        assert!(pod_from_bytes::<PodBool>(&[]).is_err());
137        assert!(pod_from_bytes::<PodBool>(&[0, 0]).is_err());
138
139        for i in 0..=u8::MAX {
140            assert_eq!(i != 0, bool::from(pod_from_bytes::<PodBool>(&[i]).unwrap()));
141        }
142    }
143
144    #[cfg(feature = "serde-traits")]
145    #[test]
146    fn test_pod_bool_serde() {
147        let pod_false: PodBool = false.into();
148        let pod_true: PodBool = true.into();
149
150        let serialized_false = serde_json::to_string(&pod_false).unwrap();
151        let serialized_true = serde_json::to_string(&pod_true).unwrap();
152        assert_eq!(&serialized_false, "false");
153        assert_eq!(&serialized_true, "true");
154
155        let deserialized_false = serde_json::from_str::<PodBool>(&serialized_false).unwrap();
156        let deserialized_true = serde_json::from_str::<PodBool>(&serialized_true).unwrap();
157        assert_eq!(pod_false, deserialized_false);
158        assert_eq!(pod_true, deserialized_true);
159    }
160
161    #[test]
162    fn test_pod_u16() {
163        assert!(pod_from_bytes::<PodU16>(&[]).is_err());
164        assert_eq!(1u16, u16::from(*pod_from_bytes::<PodU16>(&[1, 0]).unwrap()));
165    }
166
167    #[cfg(feature = "serde-traits")]
168    #[test]
169    fn test_pod_u16_serde() {
170        let pod_u16: PodU16 = u16::MAX.into();
171
172        let serialized = serde_json::to_string(&pod_u16).unwrap();
173        assert_eq!(&serialized, "65535");
174
175        let deserialized = serde_json::from_str::<PodU16>(&serialized).unwrap();
176        assert_eq!(pod_u16, deserialized);
177    }
178
179    #[test]
180    fn test_pod_i16() {
181        assert!(pod_from_bytes::<PodI16>(&[]).is_err());
182        assert_eq!(
183            -1i16,
184            i16::from(*pod_from_bytes::<PodI16>(&[255, 255]).unwrap())
185        );
186    }
187
188    #[cfg(feature = "serde-traits")]
189    #[test]
190    fn test_pod_i16_serde() {
191        let pod_i16: PodI16 = i16::MAX.into();
192
193        println!("pod_i16 {:?}", pod_i16);
194
195        let serialized = serde_json::to_string(&pod_i16).unwrap();
196        assert_eq!(&serialized, "32767");
197
198        let deserialized = serde_json::from_str::<PodI16>(&serialized).unwrap();
199        assert_eq!(pod_i16, deserialized);
200    }
201
202    #[test]
203    fn test_pod_u64() {
204        assert!(pod_from_bytes::<PodU64>(&[]).is_err());
205        assert_eq!(
206            1u64,
207            u64::from(*pod_from_bytes::<PodU64>(&[1, 0, 0, 0, 0, 0, 0, 0]).unwrap())
208        );
209    }
210
211    #[cfg(feature = "serde-traits")]
212    #[test]
213    fn test_pod_u64_serde() {
214        let pod_u64: PodU64 = u64::MAX.into();
215
216        let serialized = serde_json::to_string(&pod_u64).unwrap();
217        assert_eq!(&serialized, "18446744073709551615");
218
219        let deserialized = serde_json::from_str::<PodU64>(&serialized).unwrap();
220        assert_eq!(pod_u64, deserialized);
221    }
222
223    #[test]
224    fn test_pod_i64() {
225        assert!(pod_from_bytes::<PodI64>(&[]).is_err());
226        assert_eq!(
227            -1i64,
228            i64::from(
229                *pod_from_bytes::<PodI64>(&[255, 255, 255, 255, 255, 255, 255, 255]).unwrap()
230            )
231        );
232    }
233
234    #[cfg(feature = "serde-traits")]
235    #[test]
236    fn test_pod_i64_serde() {
237        let pod_i64: PodI64 = i64::MAX.into();
238
239        let serialized = serde_json::to_string(&pod_i64).unwrap();
240        assert_eq!(&serialized, "9223372036854775807");
241
242        let deserialized = serde_json::from_str::<PodI64>(&serialized).unwrap();
243        assert_eq!(pod_i64, deserialized);
244    }
245
246    #[test]
247    fn test_pod_u128() {
248        assert!(pod_from_bytes::<PodU128>(&[]).is_err());
249        assert_eq!(
250            1u128,
251            u128::from(
252                *pod_from_bytes::<PodU128>(&[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
253                    .unwrap()
254            )
255        );
256    }
257
258    #[cfg(feature = "serde-traits")]
259    #[test]
260    fn test_pod_u128_serde() {
261        let pod_u128: PodU128 = u128::MAX.into();
262
263        let serialized = serde_json::to_string(&pod_u128).unwrap();
264        assert_eq!(&serialized, "340282366920938463463374607431768211455");
265
266        let deserialized = serde_json::from_str::<PodU128>(&serialized).unwrap();
267        assert_eq!(pod_u128, deserialized);
268    }
269}