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,
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 + 'static,
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 let strong_ref = Self::clone(self);
396
397 let addr = Self::as_ptr(&strong_ref);
398
399 if tracker.track(addr, strong_ref) {
400 GetSize::get_size_with_tracker(&**self, tracker)
401 } else {
402 (0, tracker)
403 }
404 }
405}
406
407impl<T> GetSize for RcWeak<T> {}
408
409impl<T> GetSize for Arc<T>
410where
411 T: GetSize + 'static,
412{
413 fn get_heap_size(&self) -> usize {
414 let tracker = StandardTracker::default();
415
416 let (total, _) = GetSize::get_heap_size_with_tracker(self, tracker);
417
418 total
419 }
420
421 fn get_heap_size_with_tracker<TR: GetSizeTracker>(&self, mut tracker: TR) -> (usize, TR) {
422 let strong_ref = Self::clone(self);
423
424 let addr = Self::as_ptr(&strong_ref);
425
426 if tracker.track(addr, strong_ref) {
427 GetSize::get_size_with_tracker(&**self, tracker)
428 } else {
429 (0, tracker)
430 }
431 }
432}
433
434impl<T> GetSize for ArcWeak<T> {}
435
436impl<T> GetSize for Option<T>
437where
438 T: GetSize,
439{
440 fn get_heap_size(&self) -> usize {
441 self.as_ref().map_or(0, |t| GetSize::get_heap_size(t))
442 }
443}
444
445impl<T, E> GetSize for Result<T, E>
446where
447 T: GetSize,
448 E: GetSize,
449{
450 fn get_heap_size(&self) -> usize {
451 match self {
452 Ok(t) => GetSize::get_heap_size(t),
454 Err(e) => GetSize::get_heap_size(e),
455 }
456 }
457}
458
459impl<T> GetSize for Mutex<T>
460where
461 T: GetSize,
462{
463 fn get_heap_size(&self) -> usize {
464 GetSize::get_heap_size(&*(self.lock().expect("Mutex is poisoned")))
466 }
467}
468
469impl<T> GetSize for RwLock<T>
470where
471 T: GetSize,
472{
473 fn get_heap_size(&self) -> usize {
474 GetSize::get_heap_size(&*(self.read().expect("RwLock is poisoned")))
476 }
477}
478
479impl<T> GetSize for OnceLock<T>
480where
481 T: GetSize,
482{
483 fn get_heap_size(&self) -> usize {
484 match self.get() {
486 None => 0,
487 Some(value) => GetSize::get_heap_size(value),
488 }
489 }
490}
491
492impl GetSize for String {
493 fn get_heap_size(&self) -> usize {
494 self.capacity()
495 }
496}
497
498impl GetSize for &str {}
499
500impl GetSize for std::ffi::CString {
501 fn get_heap_size(&self) -> usize {
502 self.as_bytes_with_nul().len()
503 }
504}
505
506impl GetSize for &std::ffi::CStr {
507 fn get_heap_size(&self) -> usize {
508 self.to_bytes_with_nul().len()
509 }
510}
511
512impl GetSize for std::ffi::OsString {
513 fn get_heap_size(&self) -> usize {
514 self.len()
515 }
516}
517
518impl GetSize for &std::ffi::OsStr {
519 fn get_heap_size(&self) -> usize {
520 self.len()
521 }
522}
523
524impl GetSize for std::fs::DirBuilder {}
525impl GetSize for std::fs::DirEntry {}
526impl GetSize for std::fs::File {}
527impl GetSize for std::fs::FileType {}
528impl GetSize for std::fs::Metadata {}
529impl GetSize for std::fs::OpenOptions {}
530impl GetSize for std::fs::Permissions {}
531impl GetSize for std::fs::ReadDir {}
532
533impl<T> GetSize for std::io::BufReader<T>
534where
535 T: GetSize,
536{
537 fn get_heap_size(&self) -> usize {
538 let mut total = GetSize::get_heap_size(self.get_ref());
539
540 total += self.capacity();
541
542 total
543 }
544}
545
546impl<T> GetSize for std::io::BufWriter<T>
547where
548 T: GetSize + std::io::Write,
549{
550 fn get_heap_size(&self) -> usize {
551 let mut total = GetSize::get_heap_size(self.get_ref());
552
553 total += self.capacity();
554
555 total
556 }
557}
558
559impl GetSize for std::path::PathBuf {
560 fn get_heap_size(&self) -> usize {
561 self.capacity()
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(&self) -> usize {
572 self.iter().map(GetSize::get_size).sum()
573 }
574}
575
576impl GetSize for Box<str> {
577 fn get_heap_size(&self) -> usize {
578 self.len()
579 }
580}
581
582impl GetSize for Rc<str> {
583 fn get_heap_size(&self) -> usize {
584 self.len()
585 }
586}
587
588impl GetSize for Arc<str> {
589 fn get_heap_size(&self) -> usize {
590 self.len()
591 }
592}
593
594#[cfg(feature = "chrono")]
595mod chrono {
596 use crate::GetSize;
597
598 impl GetSize for chrono::NaiveDate {}
599 impl GetSize for chrono::NaiveTime {}
600 impl GetSize for chrono::NaiveDateTime {}
601 impl GetSize for chrono::Utc {}
602 impl GetSize for chrono::FixedOffset {}
603 impl GetSize for chrono::TimeDelta {}
604
605 impl<Tz: chrono::TimeZone> GetSize for chrono::DateTime<Tz>
606 where
607 Tz::Offset: GetSize,
608 {
609 fn get_heap_size(&self) -> usize {
610 GetSize::get_heap_size(self.offset())
611 }
612 }
613}
614
615#[cfg(feature = "chrono-tz")]
616impl GetSize for chrono_tz::TzOffset {}
617
618#[cfg(feature = "url")]
619impl GetSize for url::Url {
620 fn get_heap_size(&self) -> usize {
621 self.as_str().len()
622 }
623}
624
625#[cfg(feature = "bytes")]
626impl GetSize for bytes::Bytes {
627 fn get_heap_size(&self) -> usize {
628 self.len()
629 }
630}
631
632#[cfg(feature = "bytes")]
633impl GetSize for bytes::BytesMut {
634 fn get_heap_size(&self) -> usize {
635 self.len()
636 }
637}
638
639#[cfg(feature = "hashbrown")]
640impl<K, V, H> GetSize for hashbrown::HashMap<K, V, H>
641where
642 K: GetSize + Eq + std::hash::Hash,
643 V: GetSize,
644 H: std::hash::BuildHasher,
645{
646 fn get_heap_size(&self) -> usize {
647 self.allocation_size()
648 + self
649 .iter()
650 .map(|(k, v)| k.get_heap_size() + v.get_heap_size())
651 .sum::<usize>()
652 }
653}
654
655#[cfg(feature = "hashbrown")]
656impl<T, H> GetSize for hashbrown::HashSet<T, H>
657where
658 T: GetSize + Eq + std::hash::Hash,
659 H: std::hash::BuildHasher,
660{
661 fn get_heap_size(&self) -> usize {
662 self.allocation_size() + self.iter().map(GetSize::get_heap_size).sum::<usize>()
663 }
664}
665
666#[cfg(feature = "hashbrown")]
667impl<T> GetSize for hashbrown::HashTable<T>
668where
669 T: GetSize,
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 = "smallvec")]
677impl<A: smallvec::Array> GetSize for smallvec::SmallVec<A>
678where
679 A::Item: GetSize,
680{
681 fn get_heap_size(&self) -> usize {
682 if self.len() <= self.inline_size() {
683 return self.iter().map(GetSize::get_heap_size).sum();
684 }
685
686 self.iter().map(GetSize::get_size).sum()
687 }
688}
689
690#[cfg(feature = "compact-str")]
691impl GetSize for compact_str::CompactString {
692 fn get_heap_size(&self) -> usize {
693 if self.is_heap_allocated() {
694 self.len()
695 } else {
696 0
697 }
698 }
699}