1#![doc = include_str!("../README.md")]
2
3use std::sync::atomic::{AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize,
4 AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicUsize};
5
6pub trait GetSize {
8 #[inline] fn size_bytes_dyn(&self) -> usize { 0 }
11
12 #[inline] fn size_bytes_content_dyn(&self) -> usize { self.size_bytes_dyn() }
17
18 #[inline] fn size_bytes(&self) -> usize {
20 std::mem::size_of_val(self) + self.size_bytes_dyn()
21 }
22
23 const USES_DYN_MEM: bool = false;
25}
26
27macro_rules! impl_nodyn_getsize_for {
29 ($x:ty) => (impl self::GetSize for $x {});
30 ($x:ty, $($y:ty),+) => (
32 impl self::GetSize for $x {}
33 impl_nodyn_getsize_for!($($y),+);
34 )
35}
36
37impl_nodyn_getsize_for!(u8, u16, u32, u64, u128, usize,
38 AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicUsize,
39 bool, AtomicBool,
40 i8, i16, i32, i64, i128, isize,
41 AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize,
42 f32, f64, char, ());
43
44impl<T: GetSize, const N: usize> GetSize for [T; N] {
46 fn size_bytes_dyn(&self) -> usize {
47 if T::USES_DYN_MEM {
48 self.iter().map(self::GetSize::size_bytes_dyn).sum()
49 } else {
50 0
51 }
52 }
53 fn size_bytes_content_dyn(&self) -> usize {
54 if T::USES_DYN_MEM {
55 self.iter().map(self::GetSize::size_bytes_content_dyn).sum()
56 } else {
57 0
58 }
59 }
60 const USES_DYN_MEM: bool = T::USES_DYN_MEM;
61}
62
63macro_rules! impl_getsize_methods_for_pointer {
64 () => (
65 fn size_bytes_dyn(&self) -> ::std::primitive::usize {
66 ::std::ops::Deref::deref(self).size_bytes()
67 }
68 const USES_DYN_MEM: bool = true;
69 );
70}
71
72impl <T: GetSize> GetSize for Box<T> {
73 impl_getsize_methods_for_pointer!();
74}
75
76#[cfg(feature = "aligned-vec")] impl <T: GetSize> GetSize for aligned_vec::ABox<T> {
77 impl_getsize_methods_for_pointer!();
78}
79
80impl <T: GetSize> GetSize for ::std::rc::Rc<T> {
81 fn size_bytes_dyn(&self) -> ::std::primitive::usize {
82 let c = ::std::rc::Rc::strong_count(self);
84 (::std::ops::Deref::deref(self).size_bytes() + 2*::std::mem::size_of::<usize>() + c/2) / c
85 }
86 const USES_DYN_MEM: bool = true;
87}
88
89macro_rules! impl_getsize_methods_for_dyn_arr {
90 ($T:ty) => (
91 fn size_bytes_dyn(&self) -> ::std::primitive::usize {
92 if <$T>::USES_DYN_MEM {
93 self.iter().map(self::GetSize::size_bytes).sum()
94 } else {
95 ::std::mem::size_of::<$T>() * self.len()
96 }
97 }
98 const USES_DYN_MEM: bool = true;
99 );
100}
101
102impl<T: GetSize> GetSize for Box<[T]> {
103 impl_getsize_methods_for_dyn_arr!(T);
104}
105
106#[cfg(feature = "aligned-vec")] impl <T: GetSize, A: aligned_vec::Alignment> GetSize for aligned_vec::ABox<[T], A> {
107 impl_getsize_methods_for_dyn_arr!(T);
108}
109
110macro_rules! impl_getsize_methods_for_vec {
111 ($T:ty) => (
112 fn size_bytes_dyn(&self) -> usize {
113 let c = ::std::mem::size_of::<$T>() * self.capacity();
114 if <$T>::USES_DYN_MEM {
115 c + self.iter().map(GetSize::size_bytes_dyn).sum::<usize>()
116 } else {
117 c
118 }
119 }
120 fn size_bytes_content_dyn(&self) -> usize {
121 let c = ::std::mem::size_of::<$T>() * self.len();
122 if <$T>::USES_DYN_MEM {
123 c + self.iter().map(GetSize::size_bytes_content_dyn).sum::<usize>()
124 } else {
125 c
126 }
127 }
128 const USES_DYN_MEM: bool = true;
129 );
130}
131
132impl<T: GetSize> GetSize for Vec<T> {
133 impl_getsize_methods_for_vec!(T);
134}
135
136#[cfg(feature = "aligned-vec")] impl <T: GetSize, A: aligned_vec::Alignment> GetSize for aligned_vec::AVec<T, A> {
137 impl_getsize_methods_for_vec!(T);
138}
139
140#[cfg(feature = "rsdict")] impl GetSize for rsdict::RsDict {
141 #[inline] fn size_bytes_dyn(&self) -> usize { self.heap_size() }
142 const USES_DYN_MEM: bool = true;
143}
144
145macro_rules! impl_getsize_for_tuple {
146 ($( $T:ident ),+) => {
147 impl<$( $T: self::GetSize ),+> self::GetSize for ($( $T, )+) {
148 #[allow(non_snake_case)]
149 fn size_bytes_dyn(&self) -> ::std::primitive::usize {
150 let &($( ref $T, )+) = self;
151 0 $( + $T.size_bytes_dyn() )+
152 }
153 #[allow(non_snake_case)]
154 fn size_bytes_content_dyn(&self) -> ::std::primitive::usize {
155 let &($( ref $T, )+) = self;
156 0 $( + $T.size_bytes_content_dyn() )+
157 }
158 const USES_DYN_MEM: bool = $( $T::USES_DYN_MEM )|*;
159 }
160 }
161}
162
163impl_getsize_for_tuple!(A);
164impl_getsize_for_tuple!(A, B);
165impl_getsize_for_tuple!(A, B, C);
166impl_getsize_for_tuple!(A, B, C, D);
167impl_getsize_for_tuple!(A, B, C, D, E);
168impl_getsize_for_tuple!(A, B, C, D, E, F);
169impl_getsize_for_tuple!(A, B, C, D, E, F, G);
170impl_getsize_for_tuple!(A, B, C, D, E, F, G, H);
171impl_getsize_for_tuple!(A, B, C, D, E, F, G, H, I);
172impl_getsize_for_tuple!(A, B, C, D, E, F, G, H, I, J);
173
174
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179
180 fn test_primitive<T: GetSize>(v: T) {
181 assert_eq!(v.size_bytes_dyn(), 0);
182 assert_eq!(v.size_bytes_content_dyn(), 0);
183 assert_eq!(v.size_bytes(), std::mem::size_of_val(&v));
184 assert!(!T::USES_DYN_MEM);
185 }
186
187 #[test]
188 fn test_primitives() {
189 test_primitive(1u32);
190 test_primitive(1.0f32);
191 }
192
193 #[test]
194 fn test_array() {
195 assert_eq!([1u32, 2u32, 3u32].size_bytes(), 3*4);
196 assert_eq!([[1u32, 2u32], [3u32, 4u32]].size_bytes(), 4*4);
197 assert_eq!([vec![1u32, 2u32], vec![3u32, 4u32]].size_bytes_content_dyn(), 4*4);
198 }
199
200 #[test]
201 fn test_vec() {
202 assert_eq!(vec![1u32, 2u32, 3u32].size_bytes_content_dyn(), 3*4);
203 assert_eq!(vec![[1u32, 2u32], [3u32, 4u32]].size_bytes_content_dyn(), 4*4);
204 let v = vec![1u32, 2u32];
205 assert_eq!(vec![v.clone(), v.clone()].size_bytes_dyn(), 2*v.size_bytes());
206 assert_eq!(Vec::<u32>::with_capacity(3).size_bytes_dyn(), 3*4);
207 assert_eq!(Vec::<u32>::with_capacity(3).size_bytes_content_dyn(), 0);
208 }
209
210 #[test]
211 fn test_boxed_slice() {
212 let bs = vec![1u32, 2u32, 3u32].into_boxed_slice();
213 assert_eq!(bs.size_bytes_dyn(), 3*4);
214 assert_eq!(bs.size_bytes(), 3*4 + std::mem::size_of_val(&bs));
215 }
216
217 #[test]
218 fn test_tuple() {
219 assert_eq!((1u32, 2u32).size_bytes_dyn(), 0);
220 assert_eq!((1u32, vec![3u32, 4u32]).size_bytes_dyn(), 2*4);
221 assert_eq!((vec![1u32, 2u32], vec![3u32, 4u32]).size_bytes_dyn(), 4*4);
222 }
223
224 #[test]
225 #[allow(unused_allocation)]
226 fn test_box() {
227 assert_eq!(Box::new(1u32).size_bytes_dyn(), 4);
228 assert_eq!(Box::new([1u32, 2u32]).size_bytes_dyn(), 2*4);
229 }
230}