get_size2/
lib.rs

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