get_size2/
lib.rs

1#![doc = include_str!("./lib.md")]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3
4use std::borrow::Cow;
5use std::cell::RefCell;
6use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque};
7use std::convert::Infallible;
8use std::marker::{PhantomData, PhantomPinned};
9use std::num::{
10    NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize, NonZeroU8,
11    NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
12};
13use std::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
14use std::rc::{Rc, Weak as RcWeak};
15use std::sync::atomic::{
16    AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize, AtomicU8, AtomicU16,
17    AtomicU32, AtomicU64, AtomicUsize, Ordering,
18};
19use std::sync::{Arc, Mutex, OnceLock, RwLock, Weak as ArcWeak};
20use std::time::{Duration, Instant, SystemTime};
21
22#[cfg(feature = "derive")]
23#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
24pub use get_size_derive2::*;
25
26mod tracker;
27pub use tracker::*;
28#[cfg(test)]
29mod test;
30
31/// Determines how many bytes the object occupies inside the heap.
32pub fn heap_size<T: GetSize>(value: &T) -> usize {
33    value.get_heap_size()
34}
35
36/// Determine the size in bytes an object occupies inside RAM.
37pub trait GetSize: Sized {
38    /// Determines how may bytes this object occupies inside the stack.
39    ///
40    /// The default implementation uses [`std::mem::size_of`] and should work for almost all types.
41    #[must_use]
42    fn get_stack_size() -> usize {
43        std::mem::size_of::<Self>()
44    }
45
46    /// Determines how many bytes this object occupies inside the heap.
47    ///
48    /// The default implementation simply delegates to [`get_heap_size_with_tracker`](Self::get_heap_size_with_tracker)
49    /// with a noop tracker. This method is not meant to be implemented directly, and only exists for convenience.
50    fn get_heap_size(&self) -> usize {
51        let tracker = NoTracker::new(true);
52        Self::get_heap_size_with_tracker(self, tracker).0
53    }
54
55    /// Determines how many bytes this object occupies inside the heap while using a `tracker`.
56    ///
57    /// The default implementation returns 0, assuming the object is fully allocated on the stack.
58    /// It must be adjusted as appropriate for objects which hold data inside the heap.
59    fn get_heap_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
60        (0, tracker)
61    }
62
63    /// Determines the total size of the object.
64    ///
65    /// The default implementation simply adds up the results of [`get_stack_size`](Self::get_stack_size)
66    /// and [`get_heap_size`](Self::get_heap_size) and is not meant to be changed.
67    fn get_size(&self) -> usize {
68        Self::get_stack_size() + GetSize::get_heap_size(self)
69    }
70
71    /// Determines the total size of the object while using a `tracker`.
72    ///
73    /// The default implementation simply adds up the results of [`get_stack_size`](Self::get_stack_size)
74    /// and [`get_heap_size_with_tracker`](Self::get_heap_size_with_tracker) and is not meant to
75    /// be changed.
76    fn get_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
77        let stack_size = Self::get_stack_size();
78        let (heap_size, tracker) = Self::get_heap_size_with_tracker(self, tracker);
79        (stack_size + heap_size, tracker)
80    }
81}
82
83impl GetSize for () {}
84impl GetSize for bool {}
85impl GetSize for u8 {}
86impl GetSize for u16 {}
87impl GetSize for u32 {}
88impl GetSize for u64 {}
89impl GetSize for u128 {}
90impl GetSize for usize {}
91impl GetSize for NonZeroU8 {}
92impl GetSize for NonZeroU16 {}
93impl GetSize for NonZeroU32 {}
94impl GetSize for NonZeroU64 {}
95impl GetSize for NonZeroU128 {}
96impl GetSize for NonZeroUsize {}
97impl GetSize for i8 {}
98impl GetSize for i16 {}
99impl GetSize for i32 {}
100impl GetSize for i64 {}
101impl GetSize for i128 {}
102impl GetSize for isize {}
103impl GetSize for NonZeroI8 {}
104impl GetSize for NonZeroI16 {}
105impl GetSize for NonZeroI32 {}
106impl GetSize for NonZeroI64 {}
107impl GetSize for NonZeroI128 {}
108impl GetSize for NonZeroIsize {}
109impl GetSize for f32 {}
110impl GetSize for f64 {}
111impl GetSize for char {}
112
113impl GetSize for AtomicBool {}
114impl GetSize for AtomicI8 {}
115impl GetSize for AtomicI16 {}
116impl GetSize for AtomicI32 {}
117impl GetSize for AtomicI64 {}
118impl GetSize for AtomicIsize {}
119impl GetSize for AtomicU8 {}
120impl GetSize for AtomicU16 {}
121impl GetSize for AtomicU32 {}
122impl GetSize for AtomicU64 {}
123impl GetSize for AtomicUsize {}
124impl GetSize for Ordering {}
125
126impl GetSize for std::cmp::Ordering {}
127
128impl GetSize for Infallible {}
129impl<T> GetSize for PhantomData<T> {}
130impl GetSize for PhantomPinned {}
131
132impl GetSize for Instant {}
133impl GetSize for Duration {}
134impl GetSize for SystemTime {}
135
136/// This macro is similar to the derive macro; Generate a `GetSize` impl that
137/// adds the heap sizes of the fields that are specified. However, since we want
138/// to implement this also for third-party types where we cannot add the derive
139/// macro, we go this way.
140///
141/// # Examples
142/// ```ignore
143/// impl_sum_of_fields!(Range, start, end);
144/// impl_sum_of_fields!(Person, name, address, phone);
145/// ```
146macro_rules! impl_sum_of_fields {
147    ($name:ident, $($field:ident),+) => {
148        impl<I: GetSize> GetSize for $name<I> {
149            #[allow(unused_mut, reason = "the macro supports a variadic number of elements")]
150            #[expect(clippy::allow_attributes, reason = "the macro supports a variadic number of elements")]
151            fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, mut tracker: Tr) -> (usize, Tr) {
152                let mut size = 0;
153                let mut elem_size;
154
155                $(
156                    (elem_size, tracker) = self.$field.get_heap_size_with_tracker(tracker);
157                    size += elem_size;
158                )+
159
160                (size, tracker)
161            }
162        }
163    };
164}
165
166impl_sum_of_fields!(Range, start, end);
167impl_sum_of_fields!(RangeFrom, start);
168impl_sum_of_fields!(RangeTo, end);
169impl_sum_of_fields!(RangeToInclusive, end);
170
171impl GetSize for RangeFull {}
172
173impl<I: GetSize> GetSize for RangeInclusive<I> {
174    #[inline]
175    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
176        let (start_size, tracker) = (*self.start()).get_heap_size_with_tracker(tracker);
177        let (end_size, tracker) = (*self.end()).get_heap_size_with_tracker(tracker);
178        (start_size + end_size, tracker)
179    }
180}
181
182impl<T> GetSize for Cow<'_, T>
183where
184    T: ToOwned + ?Sized,
185    T::Owned: GetSize,
186{
187    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
188        match self {
189            Self::Borrowed(_borrowed) => (0, tracker),
190            Self::Owned(owned) => <T::Owned>::get_heap_size_with_tracker(owned, tracker),
191        }
192    }
193}
194
195macro_rules! impl_size_set {
196    ($name:ident) => {
197        impl<T> GetSize for $name<T>
198        where
199            T: GetSize,
200        {
201            fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
202                let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), elem| {
203                    let (elem_size, tracker) = T::get_heap_size_with_tracker(elem, tracker);
204                    (size + elem_size, tracker)
205                });
206
207                let allocation_size = self.capacity() * T::get_stack_size();
208                (size + allocation_size, tracker)
209            }
210        }
211    };
212}
213
214macro_rules! impl_size_set_no_capacity {
215    ($name:ident) => {
216        impl<T> GetSize for $name<T>
217        where
218            T: GetSize,
219        {
220            fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
221                let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), elem| {
222                    // We assume that value are hold inside the heap.
223                    let (elem_size, tracker) = T::get_size_with_tracker(elem, tracker);
224                    (size + elem_size, tracker)
225                });
226
227                (size, tracker)
228            }
229        }
230    };
231}
232
233impl_size_set_no_capacity!(BTreeSet);
234impl_size_set!(BinaryHeap);
235impl_size_set_no_capacity!(LinkedList);
236impl_size_set!(VecDeque);
237
238impl<K, V> GetSize for BTreeMap<K, V>
239where
240    K: GetSize,
241    V: GetSize,
242{
243    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
244        self.iter()
245            .fold((0, tracker), |(size, tracker), (key, value)| {
246                let (key_size, tracker) = K::get_size_with_tracker(key, tracker);
247                let (value_size, tracker) = V::get_size_with_tracker(value, tracker);
248                (size + key_size + value_size, tracker)
249            })
250    }
251}
252
253impl<K, V, S: ::std::hash::BuildHasher> GetSize for HashMap<K, V, S>
254where
255    K: GetSize,
256    V: GetSize,
257{
258    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
259        let (size, tracker) = self
260            .iter()
261            .fold((0, tracker), |(size, tracker), (key, value)| {
262                let (key_size, tracker) = K::get_heap_size_with_tracker(key, tracker);
263                let (value_size, tracker) = V::get_heap_size_with_tracker(value, tracker);
264                (size + key_size + value_size, tracker)
265            });
266
267        let allocation_size = self.capacity() * <(K, V)>::get_stack_size();
268        (size + allocation_size, tracker)
269    }
270}
271
272impl<T, S: ::std::hash::BuildHasher> GetSize for HashSet<T, S>
273where
274    T: GetSize,
275{
276    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
277        let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), elem| {
278            let (elem_size, tracker) = T::get_heap_size_with_tracker(elem, tracker);
279            (size + elem_size, tracker)
280        });
281
282        let allocation_size = self.capacity() * T::get_stack_size();
283        (size + allocation_size, tracker)
284    }
285}
286
287impl_size_set!(Vec);
288
289macro_rules! impl_size_tuple {
290    ($($t:ident, $T:ident),+) => {
291        impl<$($T,)*> GetSize for ($($T,)*)
292        where
293            $(
294                $T: GetSize,
295            )*
296        {
297            #[allow(unused_mut, reason = "the macro supports a variadic number of elements")]
298            #[expect(clippy::allow_attributes, reason = "the macro supports a variadic number of elements")]
299            fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, mut tracker: Tr) -> (usize, Tr) {
300                let mut total = 0;
301                let mut elem_size;
302
303                let ($($t,)*) = self;
304                $(
305                    (elem_size, tracker) = <$T>::get_heap_size_with_tracker($t, tracker);
306                    total += elem_size;
307                )*
308
309                (total, tracker)
310            }
311        }
312    }
313}
314
315macro_rules! execute_tuple_macro_16 {
316    ($name:ident) => {
317        $name!(v1, V1);
318        $name!(v1, V1, v2, V2);
319        $name!(v1, V1, v2, V2, v3, V3);
320        $name!(v1, V1, v2, V2, v3, V3, v4, V4);
321        $name!(v1, V1, v2, V2, v3, V3, v4, V4, v5, V5);
322        $name!(v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6);
323        $name!(v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7);
324        $name!(
325            v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8
326        );
327        $name!(
328            v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9
329        );
330        $name!(
331            v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10
332        );
333        $name!(
334            v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
335            V11
336        );
337        $name!(
338            v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
339            V11, v12, V12
340        );
341        $name!(
342            v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
343            V11, v12, V12, v13, V13
344        );
345        $name!(
346            v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
347            V11, v12, V12, v13, V13, v14, V14
348        );
349        $name!(
350            v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
351            V11, v12, V12, v13, V13, v14, V14, v15, V15
352        );
353        $name!(
354            v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
355            V11, v12, V12, v13, V13, v14, V14, v15, V15, v16, V16
356        );
357    };
358}
359
360execute_tuple_macro_16!(impl_size_tuple);
361
362impl<T, const SIZE: usize> GetSize for [T; SIZE]
363where
364    T: GetSize,
365{
366    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
367        self.iter().fold((0, tracker), |(size, tracker), element| {
368            // The array stack size already accounts for the stack size of the elements of the array.
369            let (elem_size, tracker) = T::get_heap_size_with_tracker(element, tracker);
370            (size + elem_size, tracker)
371        })
372    }
373}
374
375impl<T> GetSize for &[T] where T: GetSize {}
376
377impl<T> GetSize for &T {}
378impl<T> GetSize for &mut T {}
379impl<T> GetSize for *const T {}
380impl<T> GetSize for *mut T {}
381
382impl<T> GetSize for Box<T>
383where
384    T: GetSize,
385{
386    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
387        T::get_size_with_tracker(&**self, tracker)
388    }
389}
390
391impl<T> GetSize for Rc<T>
392where
393    T: GetSize,
394{
395    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, mut tracker: Tr) -> (usize, Tr) {
396        if tracker.track(Rc::as_ptr(self)) {
397            T::get_size_with_tracker(&**self, tracker)
398        } else {
399            (0, tracker)
400        }
401    }
402}
403
404impl<T> GetSize for RcWeak<T> {}
405
406impl<T> GetSize for Arc<T>
407where
408    T: GetSize,
409{
410    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, mut tracker: Tr) -> (usize, Tr) {
411        if tracker.track(Arc::as_ptr(self)) {
412            T::get_size_with_tracker(&**self, tracker)
413        } else {
414            (0, tracker)
415        }
416    }
417}
418
419impl<T> GetSize for ArcWeak<T> {}
420
421impl<T> GetSize for Option<T>
422where
423    T: GetSize,
424{
425    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
426        match self {
427            None => (0, tracker),
428            Some(value) => T::get_heap_size_with_tracker(value, tracker),
429        }
430    }
431}
432
433impl<T, E> GetSize for Result<T, E>
434where
435    T: GetSize,
436    E: GetSize,
437{
438    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
439        // The results stack size already accounts for the values stack size.
440        match self {
441            Ok(value) => T::get_heap_size_with_tracker(value, tracker),
442            Err(err) => E::get_heap_size_with_tracker(err, tracker),
443        }
444    }
445}
446
447impl<T> GetSize for Mutex<T>
448where
449    T: GetSize,
450{
451    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
452        // We assume that a `Mutex` holds its data at the stack.
453        T::get_heap_size_with_tracker(&*(self.lock().expect("Mutex is poisoned")), tracker)
454    }
455}
456
457impl<T> GetSize for RwLock<T>
458where
459    T: GetSize,
460{
461    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
462        // We assume that a `RwLock` holds its data at the stack.
463        T::get_heap_size_with_tracker(&*(self.read().expect("RwLock is poisoned")), tracker)
464    }
465}
466
467impl<T> GetSize for RefCell<T>
468where
469    T: GetSize,
470{
471    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
472        // We assume that a `RefCell` holds its data at the stack.
473        // Use try_borrow to avoid panicking if the RefCell is already mutably borrowed
474        match self.try_borrow() {
475            Ok(borrowed) => T::get_heap_size_with_tracker(&*borrowed, tracker),
476            Err(_) => {
477                // If the RefCell is already mutably borrowed, we cannot safely access it.
478                // Return 0 for heap size to avoid panic, though this is a rare edge case.
479                (0, tracker)
480            }
481        }
482    }
483}
484
485impl<T> GetSize for OnceLock<T>
486where
487    T: GetSize,
488{
489    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
490        // We assume that a `OnceLock` holds its data at the stack.
491        match self.get() {
492            None => (0, tracker),
493            Some(value) => T::get_heap_size_with_tracker(value, tracker),
494        }
495    }
496}
497
498impl GetSize for String {
499    fn get_heap_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
500        (self.capacity(), tracker)
501    }
502}
503
504impl GetSize for &str {}
505
506impl GetSize for std::ffi::CString {
507    fn get_heap_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
508        (self.as_bytes_with_nul().len(), tracker)
509    }
510}
511
512impl GetSize for &std::ffi::CStr {
513    fn get_heap_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
514        (self.to_bytes_with_nul().len(), tracker)
515    }
516}
517
518impl GetSize for std::ffi::OsString {
519    fn get_heap_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
520        (self.len(), tracker)
521    }
522}
523
524impl GetSize for &std::ffi::OsStr {
525    fn get_heap_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
526        (self.len(), tracker)
527    }
528}
529
530impl GetSize for std::fs::DirBuilder {}
531impl GetSize for std::fs::DirEntry {}
532impl GetSize for std::fs::File {}
533impl GetSize for std::fs::FileType {}
534impl GetSize for std::fs::Metadata {}
535impl GetSize for std::fs::OpenOptions {}
536impl GetSize for std::fs::Permissions {}
537impl GetSize for std::fs::ReadDir {}
538
539impl<T> GetSize for std::io::BufReader<T>
540where
541    T: GetSize,
542{
543    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
544        let (total, tracker) = T::get_heap_size_with_tracker(self.get_ref(), tracker);
545        (total + self.capacity(), tracker)
546    }
547}
548
549impl<T> GetSize for std::io::BufWriter<T>
550where
551    T: GetSize + std::io::Write,
552{
553    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
554        let (total, tracker) = T::get_heap_size_with_tracker(self.get_ref(), tracker);
555        (total + self.capacity(), tracker)
556    }
557}
558
559impl GetSize for std::path::PathBuf {
560    fn get_heap_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
561        (self.capacity(), tracker)
562    }
563}
564
565impl GetSize for &std::path::Path {}
566
567impl<T> GetSize for Box<[T]>
568where
569    T: GetSize,
570{
571    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
572        let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), element| {
573            let (elem_size, tracker) = T::get_heap_size_with_tracker(element, tracker);
574            (size + elem_size, tracker)
575        });
576
577        let allocation_size = self.len() * T::get_stack_size();
578        (size + allocation_size, tracker)
579    }
580}
581
582impl GetSize for Box<str> {
583    fn get_heap_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
584        (self.len(), tracker)
585    }
586}
587
588impl<T> GetSize for Rc<[T]>
589where
590    T: GetSize,
591{
592    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
593        let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), element| {
594            let (elem_size, tracker) = T::get_heap_size_with_tracker(element, tracker);
595            (size + elem_size, tracker)
596        });
597
598        let allocation_size = self.len() * T::get_stack_size();
599        (size + allocation_size, tracker)
600    }
601}
602
603impl GetSize for Rc<str> {
604    fn get_heap_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
605        (self.len(), tracker)
606    }
607}
608
609impl<T> GetSize for Arc<[T]>
610where
611    T: GetSize,
612{
613    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
614        let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), element| {
615            let (elem_size, tracker) = T::get_heap_size_with_tracker(element, tracker);
616            (size + elem_size, tracker)
617        });
618
619        let allocation_size = self.len() * T::get_stack_size();
620        (size + allocation_size, tracker)
621    }
622}
623
624impl GetSize for Arc<str> {
625    fn get_heap_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
626        (self.len(), tracker)
627    }
628}
629
630#[cfg(feature = "chrono")]
631mod chrono {
632    use crate::{GetSize, GetSizeTracker};
633
634    impl GetSize for chrono::NaiveDate {}
635    impl GetSize for chrono::NaiveTime {}
636    impl GetSize for chrono::NaiveDateTime {}
637    impl GetSize for chrono::Utc {}
638    impl GetSize for chrono::FixedOffset {}
639    impl GetSize for chrono::TimeDelta {}
640
641    impl<Tz: chrono::TimeZone> GetSize for chrono::DateTime<Tz>
642    where
643        Tz::Offset: GetSize,
644    {
645        fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
646            <Tz::Offset>::get_heap_size_with_tracker(self.offset(), tracker)
647        }
648    }
649}
650
651#[cfg(feature = "chrono-tz")]
652impl GetSize for chrono_tz::TzOffset {}
653
654#[cfg(feature = "url")]
655impl GetSize for url::Url {
656    fn get_heap_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
657        (self.as_str().len(), tracker)
658    }
659}
660
661#[cfg(feature = "bytes")]
662impl GetSize for bytes::Bytes {
663    fn get_heap_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
664        (self.len(), tracker)
665    }
666}
667
668#[cfg(feature = "bytes")]
669impl GetSize for bytes::BytesMut {
670    fn get_heap_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
671        (self.len(), tracker)
672    }
673}
674
675#[cfg(feature = "hashbrown")]
676impl<K, V, H> GetSize for hashbrown::HashMap<K, V, H>
677where
678    K: GetSize + Eq + std::hash::Hash,
679    V: GetSize,
680    H: std::hash::BuildHasher,
681{
682    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
683        let (size, tracker) = self
684            .iter()
685            .fold((0, tracker), |(size, tracker), (key, value)| {
686                let (key_size, tracker) = K::get_heap_size_with_tracker(key, tracker);
687                let (value_size, tracker) = V::get_heap_size_with_tracker(value, tracker);
688                (size + key_size + value_size, tracker)
689            });
690
691        (size + self.allocation_size(), tracker)
692    }
693}
694
695#[cfg(feature = "hashbrown")]
696impl<T, H> GetSize for hashbrown::HashSet<T, H>
697where
698    T: GetSize + Eq + std::hash::Hash,
699    H: std::hash::BuildHasher,
700{
701    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
702        let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), element| {
703            let (elem_size, tracker) = T::get_heap_size_with_tracker(element, tracker);
704            (size + elem_size, tracker)
705        });
706
707        (size + self.allocation_size(), tracker)
708    }
709}
710
711#[cfg(feature = "hashbrown")]
712impl<T> GetSize for hashbrown::HashTable<T>
713where
714    T: GetSize,
715{
716    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
717        let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), element| {
718            let (elem_size, tracker) = T::get_heap_size_with_tracker(element, tracker);
719            (size + elem_size, tracker)
720        });
721
722        (size + self.allocation_size(), tracker)
723    }
724}
725
726#[cfg(feature = "smallvec")]
727impl<A: smallvec::Array> GetSize for smallvec::SmallVec<A>
728where
729    A::Item: GetSize,
730{
731    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
732        let (mut size, tracker) = self.iter().fold((0, tracker), |(size, tracker), element| {
733            let (elem_size, tracker) = <A::Item>::get_heap_size_with_tracker(element, tracker);
734            (size + elem_size, tracker)
735        });
736
737        if self.len() > self.inline_size() {
738            size += self.capacity() * <A::Item>::get_stack_size();
739        }
740
741        (size, tracker)
742    }
743}
744
745#[cfg(feature = "thin-vec")]
746impl<T> GetSize for thin_vec::ThinVec<T>
747where
748    T: GetSize,
749{
750    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
751        if self.capacity() == 0 {
752            // If it's the singleton we might not be a heap pointer.
753            return (0, tracker);
754        }
755
756        let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), element| {
757            let (elem_size, tracker) = T::get_heap_size_with_tracker(element, tracker);
758            (size + elem_size, tracker)
759        });
760
761        let metadata_size = std::mem::size_of::<usize>() * 2; // Capacity and length.
762        let allocation_size = self.capacity() * T::get_stack_size();
763        (size + metadata_size + allocation_size, tracker)
764    }
765}
766
767#[cfg(feature = "compact-str")]
768impl GetSize for compact_str::CompactString {
769    fn get_heap_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
770        let size = if self.is_heap_allocated() {
771            self.capacity()
772        } else {
773            0
774        };
775
776        (size, tracker)
777    }
778}
779
780#[cfg(feature = "indexmap")]
781impl<K, V, S> GetSize for indexmap::IndexMap<K, V, S>
782where
783    K: GetSize,
784    V: GetSize,
785    S: std::hash::BuildHasher,
786{
787    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
788        let (size, tracker) = self
789            .iter()
790            .fold((0, tracker), |(size, tracker), (key, value)| {
791                let (key_size, tracker) = K::get_heap_size_with_tracker(key, tracker);
792                let (value_size, tracker) = V::get_heap_size_with_tracker(value, tracker);
793                (size + key_size + value_size, tracker)
794            });
795
796        let allocation_size = self.capacity() * <(K, V)>::get_stack_size();
797        (size + allocation_size, tracker)
798    }
799}
800
801#[cfg(feature = "indexmap")]
802impl<T, S> GetSize for indexmap::IndexSet<T, S>
803where
804    T: GetSize,
805{
806    fn get_heap_size_with_tracker<Tr: GetSizeTracker>(&self, tracker: Tr) -> (usize, Tr) {
807        let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), element| {
808            let (elem_size, tracker) = T::get_heap_size_with_tracker(element, tracker);
809            (size + elem_size, tracker)
810        });
811
812        let allocation_size = self.capacity() * T::get_stack_size();
813        (size + allocation_size, tracker)
814    }
815}