struct_pad/
lib.rs

1#![no_std]
2//! Padding types to enable memory layout optimizations.
3//!
4//! # Example
5//!
6//! Basic usage:
7//!
8//! ```rust
9//! use struct_pad::{Pad, PadU0, PadU8, PadU16, PadU32};
10//!
11//! struct Example {
12//!     field1: u64,
13//!     field2: u8,
14//!     // Padding fields
15//!     pad1: PadU8,
16//!     #[cfg(target_pointer_width = "16")]
17//!     pad2: PadU0,
18//!     #[cfg(not(target_pointer_width = "16"))]
19//!     pad2: PadU16,
20//!     #[cfg(target_pointer_width = "64")]
21//!     pad3: PadU32,
22//!     #[cfg(not(target_pointer_width = "64"))]
23//!     pad3: PadU0,
24//! }
25//!
26//! impl Example {
27//!     const fn new(field1: u64, field2: u8) -> Self {
28//!         Self {
29//!             field1,
30//!             field2,
31//!             pad1: Pad::VALUE,
32//!             pad2: Pad::VALUE,
33//!             pad3: Pad::VALUE,
34//!         }
35//!     }
36//! }
37//! ```
38
39use core::cmp::Ordering;
40use core::hash::{Hash, Hasher};
41
42/// A padding type.
43/// 
44/// Types implementing `Pad` have only *one* valid bit-pattern.
45///
46/// This trait is provided so that downstream crates may 
47/// construct pad values generically within `const fn`'s.
48pub trait Pad: Copy + private::Sealed {
49    /// The only valid `Pad` value.
50    const VALUE: Self;
51}
52
53/// A padding type with the same layout as `()`.
54///
55/// Like the other padding types, `PadU0` implements the `Pad` trait.
56/// However, it occupies no space in memory.
57#[derive(Debug)]
58pub struct PadU0(());
59
60impl Clone for PadU0 {
61    #[inline]
62    #[must_use]
63    fn clone(&self) -> Self {
64        Self::VALUE
65    }
66}
67
68impl Copy for PadU0 {}
69
70impl Default for PadU0 {
71    #[inline]
72    #[must_use]
73    fn default() -> Self {
74        Self::VALUE
75    }
76}
77
78impl Eq for PadU0 {}
79
80impl Hash for PadU0 {
81    #[inline]
82    fn hash<H: Hasher>(&self, _: &mut H) {}
83}
84
85impl Ord for PadU0 {
86    #[inline]
87    #[must_use]
88    fn cmp(&self, _: &Self) -> Ordering {
89        Ordering::Equal
90    }
91}
92
93impl Pad for PadU0 {
94    const VALUE: Self = Self(());
95}
96
97impl PartialEq for PadU0 {
98    #[inline]
99    #[must_use]
100    fn eq(&self, _: &Self) -> bool {
101        true
102    }
103}
104
105impl PartialOrd for PadU0 {
106    #[inline]
107    #[must_use]
108    fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
109        Some(Ordering::Equal)
110    }
111}
112
113/// A padding type with the same layout as `u8`.
114///
115/// `PadU8` is implemented as a wrapper around a single-variant enum
116/// with an all-zeros bit-pattern.
117#[derive(Debug)]
118#[repr(transparent)]
119pub struct PadU8(PadU8Inner);
120
121impl Clone for PadU8 {
122    #[inline]
123    #[must_use]
124    fn clone(&self) -> Self {
125        Self::VALUE
126    }
127}
128
129impl Copy for PadU8 {}
130
131impl Default for PadU8 {
132    #[inline]
133    #[must_use]
134    fn default() -> Self {
135        Self::VALUE
136    }
137}
138
139impl Eq for PadU8 {}
140
141impl Hash for PadU8 {
142    #[inline]
143    fn hash<H: Hasher>(&self, _: &mut H) {}
144}
145
146impl Ord for PadU8 {
147    #[inline]
148    #[must_use]
149    fn cmp(&self, _: &Self) -> Ordering {
150        Ordering::Equal
151    }
152}
153
154impl Pad for PadU8 {
155    const VALUE: Self = Self(PadU8Inner::VALUE);
156}
157
158impl PartialEq for PadU8 {
159    #[inline]
160    #[must_use]
161    fn eq(&self, _: &Self) -> bool {
162        true
163    }
164}
165
166impl PartialOrd for PadU8 {
167    #[inline]
168    #[must_use]
169    fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
170        Some(Ordering::Equal)
171    }
172}
173
174#[derive(Debug)]
175#[repr(u8)]
176enum PadU8Inner {
177    VALUE = 0,
178}
179
180impl Clone for PadU8Inner {
181    #[inline]
182    #[must_use]
183    fn clone(&self) -> Self {
184        Self::VALUE
185    }
186}
187
188impl Copy for PadU8Inner {}
189
190/// A padding type with the same layout as `u16`.
191///
192/// `PadU16` is implemented as a wrapper around a single-variant enum
193/// with an all-zeros bit-pattern.
194#[derive(Debug)]
195#[repr(transparent)]
196pub struct PadU16(PadU16Inner);
197
198impl Clone for PadU16 {
199    #[inline]
200    #[must_use]
201    fn clone(&self) -> Self {
202        Self::VALUE
203    }
204}
205
206impl Copy for PadU16 {}
207
208impl Default for PadU16 {
209    #[inline]
210    #[must_use]
211    fn default() -> Self {
212        Self::VALUE
213    }
214}
215
216impl Eq for PadU16 {}
217
218impl Hash for PadU16 {
219    #[inline]
220    fn hash<H: Hasher>(&self, _: &mut H) {}
221}
222
223impl Ord for PadU16 {
224    #[inline]
225    #[must_use]
226    fn cmp(&self, _: &Self) -> Ordering {
227        Ordering::Equal
228    }
229}
230
231impl Pad for PadU16 {
232    const VALUE: Self = Self(PadU16Inner::VALUE);
233}
234
235impl PartialEq for PadU16 {
236    #[inline]
237    #[must_use]
238    fn eq(&self, _: &Self) -> bool {
239        true
240    }
241}
242
243impl PartialOrd for PadU16 {
244    #[inline]
245    #[must_use]
246    fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
247        Some(Ordering::Equal)
248    }
249}
250
251#[derive(Debug)]
252#[repr(u16)]
253enum PadU16Inner {
254    VALUE = 0,
255}
256
257impl Clone for PadU16Inner {
258    #[inline]
259    #[must_use]
260    fn clone(&self) -> Self {
261        Self::VALUE
262    }
263}
264
265impl Copy for PadU16Inner {}
266
267/// A padding type with the same layout as `u32`.
268///
269/// `PadU32` is implemented as a wrapper around a single-variant enum
270/// with an all-zeros bit-pattern.
271#[derive(Debug)]
272#[repr(transparent)]
273pub struct PadU32(PadU32Inner);
274
275impl Clone for PadU32 {
276    #[inline]
277    #[must_use]
278    fn clone(&self) -> Self {
279        Self::VALUE
280    }
281}
282
283impl Copy for PadU32 {}
284
285impl Default for PadU32 {
286    #[inline]
287    #[must_use]
288    fn default() -> Self {
289        Self::VALUE
290    }
291}
292
293impl Eq for PadU32 {}
294
295impl Hash for PadU32 {
296    #[inline]
297    fn hash<H: Hasher>(&self, _: &mut H) {}
298}
299
300impl Ord for PadU32 {
301    #[inline]
302    #[must_use]
303    fn cmp(&self, _: &Self) -> Ordering {
304        Ordering::Equal
305    }
306}
307
308impl Pad for PadU32 {
309    const VALUE: Self = Self(PadU32Inner::VALUE);
310}
311
312impl PartialEq for PadU32 {
313    #[inline]
314    #[must_use]
315    fn eq(&self, _: &Self) -> bool {
316        true
317    }
318}
319
320impl PartialOrd for PadU32 {
321    #[inline]
322    #[must_use]
323    fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
324        Some(Ordering::Equal)
325    }
326}
327
328#[derive(Debug)]
329#[repr(u32)]
330enum PadU32Inner {
331    VALUE = 0,
332}
333
334impl Clone for PadU32Inner {
335    #[inline]
336    #[must_use]
337    fn clone(&self) -> Self {
338        Self::VALUE
339    }
340}
341
342impl Copy for PadU32Inner {}
343
344/// A padding type with the same layout as `u64`.
345///
346/// `PadU64` is implemented as a wrapper around a single-variant enum
347/// with an all-zeros bit-pattern.
348#[derive(Debug)]
349#[repr(transparent)]
350pub struct PadU64(PadU64Inner);
351
352impl Clone for PadU64 {
353    #[inline]
354    #[must_use]
355    fn clone(&self) -> Self {
356        Self::VALUE
357    }
358}
359
360impl Copy for PadU64 {}
361
362impl Default for PadU64 {
363    #[inline]
364    #[must_use]
365    fn default() -> Self {
366        Self::VALUE
367    }
368}
369
370impl Eq for PadU64 {}
371
372impl Hash for PadU64 {
373    #[inline]
374    fn hash<H: Hasher>(&self, _: &mut H) {}
375}
376
377impl Ord for PadU64 {
378    #[inline]
379    #[must_use]
380    fn cmp(&self, _: &Self) -> Ordering {
381        Ordering::Equal
382    }
383}
384
385impl Pad for PadU64 {
386    const VALUE: Self = Self(PadU64Inner::VALUE);
387}
388
389impl PartialEq for PadU64 {
390    #[inline]
391    #[must_use]
392    fn eq(&self, _: &Self) -> bool {
393        true
394    }
395}
396
397impl PartialOrd for PadU64 {
398    #[inline]
399    #[must_use]
400    fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
401        Some(Ordering::Equal)
402    }
403}
404
405#[derive(Debug)]
406#[repr(u64)]
407enum PadU64Inner {
408    VALUE = 0,
409}
410
411impl Clone for PadU64Inner {
412    #[inline]
413    #[must_use]
414    fn clone(&self) -> Self {
415        Self::VALUE
416    }
417}
418
419impl Copy for PadU64Inner {}
420
421/// A padding type with the same layout as `usize`.
422///
423/// `PadUsize` is a type alias to whichever padding type is
424/// the same size as `usize`.
425#[cfg(target_pointer_width = "16")]
426pub type PadUsize = PadU16;
427/// A padding type with the same layout as `usize`.
428///
429/// `PadUsize` is a type alias to whichever padding type is
430/// the same size as `usize`.
431#[cfg(target_pointer_width = "32")]
432pub type PadUsize = PadU32;
433/// A padding type with the same layout as `usize`.
434///
435/// `PadUsize` is a type alias to whichever padding type is
436/// the same size as `usize`.
437#[cfg(target_pointer_width = "64")]
438pub type PadUsize = PadU64;
439
440mod private {
441    pub use super::*;
442    pub trait Sealed {}
443    impl Sealed for PadU0 {}
444    impl Sealed for PadU8 {}
445    impl Sealed for PadU16 {}
446    impl Sealed for PadU32 {}
447    impl Sealed for PadU64 {}
448}
449
450#[cfg(test)]
451mod tests {
452    use super::*;
453    use core::mem::{align_of, size_of};
454
455    #[test]
456    fn align() {
457        assert_eq!(align_of::<PadU0>(), align_of::<()>());
458        assert_eq!(align_of::<PadU8>(), align_of::<u8>());
459        assert_eq!(align_of::<PadU16>(), align_of::<u16>());
460        assert_eq!(align_of::<PadU32>(), align_of::<u32>());
461        assert_eq!(align_of::<PadU64>(), align_of::<u64>());
462        assert_eq!(align_of::<PadUsize>(), align_of::<usize>());
463    }
464
465    #[test]
466    fn align_option() {
467        assert_eq!(align_of::<Option<PadU0>>(), align_of::<Option<()>>());
468        assert_eq!(align_of::<Option<PadU8>>(), align_of::<u8>());
469        assert_eq!(align_of::<Option<PadU16>>(), align_of::<u16>());
470        assert_eq!(align_of::<Option<PadU32>>(), align_of::<u32>());
471        assert_eq!(align_of::<Option<PadU64>>(), align_of::<u64>());
472        assert_eq!(align_of::<Option<PadUsize>>(), align_of::<usize>());
473    }
474
475    #[test]
476    fn size() {
477        assert_eq!(size_of::<PadU0>(), size_of::<()>());
478        assert_eq!(size_of::<PadU8>(), size_of::<u8>());
479        assert_eq!(size_of::<PadU16>(), size_of::<u16>());
480        assert_eq!(size_of::<PadU32>(), size_of::<u32>());
481        assert_eq!(size_of::<PadU64>(), size_of::<u64>());
482        assert_eq!(size_of::<PadUsize>(), size_of::<usize>());
483    }
484
485    #[test]
486    fn size_option() {
487        assert_eq!(size_of::<Option<PadU0>>(), size_of::<Option<()>>());
488        assert_eq!(size_of::<Option<PadU8>>(), size_of::<u8>());
489        assert_eq!(size_of::<Option<PadU16>>(), size_of::<u16>());
490        assert_eq!(size_of::<Option<PadU32>>(), size_of::<u32>());
491        assert_eq!(size_of::<Option<PadU64>>(), size_of::<u64>());
492        assert_eq!(size_of::<Option<PadUsize>>(), size_of::<usize>());
493    }
494
495    #[test]
496    fn bit_pattern() {
497        assert_eq!(PadU8::VALUE.0 as u8, 0);
498        assert_eq!(PadU16::VALUE.0 as u16, 0);
499        assert_eq!(PadU32::VALUE.0 as u32, 0);
500        assert_eq!(PadU64::VALUE.0 as u64, 0);
501        assert_eq!(PadUsize::VALUE.0 as usize, 0);
502    }
503
504    #[test]
505    fn bit_pattern_default() {
506        assert_eq!(PadU8::default().0 as u8, 0);
507        assert_eq!(PadU16::default().0 as u16, 0);
508        assert_eq!(PadU32::default().0 as u32, 0);
509        assert_eq!(PadU64::default().0 as u64, 0);
510        assert_eq!(PadUsize::default().0 as usize, 0);
511    }
512}