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
30pub fn heap_size<T: GetSize>(value: &T) -> usize {
32 value.get_heap_size()
33}
34
35pub trait GetSize: Sized {
37 #[must_use]
41 fn get_stack_size() -> usize {
42 std::mem::size_of::<Self>()
43 }
44
45 fn get_heap_size(&self) -> usize {
50 0
51 }
52
53 fn get_heap_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
58 (GetSize::get_heap_size(self), tracker)
59 }
60
61 fn get_size(&self) -> usize {
66 Self::get_stack_size() + GetSize::get_heap_size(self)
67 }
68
69 fn get_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
75 let stack_size = Self::get_stack_size();
76 let (heap_size, tracker) = GetSize::get_heap_size_with_tracker(self, tracker);
77
78 let total = stack_size + heap_size;
79
80 (total, tracker)
81 }
82}
83
84impl GetSize for () {}
85impl GetSize for bool {}
86impl GetSize for u8 {}
87impl GetSize for u16 {}
88impl GetSize for u32 {}
89impl GetSize for u64 {}
90impl GetSize for u128 {}
91impl GetSize for usize {}
92impl GetSize for NonZeroU8 {}
93impl GetSize for NonZeroU16 {}
94impl GetSize for NonZeroU32 {}
95impl GetSize for NonZeroU64 {}
96impl GetSize for NonZeroU128 {}
97impl GetSize for NonZeroUsize {}
98impl GetSize for i8 {}
99impl GetSize for i16 {}
100impl GetSize for i32 {}
101impl GetSize for i64 {}
102impl GetSize for i128 {}
103impl GetSize for isize {}
104impl GetSize for NonZeroI8 {}
105impl GetSize for NonZeroI16 {}
106impl GetSize for NonZeroI32 {}
107impl GetSize for NonZeroI64 {}
108impl GetSize for NonZeroI128 {}
109impl GetSize for NonZeroIsize {}
110impl GetSize for f32 {}
111impl GetSize for f64 {}
112impl GetSize for char {}
113
114impl GetSize for AtomicBool {}
115impl GetSize for AtomicI8 {}
116impl GetSize for AtomicI16 {}
117impl GetSize for AtomicI32 {}
118impl GetSize for AtomicI64 {}
119impl GetSize for AtomicIsize {}
120impl GetSize for AtomicU8 {}
121impl GetSize for AtomicU16 {}
122impl GetSize for AtomicU32 {}
123impl GetSize for AtomicU64 {}
124impl GetSize for AtomicUsize {}
125impl GetSize for Ordering {}
126
127impl GetSize for std::cmp::Ordering {}
128
129impl GetSize for Infallible {}
130impl<T> GetSize for PhantomData<T> {}
131impl GetSize for PhantomPinned {}
132
133impl GetSize for Instant {}
134impl GetSize for Duration {}
135impl GetSize for SystemTime {}
136
137macro_rules! impl_sum_of_fields {
148 ($name:ident, $($field:ident),+) => {
149 impl<I: GetSize> GetSize for $name<I> {
150 #[inline]
151 fn get_heap_size(&self) -> usize {
152 0 $(+ self.$field.get_heap_size())+
153 }
154 }
155 };
156}
157
158impl_sum_of_fields!(Range, start, end);
159impl_sum_of_fields!(RangeFrom, start);
160impl_sum_of_fields!(RangeTo, end);
161impl_sum_of_fields!(RangeToInclusive, end);
162impl GetSize for RangeFull {}
163
164impl<I: GetSize> GetSize for RangeInclusive<I> {
165 #[inline]
166 fn get_heap_size(&self) -> usize {
167 (*self.start()).get_heap_size() + (*self.end()).get_heap_size()
169 }
170}
171
172impl<T> GetSize for Cow<'_, T>
173where
174 T: ToOwned + ?Sized,
175 <T as ToOwned>::Owned: GetSize,
176{
177 fn get_heap_size(&self) -> usize {
178 match self {
179 Self::Borrowed(_borrowed) => 0,
180 Self::Owned(owned) => GetSize::get_heap_size(owned),
181 }
182 }
183}
184
185macro_rules! impl_size_set {
186 ($name:ident) => {
187 impl<T> GetSize for $name<T>
188 where
189 T: GetSize,
190 {
191 fn get_heap_size(&self) -> usize {
192 let mut total = 0;
193
194 for v in self.iter() {
195 total += GetSize::get_size(v);
197 }
198
199 let additional: usize = self.capacity() - self.len();
200 total += additional * T::get_stack_size();
201
202 total
203 }
204 }
205 };
206}
207
208macro_rules! impl_size_set_no_capacity {
209 ($name:ident) => {
210 impl<T> GetSize for $name<T>
211 where
212 T: GetSize,
213 {
214 fn get_heap_size(&self) -> usize {
215 let mut total = 0;
216
217 for v in self.iter() {
218 total += GetSize::get_size(v);
220 }
221
222 total
223 }
224 }
225 };
226}
227
228impl_size_set_no_capacity!(BTreeSet);
229impl_size_set!(BinaryHeap);
230impl_size_set_no_capacity!(LinkedList);
231impl_size_set!(VecDeque);
232
233impl<K, V> GetSize for BTreeMap<K, V>
234where
235 K: GetSize,
236 V: GetSize,
237{
238 fn get_heap_size(&self) -> usize {
239 let mut total = 0;
240 for (k, v) in self {
241 total += GetSize::get_size(k);
242 total += GetSize::get_size(v);
243 }
244 total
245 }
246}
247
248impl<K, V, S: ::std::hash::BuildHasher> GetSize for HashMap<K, V, S>
249where
250 K: GetSize,
251 V: GetSize,
252{
253 fn get_heap_size(&self) -> usize {
254 let mut total = 0;
255 for (k, v) in self {
256 total += GetSize::get_heap_size(k);
257 total += GetSize::get_heap_size(v);
258 }
259 total += self.capacity() * <(K, V)>::get_stack_size();
260 total
261 }
262}
263
264impl<T, S: ::std::hash::BuildHasher> GetSize for HashSet<T, S>
265where
266 T: GetSize,
267{
268 fn get_heap_size(&self) -> usize {
269 let mut total = 0;
270 for v in self {
271 total += GetSize::get_size(v);
272 }
273 let additional: usize = self.capacity() - self.len();
274 total += additional * T::get_stack_size();
275 total
276 }
277}
278
279impl_size_set!(Vec);
280
281macro_rules! impl_size_tuple {
282 ($($t:ident, $T:ident),+) => {
283 impl<$($T,)*> GetSize for ($($T,)*)
284 where
285 $(
286 $T: GetSize,
287 )*
288 {
289 fn get_heap_size(&self) -> usize {
290 let mut total = 0;
291
292 let ($($t,)*) = self;
293 $(
294 total += GetSize::get_heap_size($t);
295 )*
296
297 total
298 }
299 }
300 }
301}
302
303macro_rules! execute_tuple_macro_16 {
304 ($name:ident) => {
305 $name!(v1, V1);
306 $name!(v1, V1, v2, V2);
307 $name!(v1, V1, v2, V2, v3, V3);
308 $name!(v1, V1, v2, V2, v3, V3, v4, V4);
309 $name!(v1, V1, v2, V2, v3, V3, v4, V4, v5, V5);
310 $name!(v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6);
311 $name!(v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7);
312 $name!(
313 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8
314 );
315 $name!(
316 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9
317 );
318 $name!(
319 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10
320 );
321 $name!(
322 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
323 V11
324 );
325 $name!(
326 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
327 V11, v12, V12
328 );
329 $name!(
330 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
331 V11, v12, V12, v13, V13
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, v12, V12, v13, V13, v14, V14
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, v13, V13, v14, V14, v15, V15
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, v14, V14, v15, V15, v16, V16
344 );
345 };
346}
347
348execute_tuple_macro_16!(impl_size_tuple);
349
350impl<T, const SIZE: usize> GetSize for [T; SIZE]
351where
352 T: GetSize,
353{
354 fn get_heap_size(&self) -> usize {
355 let mut total = 0;
356
357 for element in self {
358 total += GetSize::get_heap_size(element);
360 }
361
362 total
363 }
364}
365
366impl<T> GetSize for &[T] where T: GetSize {}
367
368impl<T> GetSize for &T {}
369impl<T> GetSize for &mut T {}
370impl<T> GetSize for *const T {}
371impl<T> GetSize for *mut T {}
372
373impl<T> GetSize for Box<T>
374where
375 T: GetSize,
376{
377 fn get_heap_size(&self) -> usize {
378 GetSize::get_size(&**self)
379 }
380}
381
382impl<T> GetSize for Rc<T>
383where
384 T: GetSize,
385{
386 fn get_heap_size(&self) -> usize {
387 let tracker = StandardTracker::default();
388
389 let (total, _) = GetSize::get_heap_size_with_tracker(self, tracker);
390
391 total
392 }
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 GetSize::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(&self) -> usize {
410 let tracker = StandardTracker::default();
411
412 let (total, _) = GetSize::get_heap_size_with_tracker(self, tracker);
413
414 total
415 }
416
417 fn get_heap_size_with_tracker<TR: GetSizeTracker>(&self, mut tracker: TR) -> (usize, TR) {
418 if tracker.track(Arc::as_ptr(self)) {
419 GetSize::get_size_with_tracker(&**self, tracker)
420 } else {
421 (0, tracker)
422 }
423 }
424}
425
426impl<T> GetSize for ArcWeak<T> {}
427
428impl<T> GetSize for Option<T>
429where
430 T: GetSize,
431{
432 fn get_heap_size(&self) -> usize {
433 self.as_ref().map_or(0, |t| GetSize::get_heap_size(t))
434 }
435}
436
437impl<T, E> GetSize for Result<T, E>
438where
439 T: GetSize,
440 E: GetSize,
441{
442 fn get_heap_size(&self) -> usize {
443 match self {
444 Ok(t) => GetSize::get_heap_size(t),
446 Err(e) => GetSize::get_heap_size(e),
447 }
448 }
449}
450
451impl<T> GetSize for Mutex<T>
452where
453 T: GetSize,
454{
455 fn get_heap_size(&self) -> usize {
456 GetSize::get_heap_size(&*(self.lock().expect("Mutex is poisoned")))
458 }
459}
460
461impl<T> GetSize for RwLock<T>
462where
463 T: GetSize,
464{
465 fn get_heap_size(&self) -> usize {
466 GetSize::get_heap_size(&*(self.read().expect("RwLock is poisoned")))
468 }
469}
470
471impl<T> GetSize for OnceLock<T>
472where
473 T: GetSize,
474{
475 fn get_heap_size(&self) -> usize {
476 match self.get() {
478 None => 0,
479 Some(value) => GetSize::get_heap_size(value),
480 }
481 }
482}
483
484impl GetSize for String {
485 fn get_heap_size(&self) -> usize {
486 self.capacity()
487 }
488}
489
490impl GetSize for &str {}
491
492impl GetSize for std::ffi::CString {
493 fn get_heap_size(&self) -> usize {
494 self.as_bytes_with_nul().len()
495 }
496}
497
498impl GetSize for &std::ffi::CStr {
499 fn get_heap_size(&self) -> usize {
500 self.to_bytes_with_nul().len()
501 }
502}
503
504impl GetSize for std::ffi::OsString {
505 fn get_heap_size(&self) -> usize {
506 self.len()
507 }
508}
509
510impl GetSize for &std::ffi::OsStr {
511 fn get_heap_size(&self) -> usize {
512 self.len()
513 }
514}
515
516impl GetSize for std::fs::DirBuilder {}
517impl GetSize for std::fs::DirEntry {}
518impl GetSize for std::fs::File {}
519impl GetSize for std::fs::FileType {}
520impl GetSize for std::fs::Metadata {}
521impl GetSize for std::fs::OpenOptions {}
522impl GetSize for std::fs::Permissions {}
523impl GetSize for std::fs::ReadDir {}
524
525impl<T> GetSize for std::io::BufReader<T>
526where
527 T: GetSize,
528{
529 fn get_heap_size(&self) -> usize {
530 let mut total = GetSize::get_heap_size(self.get_ref());
531
532 total += self.capacity();
533
534 total
535 }
536}
537
538impl<T> GetSize for std::io::BufWriter<T>
539where
540 T: GetSize + std::io::Write,
541{
542 fn get_heap_size(&self) -> usize {
543 let mut total = GetSize::get_heap_size(self.get_ref());
544
545 total += self.capacity();
546
547 total
548 }
549}
550
551impl GetSize for std::path::PathBuf {
552 fn get_heap_size(&self) -> usize {
553 self.capacity()
554 }
555}
556
557impl GetSize for &std::path::Path {}
558
559impl<T> GetSize for Box<[T]>
560where
561 T: GetSize,
562{
563 fn get_heap_size(&self) -> usize {
564 self.iter().map(GetSize::get_size).sum()
565 }
566}
567
568impl GetSize for Box<str> {
569 fn get_heap_size(&self) -> usize {
570 self.len()
571 }
572}
573
574impl<T> GetSize for Rc<[T]>
575where
576 T: GetSize,
577{
578 fn get_heap_size(&self) -> usize {
579 self.iter().map(GetSize::get_size).sum()
580 }
581}
582
583impl GetSize for Rc<str> {
584 fn get_heap_size(&self) -> usize {
585 self.len()
586 }
587}
588
589impl<T> GetSize for Arc<[T]>
590where
591 T: GetSize,
592{
593 fn get_heap_size(&self) -> usize {
594 self.iter().map(GetSize::get_size).sum()
595 }
596}
597
598impl GetSize for Arc<str> {
599 fn get_heap_size(&self) -> usize {
600 self.len()
601 }
602}
603
604#[cfg(feature = "chrono")]
605mod chrono {
606 use crate::GetSize;
607
608 impl GetSize for chrono::NaiveDate {}
609 impl GetSize for chrono::NaiveTime {}
610 impl GetSize for chrono::NaiveDateTime {}
611 impl GetSize for chrono::Utc {}
612 impl GetSize for chrono::FixedOffset {}
613 impl GetSize for chrono::TimeDelta {}
614
615 impl<Tz: chrono::TimeZone> GetSize for chrono::DateTime<Tz>
616 where
617 Tz::Offset: GetSize,
618 {
619 fn get_heap_size(&self) -> usize {
620 GetSize::get_heap_size(self.offset())
621 }
622 }
623}
624
625#[cfg(feature = "chrono-tz")]
626impl GetSize for chrono_tz::TzOffset {}
627
628#[cfg(feature = "url")]
629impl GetSize for url::Url {
630 fn get_heap_size(&self) -> usize {
631 self.as_str().len()
632 }
633}
634
635#[cfg(feature = "bytes")]
636impl GetSize for bytes::Bytes {
637 fn get_heap_size(&self) -> usize {
638 self.len()
639 }
640}
641
642#[cfg(feature = "bytes")]
643impl GetSize for bytes::BytesMut {
644 fn get_heap_size(&self) -> usize {
645 self.len()
646 }
647}
648
649#[cfg(feature = "hashbrown")]
650impl<K, V, H> GetSize for hashbrown::HashMap<K, V, H>
651where
652 K: GetSize + Eq + std::hash::Hash,
653 V: GetSize,
654 H: std::hash::BuildHasher,
655{
656 fn get_heap_size(&self) -> usize {
657 self.allocation_size()
658 + self
659 .iter()
660 .map(|(k, v)| k.get_heap_size() + v.get_heap_size())
661 .sum::<usize>()
662 }
663}
664
665#[cfg(feature = "hashbrown")]
666impl<T, H> GetSize for hashbrown::HashSet<T, H>
667where
668 T: GetSize + Eq + std::hash::Hash,
669 H: std::hash::BuildHasher,
670{
671 fn get_heap_size(&self) -> usize {
672 self.allocation_size() + self.iter().map(GetSize::get_heap_size).sum::<usize>()
673 }
674}
675
676#[cfg(feature = "hashbrown")]
677impl<T> GetSize for hashbrown::HashTable<T>
678where
679 T: GetSize,
680{
681 fn get_heap_size(&self) -> usize {
682 self.allocation_size() + self.iter().map(GetSize::get_heap_size).sum::<usize>()
683 }
684}
685
686#[cfg(feature = "smallvec")]
687impl<A: smallvec::Array> GetSize for smallvec::SmallVec<A>
688where
689 A::Item: GetSize,
690{
691 fn get_heap_size(&self) -> usize {
692 if self.len() <= self.inline_size() {
693 return self.iter().map(GetSize::get_heap_size).sum();
694 }
695
696 let mut total = self.iter().map(GetSize::get_size).sum();
697 let additional: usize = self.capacity() - self.len();
698 total += additional * A::Item::get_stack_size();
699 total
700 }
701}
702
703#[cfg(feature = "thin-vec")]
704impl<T> GetSize for thin_vec::ThinVec<T>
705where
706 T: GetSize,
707{
708 fn get_heap_size(&self) -> usize {
709 if self.capacity() == 0 {
710 return 0;
712 }
713
714 let mut total = std::mem::size_of::<usize>() * 2;
716
717 for v in self {
718 total += GetSize::get_size(v);
720 }
721
722 let additional: usize = self.capacity() - self.len();
723 total += additional * T::get_stack_size();
724
725 total
726 }
727}
728
729#[cfg(feature = "compact-str")]
730impl GetSize for compact_str::CompactString {
731 fn get_heap_size(&self) -> usize {
732 if self.is_heap_allocated() {
733 self.capacity()
734 } else {
735 0
736 }
737 }
738}
739
740#[cfg(feature = "indexmap")]
741impl<K, V, S> GetSize for indexmap::IndexMap<K, V, S>
742where
743 K: GetSize,
744 V: GetSize,
745 S: std::hash::BuildHasher,
746{
747 fn get_heap_size(&self) -> usize {
748 self.capacity() * <(K, V)>::get_stack_size()
749 + self
750 .iter()
751 .map(|(k, v)| k.get_heap_size() + v.get_heap_size())
752 .sum::<usize>()
753 }
754}
755
756#[cfg(feature = "indexmap")]
757impl<T, S> GetSize for indexmap::IndexSet<T, S>
758where
759 T: GetSize,
760{
761 fn get_heap_size(&self) -> usize {
762 self.capacity() * <T>::get_stack_size()
763 + self.iter().map(GetSize::get_heap_size).sum::<usize>()
764 }
765}