size_of_no_padding/
lib.rs

1//! # Size Of No Padding
2//! This crate provides two derive proc-macro.
3//!
4//! ## `SizeOfNoPadding`
5//! > Only support struct can be marked as `Copy`
6//!
7//! Create a shadow struct which as same as original struct except it's marked `#[repr(packed)]`. call `size_of_no_padding()` method on struct will invoke `std::mem::size_of()` function on shadow one in compile time.
8//!
9//! ### Example
10//! ```rust
11//! use size_of_no_padding::SizeOfNoPadding;
12//! use size_of_no_padding::SizeOf;
13//!
14//! #[derive(SizeOfNoPadding)]
15//! struct Abc {
16//!     a: u8,
17//!     b: u32,
18//!     c: u8,
19//! }
20//!
21//! assert_eq!(8, std::mem::size_of::<Abc>());
22//! assert_eq!(6, Abc::size_of_no_padding());
23//!
24//! ```
25//!
26//! ### `SizeOfNoPaddingAny`
27//! > Support struct whose non-Copy fields impl [`SizeOfAny`] trait
28//!
29//! Calculate the size for every field, add up all the size. call `size_of_no_padding(&self)` will give the size of whole struct without padding in runtime.
30//!
31//! ### Example
32//! ```rust
33//! use size_of_no_padding::SizeOfNoPaddingAny;
34//! use size_of_no_padding::SizeOfAny;
35//!
36//! #[derive(SizeOfNoPaddingAny)]
37//! struct Abc2 {
38//!     a: u8,
39//!     b: u32,
40//!     c: u8,
41//!     d: Vec<u16>,
42//!     e: Abc3,
43//! }
44//!
45//! #[derive(SizeOfNoPaddingAny)]
46//! struct Abc3([u32; 4], u16);
47//!
48//! let abc = Abc2 {
49//!     a: 1,
50//!     b: 2,
51//!     c: 3,
52//!     d: vec![4, 5, 6],
53//!     e: Abc3([7, 8, 9, 10], 11),
54//! };
55//!
56//! assert_eq!(std::mem::size_of::<Abc2>(), 56);
57//! assert_eq!(abc.size_of_no_padding_any(), 30);
58//! ```
59//!
60//! ## License
61//!
62//! Licensed under either of
63//!
64//! - Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
65//! - MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
66//!
67//! at your option.
68pub use size_of_no_padding_derive::{SizeOfNoPadding, SizeOfNoPaddingAny};
69extern crate self as size_of_no_padding;
70
71/// A trait for types that can calculate their size without padding.
72/// Struct can derive this trait by using `#[derive(SizeOfNoPaddingAny)]`
73pub trait SizeOfAny {
74    fn size_of_no_padding_any(&self) -> usize;
75}
76
77/// A trait for types that can calculate their size without padding.
78/// Struct can derive this trait by using `#[derive(SizeOfNoPadding)]`
79pub trait SizeOf {
80    fn size_of_no_padding() -> usize;
81}
82
83/// A trait for Primitive types.
84/// This trait is used to implement [`SizeOfAny`] for primitive types.
85pub trait Primitive {}
86
87impl Primitive for u8 {}
88impl Primitive for u16 {}
89impl Primitive for u32 {}
90impl Primitive for u64 {}
91impl Primitive for usize {}
92impl Primitive for i8 {}
93impl Primitive for i16 {}
94impl Primitive for i32 {}
95impl Primitive for i64 {}
96impl Primitive for isize {}
97impl Primitive for f32 {}
98impl Primitive for f64 {}
99impl Primitive for bool {}
100impl Primitive for char {}
101impl Primitive for () {}
102
103impl<T: SizeOfAny> SizeOfAny for [T] {
104    fn size_of_no_padding_any(&self) -> usize {
105        self.iter().map(|item| item.size_of_no_padding_any()).sum()
106    }
107}
108
109impl<T: Primitive> SizeOfAny for T {
110    fn size_of_no_padding_any(&self) -> usize {
111        std::mem::size_of::<T>()
112    }
113}
114
115#[cfg(test)]
116mod test {
117    use crate::{Primitive, SizeOf, SizeOfAny};
118    use size_of_no_padding_derive::{SizeOfNoPadding, SizeOfNoPaddingAny};
119
120    #[derive(SizeOfNoPadding)]
121    #[allow(dead_code)]
122    struct Abc<T> {
123        a: u8,
124        b: u32,
125        c: u8,
126        d: T,
127    }
128
129    #[test]
130    fn test_size_of_abc() {
131        let size = std::mem::size_of::<Abc<u32>>();
132        assert_eq!(size, 12);
133        let size_no_padding = Abc::<u32>::size_of_no_padding();
134        assert_eq!(size_no_padding, 10);
135    }
136
137    #[derive(SizeOfNoPaddingAny)]
138    struct Abc2<const T: usize, K: Primitive> {
139        a: K,
140        b: u32,
141        c: [u8; T],
142        d: Vec<Abc3>,
143        e: Abc3,
144    }
145
146    #[derive(SizeOfNoPaddingAny, Clone, Copy)]
147    struct Abc3([u32; 4], u16);
148
149    #[test]
150    fn test_size_of_abc2() {
151        assert_eq!(std::mem::size_of::<Abc3>(), 20);
152
153        let abc3 = Abc3([7, 8, 9, 10], 11);
154        let size = abc3.size_of_no_padding_any();
155        assert_eq!(size, 18);
156
157        let abc2 = Abc2 {
158            a: 1u8,
159            b: 2,
160            c: [3, 4, 5, 6],
161            d: vec![abc3, abc3],
162            e: abc3,
163        };
164
165        let size = abc2.size_of_no_padding_any();
166        assert_eq!(size, 63);
167    }
168}