get_size/
lib.rs

1#![doc = include_str!("./lib.md")]
2
3#![cfg_attr(docsrs, feature(doc_cfg))]
4
5
6
7use std::sync::{Arc, Mutex, RwLock};
8use std::sync::atomic::{
9    AtomicBool,
10    AtomicI8,
11    AtomicI16,
12    AtomicI32,
13    AtomicI64,
14    AtomicIsize,
15    AtomicU8,
16    AtomicU16,
17    AtomicU32,
18    AtomicU64,
19    AtomicUsize,
20    Ordering,
21};
22use std::collections::{
23    BTreeMap,
24    BTreeSet,
25    BinaryHeap,
26    HashMap,
27    HashSet,
28    LinkedList,
29    VecDeque,
30};
31use std::num::{
32    NonZeroI8,
33    NonZeroI16,
34    NonZeroI32,
35    NonZeroI64,
36    NonZeroI128,
37    NonZeroIsize,
38    NonZeroU8,
39    NonZeroU16,
40    NonZeroU32,
41    NonZeroU64,
42    NonZeroU128,
43    NonZeroUsize,
44};
45use std::convert::Infallible;
46use std::borrow::Cow;
47use std::rc::Rc;
48use std::marker::{PhantomData, PhantomPinned};
49use std::time::{Instant, Duration, SystemTime};
50
51
52
53#[cfg(feature = "derive")]
54#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
55pub use get_size_derive::*;
56
57
58
59
60#[cfg(test)]
61mod tests;
62
63
64
65/// Determine the size in bytes an object occupies inside RAM.
66pub trait GetSize: Sized {
67    /// Determines how may bytes this object occupies inside the stack.
68    ///
69    /// The default implementation uses [std::mem::size_of] and should work for almost all types.
70    fn get_stack_size() -> usize {
71        std::mem::size_of::<Self>()
72    }
73
74    /// Determines how many bytes this object occupies inside the heap.
75    ///
76    /// The default implementation returns 0, assuming the object is fully allocated on the stack.
77    /// It must be adjusted as appropriate for objects which hold data inside the heap.
78    fn get_heap_size(&self) -> usize {
79        0
80    }
81
82    /// Determines the total size of the object.
83    ///
84    /// The default implementation simply adds up the result of the other two methods and is not meant
85    /// to be changed.
86    fn get_size(&self) -> usize {
87        Self::get_stack_size() + GetSize::get_heap_size(self)
88    }
89}
90
91
92
93impl GetSize for () {}
94impl GetSize for bool {}
95impl GetSize for u8 {}
96impl GetSize for u16 {}
97impl GetSize for u32 {}
98impl GetSize for u64 {}
99impl GetSize for u128 {}
100impl GetSize for usize {}
101impl GetSize for NonZeroU8 {}
102impl GetSize for NonZeroU16 {}
103impl GetSize for NonZeroU32 {}
104impl GetSize for NonZeroU64 {}
105impl GetSize for NonZeroU128 {}
106impl GetSize for NonZeroUsize {}
107impl GetSize for i8 {}
108impl GetSize for i16 {}
109impl GetSize for i32 {}
110impl GetSize for i64 {}
111impl GetSize for i128 {}
112impl GetSize for isize {}
113impl GetSize for NonZeroI8 {}
114impl GetSize for NonZeroI16 {}
115impl GetSize for NonZeroI32 {}
116impl GetSize for NonZeroI64 {}
117impl GetSize for NonZeroI128 {}
118impl GetSize for NonZeroIsize {}
119impl GetSize for f32 {}
120impl GetSize for f64 {}
121impl GetSize for char {}
122
123impl GetSize for AtomicBool {}
124impl GetSize for AtomicI8 {}
125impl GetSize for AtomicI16 {}
126impl GetSize for AtomicI32 {}
127impl GetSize for AtomicI64 {}
128impl GetSize for AtomicIsize {}
129impl GetSize for AtomicU8 {}
130impl GetSize for AtomicU16 {}
131impl GetSize for AtomicU32 {}
132impl GetSize for AtomicU64 {}
133impl GetSize for AtomicUsize {}
134impl GetSize for Ordering {}
135
136impl GetSize for std::cmp::Ordering {}
137
138impl GetSize for Infallible {}
139impl<T> GetSize for PhantomData<T> {}
140impl GetSize for PhantomPinned {}
141
142impl GetSize for Instant {}
143impl GetSize for Duration {}
144impl GetSize for SystemTime {}
145
146
147
148impl<'a, T> GetSize for Cow<'a, T>
149where
150    T: ToOwned,
151    <T as ToOwned>::Owned: GetSize,
152{
153    fn get_heap_size(&self) -> usize {
154        match self {
155            Self::Borrowed(_borrowed) => 0,
156            Self::Owned(owned) => GetSize::get_heap_size(owned),
157        }
158    }
159}
160
161
162
163macro_rules! impl_size_set {
164    ($name:ident) => {
165        impl<T> GetSize for $name<T> where T: GetSize {
166            fn get_heap_size(&self) -> usize {
167                let mut total = 0;
168
169                for v in self.iter() {
170                    // We assume that value are hold inside the heap.
171                    total += GetSize::get_size(v);
172                }
173
174                let additional: usize = self.capacity() - self.len();
175                total += additional * T::get_stack_size();
176
177                total
178            }
179        }
180    }
181}
182
183macro_rules! impl_size_set_no_capacity {
184    ($name:ident) => {
185        impl<T> GetSize for $name<T> where T: GetSize {
186            fn get_heap_size(&self) -> usize {
187                let mut total = 0;
188
189                for v in self.iter() {
190                    // We assume that value are hold inside the heap.
191                    total += GetSize::get_size(v);
192                }
193
194                total
195            }
196        }
197    }
198}
199
200macro_rules! impl_size_map {
201    ($name:ident) => {
202        impl<K, V> GetSize for $name<K, V> where K: GetSize, V: GetSize {
203            fn get_heap_size(&self) -> usize {
204                let mut total = 0;
205
206                for (k, v) in self.iter() {
207                    // We assume that keys and value are hold inside the heap.
208                    total += GetSize::get_size(k);
209                    total += GetSize::get_size(v);
210                }
211
212                let additional: usize = self.capacity() - self.len();
213                total += additional * K::get_stack_size();
214                total += additional * V::get_stack_size();
215
216                total
217            }
218        }
219    }
220}
221
222macro_rules! impl_size_map_no_capacity {
223    ($name:ident) => {
224        impl<K, V> GetSize for $name<K, V> where K: GetSize, V: GetSize {
225            fn get_heap_size(&self) -> usize {
226                let mut total = 0;
227
228                for (k, v) in self.iter() {
229                    // We assume that keys and value are hold inside the heap.
230                    total += GetSize::get_size(k);
231                    total += GetSize::get_size(v);
232                }
233
234                total
235            }
236        }
237    }
238}
239
240impl_size_map_no_capacity!(BTreeMap);
241impl_size_set_no_capacity!(BTreeSet);
242impl_size_set!(BinaryHeap);
243impl_size_map!(HashMap);
244impl_size_set!(HashSet);
245impl_size_set_no_capacity!(LinkedList);
246impl_size_set!(VecDeque);
247
248impl_size_set!(Vec);
249
250
251
252macro_rules! impl_size_tuple {
253    ($($t:ident, $T:ident),+) => {
254        impl<$($T,)*> GetSize for ($($T,)*)
255        where
256            $(
257                $T: GetSize,
258            )*
259        {
260            fn get_heap_size(&self) -> usize {
261                let mut total = 0;
262
263                let ($($t,)*) = self;
264                $(
265                    total += GetSize::get_heap_size($t);
266                )*
267
268                total
269            }
270        }
271    }
272}
273
274macro_rules! execute_tuple_macro_16 {
275    ($name:ident) => {
276        $name!(v1,V1);
277        $name!(v1,V1,v2,V2);
278        $name!(v1,V1,v2,V2,v3,V3);
279        $name!(v1,V1,v2,V2,v3,V3,v4,V4);
280        $name!(v1,V1,v2,V2,v3,V3,v4,V4,v5,V5);
281        $name!(v1,V1,v2,V2,v3,V3,v4,V4,v5,V5,v6,V6);
282        $name!(v1,V1,v2,V2,v3,V3,v4,V4,v5,V5,v6,V6,v7,V7);
283        $name!(v1,V1,v2,V2,v3,V3,v4,V4,v5,V5,v6,V6,v7,V7,v8,V8);
284        $name!(v1,V1,v2,V2,v3,V3,v4,V4,v5,V5,v6,V6,v7,V7,v8,V8,v9,V9);
285        $name!(v1,V1,v2,V2,v3,V3,v4,V4,v5,V5,v6,V6,v7,V7,v8,V8,v9,V9,v10,V10);
286        $name!(v1,V1,v2,V2,v3,V3,v4,V4,v5,V5,v6,V6,v7,V7,v8,V8,v9,V9,v10,V10,v11,V11);
287        $name!(v1,V1,v2,V2,v3,V3,v4,V4,v5,V5,v6,V6,v7,V7,v8,V8,v9,V9,v10,V10,v11,V11,v12,V12);
288        $name!(v1,V1,v2,V2,v3,V3,v4,V4,v5,V5,v6,V6,v7,V7,v8,V8,v9,V9,v10,V10,v11,V11,v12,V12,v13,V13);
289        $name!(v1,V1,v2,V2,v3,V3,v4,V4,v5,V5,v6,V6,v7,V7,v8,V8,v9,V9,v10,V10,v11,V11,v12,V12,v13,V13,v14,V14);
290        $name!(v1,V1,v2,V2,v3,V3,v4,V4,v5,V5,v6,V6,v7,V7,v8,V8,v9,V9,v10,V10,v11,V11,v12,V12,v13,V13,v14,V14,v15,V15);
291        $name!(v1,V1,v2,V2,v3,V3,v4,V4,v5,V5,v6,V6,v7,V7,v8,V8,v9,V9,v10,V10,v11,V11,v12,V12,v13,V13,v14,V14,v15,V15,v16,V16);
292    }
293}
294
295execute_tuple_macro_16!(impl_size_tuple);
296
297
298
299impl<T, const SIZE: usize> GetSize for [T; SIZE] where T: GetSize {
300    fn get_heap_size(&self) -> usize {
301        let mut total = 0;
302
303        for element in self.iter() {
304            // The array stack size already accounts for the stack size of the elements of the array.
305            total += GetSize::get_heap_size(element);
306        }
307
308        total
309    }
310}
311
312impl<T> GetSize for &[T] where T: GetSize {}
313
314impl<T> GetSize for &T {}
315impl<T> GetSize for &mut T {}
316impl<T> GetSize for *const T {}
317impl<T> GetSize for *mut T {}
318
319impl<T> GetSize for Box<T> where T: GetSize {
320    fn get_heap_size(&self) -> usize {
321        GetSize::get_size(&**self)
322    }
323}
324
325impl<T> GetSize for Rc<T> where T: GetSize {
326    fn get_heap_size(&self) -> usize {
327        GetSize::get_size(&**self)
328    }
329}
330
331impl<T> GetSize for Arc<T> where T: GetSize {
332    fn get_heap_size(&self) -> usize {
333        GetSize::get_size(&**self)
334    }
335}
336
337impl<T> GetSize for Option<T> where T: GetSize {
338    fn get_heap_size(&self) -> usize {
339        match self {
340            // The options stack size already accounts for the values stack size.
341            Some(t) => GetSize::get_heap_size(t),
342            None => 0
343        }
344    }
345}
346
347impl<T, E> GetSize for Result<T, E> where T: GetSize, E: GetSize {
348    fn get_heap_size(&self) -> usize {
349        match self {
350            // The results stack size already accounts for the values stack size.
351            Ok(t) => GetSize::get_heap_size(t),
352            Err(e) => GetSize::get_heap_size(e),
353        }
354    }
355}
356
357impl<T> GetSize for Mutex<T> where T: GetSize {
358    fn get_heap_size(&self) -> usize {
359        // We assume that a Mutex does hold its data at the stack.
360        GetSize::get_heap_size(&*(self.lock().unwrap()))
361    }
362}
363
364impl<T> GetSize for RwLock<T> where T: GetSize {
365    fn get_heap_size(&self) -> usize {
366        // We assume that a RwLock does hold its data at the stack.
367        GetSize::get_heap_size(&*(self.read().unwrap()))
368    }
369}
370
371
372impl GetSize for String {
373    fn get_heap_size(&self) -> usize {
374        self.capacity()
375    }
376}
377
378impl GetSize for &str {}
379
380impl GetSize for std::ffi::CString {
381    fn get_heap_size(&self) -> usize {
382        self.as_bytes_with_nul().len()
383    }
384}
385
386impl GetSize for &std::ffi::CStr {
387    fn get_heap_size(&self) -> usize {
388        self.to_bytes_with_nul().len()
389    }
390}
391
392impl GetSize for std::ffi::OsString {
393    fn get_heap_size(&self) -> usize {
394        self.len()
395    }
396}
397
398impl GetSize for &std::ffi::OsStr {
399    fn get_heap_size(&self) -> usize {
400        self.len()
401    }
402}
403
404impl GetSize for std::fs::DirBuilder {}
405impl GetSize for std::fs::DirEntry {}
406impl GetSize for std::fs::File {}
407impl GetSize for std::fs::FileType {}
408impl GetSize for std::fs::Metadata {}
409impl GetSize for std::fs::OpenOptions {}
410impl GetSize for std::fs::Permissions {}
411impl GetSize for std::fs::ReadDir {}
412
413impl<T> GetSize for std::io::BufReader<T> where T: GetSize {
414    fn get_heap_size(&self) -> usize {
415        let mut total = GetSize::get_heap_size(self.get_ref());
416
417        total += self.capacity();
418
419        total
420    }
421}
422
423impl<T> GetSize for std::io::BufWriter<T> where T: GetSize + std::io::Write {
424    fn get_heap_size(&self) -> usize {
425        let mut total = GetSize::get_heap_size(self.get_ref());
426
427        total += self.capacity();
428
429        total
430    }
431}
432
433impl GetSize for std::path::PathBuf {
434    fn get_heap_size(&self) -> usize {
435        self.capacity()
436    }
437}
438
439impl GetSize for &std::path::Path {}
440
441impl<T> GetSize for Box<[T]> {
442    fn get_heap_size(&self) -> usize {
443        let mut total = 0;
444        for item in self.iter() {
445            total += item.get_size()
446        }
447
448        total
449    }
450}