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::rc::{Rc, Weak as RcWeak};
13use std::sync::atomic::{
14 AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize, AtomicU8, AtomicU16,
15 AtomicU32, AtomicU64, AtomicUsize, Ordering,
16};
17use std::sync::{Arc, Mutex, RwLock, Weak as ArcWeak};
18use std::time::{Duration, Instant, SystemTime};
19
20#[cfg(feature = "derive")]
21#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
22pub use get_size_derive2::*;
23
24mod tracker;
25pub use tracker::*;
26#[cfg(test)]
27mod test;
28
29pub trait GetSize: Sized {
31 #[must_use]
35 fn get_stack_size() -> usize {
36 std::mem::size_of::<Self>()
37 }
38
39 fn get_heap_size(&self) -> usize {
44 0
45 }
46
47 fn get_heap_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
52 (GetSize::get_heap_size(self), tracker)
53 }
54
55 fn get_size(&self) -> usize {
60 Self::get_stack_size() + GetSize::get_heap_size(self)
61 }
62
63 fn get_size_with_tracker<T: GetSizeTracker>(&self, tracker: T) -> (usize, T) {
69 let stack_size = Self::get_stack_size();
70 let (heap_size, tracker) = GetSize::get_heap_size_with_tracker(self, tracker);
71
72 let total = stack_size + heap_size;
73
74 (total, tracker)
75 }
76}
77
78impl GetSize for () {}
79impl GetSize for bool {}
80impl GetSize for u8 {}
81impl GetSize for u16 {}
82impl GetSize for u32 {}
83impl GetSize for u64 {}
84impl GetSize for u128 {}
85impl GetSize for usize {}
86impl GetSize for NonZeroU8 {}
87impl GetSize for NonZeroU16 {}
88impl GetSize for NonZeroU32 {}
89impl GetSize for NonZeroU64 {}
90impl GetSize for NonZeroU128 {}
91impl GetSize for NonZeroUsize {}
92impl GetSize for i8 {}
93impl GetSize for i16 {}
94impl GetSize for i32 {}
95impl GetSize for i64 {}
96impl GetSize for i128 {}
97impl GetSize for isize {}
98impl GetSize for NonZeroI8 {}
99impl GetSize for NonZeroI16 {}
100impl GetSize for NonZeroI32 {}
101impl GetSize for NonZeroI64 {}
102impl GetSize for NonZeroI128 {}
103impl GetSize for NonZeroIsize {}
104impl GetSize for f32 {}
105impl GetSize for f64 {}
106impl GetSize for char {}
107
108impl GetSize for AtomicBool {}
109impl GetSize for AtomicI8 {}
110impl GetSize for AtomicI16 {}
111impl GetSize for AtomicI32 {}
112impl GetSize for AtomicI64 {}
113impl GetSize for AtomicIsize {}
114impl GetSize for AtomicU8 {}
115impl GetSize for AtomicU16 {}
116impl GetSize for AtomicU32 {}
117impl GetSize for AtomicU64 {}
118impl GetSize for AtomicUsize {}
119impl GetSize for Ordering {}
120
121impl GetSize for std::cmp::Ordering {}
122
123impl GetSize for Infallible {}
124impl<T> GetSize for PhantomData<T> {}
125impl GetSize for PhantomPinned {}
126
127impl GetSize for Instant {}
128impl GetSize for Duration {}
129impl GetSize for SystemTime {}
130
131#[expect(clippy::needless_lifetimes, reason = "ok here")]
132impl<'a, T> GetSize for Cow<'a, T>
133where
134 T: ToOwned,
135 <T as ToOwned>::Owned: GetSize,
136{
137 fn get_heap_size(&self) -> usize {
138 match self {
139 Self::Borrowed(_borrowed) => 0,
140 Self::Owned(owned) => GetSize::get_heap_size(owned),
141 }
142 }
143}
144
145macro_rules! impl_size_set {
146 ($name:ident) => {
147 impl<T> GetSize for $name<T>
148 where
149 T: GetSize,
150 {
151 fn get_heap_size(&self) -> usize {
152 let mut total = 0;
153
154 for v in self.iter() {
155 total += GetSize::get_size(v);
157 }
158
159 let additional: usize = self.capacity() - self.len();
160 total += additional * T::get_stack_size();
161
162 total
163 }
164 }
165 };
166}
167
168macro_rules! impl_size_set_no_capacity {
169 ($name:ident) => {
170 impl<T> GetSize for $name<T>
171 where
172 T: GetSize,
173 {
174 fn get_heap_size(&self) -> usize {
175 let mut total = 0;
176
177 for v in self.iter() {
178 total += GetSize::get_size(v);
180 }
181
182 total
183 }
184 }
185 };
186}
187
188macro_rules! impl_size_map {
189 ($name:ident) => {
190 impl<K, V> GetSize for $name<K, V>
191 where
192 K: GetSize,
193 V: GetSize,
194 {
195 fn get_heap_size(&self) -> usize {
196 let mut total = 0;
197
198 for (k, v) in self.iter() {
199 total += GetSize::get_size(k);
201 total += GetSize::get_size(v);
202 }
203
204 let additional: usize = self.capacity() - self.len();
205 total += additional * K::get_stack_size();
206 total += additional * V::get_stack_size();
207
208 total
209 }
210 }
211 };
212}
213
214macro_rules! impl_size_map_no_capacity {
215 ($name:ident) => {
216 impl<K, V> GetSize for $name<K, V>
217 where
218 K: GetSize,
219 V: GetSize,
220 {
221 fn get_heap_size(&self) -> usize {
222 let mut total = 0;
223
224 for (k, v) in self.iter() {
225 total += GetSize::get_size(k);
227 total += GetSize::get_size(v);
228 }
229
230 total
231 }
232 }
233 };
234}
235
236impl_size_map_no_capacity!(BTreeMap);
237impl_size_set_no_capacity!(BTreeSet);
238impl_size_set!(BinaryHeap);
239impl_size_map!(HashMap);
240impl_size_set!(HashSet);
241impl_size_set_no_capacity!(LinkedList);
242impl_size_set!(VecDeque);
243
244impl_size_set!(Vec);
245
246macro_rules! impl_size_tuple {
247 ($($t:ident, $T:ident),+) => {
248 impl<$($T,)*> GetSize for ($($T,)*)
249 where
250 $(
251 $T: GetSize,
252 )*
253 {
254 fn get_heap_size(&self) -> usize {
255 let mut total = 0;
256
257 let ($($t,)*) = self;
258 $(
259 total += GetSize::get_heap_size($t);
260 )*
261
262 total
263 }
264 }
265 }
266}
267
268macro_rules! execute_tuple_macro_16 {
269 ($name:ident) => {
270 $name!(v1, V1);
271 $name!(v1, V1, v2, V2);
272 $name!(v1, V1, v2, V2, v3, V3);
273 $name!(v1, V1, v2, V2, v3, V3, v4, V4);
274 $name!(v1, V1, v2, V2, v3, V3, v4, V4, v5, V5);
275 $name!(v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6);
276 $name!(v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7);
277 $name!(
278 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8
279 );
280 $name!(
281 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9
282 );
283 $name!(
284 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10
285 );
286 $name!(
287 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
288 V11
289 );
290 $name!(
291 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
292 V11, v12, V12
293 );
294 $name!(
295 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
296 V11, v12, V12, v13, V13
297 );
298 $name!(
299 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
300 V11, v12, V12, v13, V13, v14, V14
301 );
302 $name!(
303 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
304 V11, v12, V12, v13, V13, v14, V14, v15, V15
305 );
306 $name!(
307 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
308 V11, v12, V12, v13, V13, v14, V14, v15, V15, v16, V16
309 );
310 };
311}
312
313execute_tuple_macro_16!(impl_size_tuple);
314
315impl<T, const SIZE: usize> GetSize for [T; SIZE]
316where
317 T: GetSize,
318{
319 fn get_heap_size(&self) -> usize {
320 let mut total = 0;
321
322 for element in self {
323 total += GetSize::get_heap_size(element);
325 }
326
327 total
328 }
329}
330
331impl<T> GetSize for &[T] where T: GetSize {}
332
333impl<T> GetSize for &T {}
334impl<T> GetSize for &mut T {}
335impl<T> GetSize for *const T {}
336impl<T> GetSize for *mut T {}
337
338impl<T> GetSize for Box<T>
339where
340 T: GetSize,
341{
342 fn get_heap_size(&self) -> usize {
343 GetSize::get_size(&**self)
344 }
345}
346
347impl<T> GetSize for Rc<T>
348where
349 T: GetSize + 'static,
350{
351 fn get_heap_size(&self) -> usize {
352 let tracker = StandardTracker::default();
353
354 let (total, _) = GetSize::get_heap_size_with_tracker(self, tracker);
355
356 total
357 }
358
359 fn get_heap_size_with_tracker<TR: GetSizeTracker>(&self, mut tracker: TR) -> (usize, TR) {
360 let strong_ref = Self::clone(self);
361
362 let addr = Self::as_ptr(&strong_ref);
363
364 if tracker.track(addr, strong_ref) {
365 GetSize::get_size_with_tracker(&**self, tracker)
366 } else {
367 (0, tracker)
368 }
369 }
370}
371
372impl<T> GetSize for RcWeak<T> {}
373
374impl<T> GetSize for Arc<T>
375where
376 T: GetSize + 'static,
377{
378 fn get_heap_size(&self) -> usize {
379 let tracker = StandardTracker::default();
380
381 let (total, _) = GetSize::get_heap_size_with_tracker(self, tracker);
382
383 total
384 }
385
386 fn get_heap_size_with_tracker<TR: GetSizeTracker>(&self, mut tracker: TR) -> (usize, TR) {
387 let strong_ref = Self::clone(self);
388
389 let addr = Self::as_ptr(&strong_ref);
390
391 if tracker.track(addr, strong_ref) {
392 GetSize::get_size_with_tracker(&**self, tracker)
393 } else {
394 (0, tracker)
395 }
396 }
397}
398
399impl<T> GetSize for ArcWeak<T> {}
400
401impl<T> GetSize for Option<T>
402where
403 T: GetSize,
404{
405 fn get_heap_size(&self) -> usize {
406 self.as_ref().map_or(0, |t| GetSize::get_heap_size(t))
407 }
408}
409
410impl<T, E> GetSize for Result<T, E>
411where
412 T: GetSize,
413 E: GetSize,
414{
415 fn get_heap_size(&self) -> usize {
416 match self {
417 Ok(t) => GetSize::get_heap_size(t),
419 Err(e) => GetSize::get_heap_size(e),
420 }
421 }
422}
423
424impl<T> GetSize for Mutex<T>
425where
426 T: GetSize,
427{
428 fn get_heap_size(&self) -> usize {
429 GetSize::get_heap_size(&*(self.lock().expect("Mutex is poisoned")))
431 }
432}
433
434impl<T> GetSize for RwLock<T>
435where
436 T: GetSize,
437{
438 fn get_heap_size(&self) -> usize {
439 GetSize::get_heap_size(&*(self.read().expect("RwLock is poisoned")))
441 }
442}
443
444impl GetSize for String {
445 fn get_heap_size(&self) -> usize {
446 self.capacity()
447 }
448}
449
450impl GetSize for &str {}
451
452impl GetSize for std::ffi::CString {
453 fn get_heap_size(&self) -> usize {
454 self.as_bytes_with_nul().len()
455 }
456}
457
458impl GetSize for &std::ffi::CStr {
459 fn get_heap_size(&self) -> usize {
460 self.to_bytes_with_nul().len()
461 }
462}
463
464impl GetSize for std::ffi::OsString {
465 fn get_heap_size(&self) -> usize {
466 self.len()
467 }
468}
469
470impl GetSize for &std::ffi::OsStr {
471 fn get_heap_size(&self) -> usize {
472 self.len()
473 }
474}
475
476impl GetSize for std::fs::DirBuilder {}
477impl GetSize for std::fs::DirEntry {}
478impl GetSize for std::fs::File {}
479impl GetSize for std::fs::FileType {}
480impl GetSize for std::fs::Metadata {}
481impl GetSize for std::fs::OpenOptions {}
482impl GetSize for std::fs::Permissions {}
483impl GetSize for std::fs::ReadDir {}
484
485impl<T> GetSize for std::io::BufReader<T>
486where
487 T: GetSize,
488{
489 fn get_heap_size(&self) -> usize {
490 let mut total = GetSize::get_heap_size(self.get_ref());
491
492 total += self.capacity();
493
494 total
495 }
496}
497
498impl<T> GetSize for std::io::BufWriter<T>
499where
500 T: GetSize + std::io::Write,
501{
502 fn get_heap_size(&self) -> usize {
503 let mut total = GetSize::get_heap_size(self.get_ref());
504
505 total += self.capacity();
506
507 total
508 }
509}
510
511impl GetSize for std::path::PathBuf {
512 fn get_heap_size(&self) -> usize {
513 self.capacity()
514 }
515}
516
517impl GetSize for &std::path::Path {}
518
519impl<T> GetSize for Box<[T]>
520where
521 T: GetSize,
522{
523 fn get_heap_size(&self) -> usize {
524 self.iter().map(GetSize::get_size).sum()
525 }
526}
527
528#[cfg(feature = "chrono")]
529mod chrono {
530 use crate::GetSize;
531
532 impl GetSize for chrono::NaiveDate {}
533 impl GetSize for chrono::NaiveTime {}
534 impl GetSize for chrono::NaiveDateTime {}
535 impl GetSize for chrono::Utc {}
536 impl GetSize for chrono::FixedOffset {}
537 impl GetSize for chrono::TimeDelta {}
538
539 impl<Tz: chrono::TimeZone> GetSize for chrono::DateTime<Tz>
540 where
541 Tz::Offset: GetSize,
542 {
543 fn get_heap_size(&self) -> usize {
544 GetSize::get_heap_size(self.offset())
545 }
546 }
547}
548
549#[cfg(feature = "chrono-tz")]
550impl GetSize for chrono_tz::TzOffset {}
551
552#[cfg(feature = "url")]
553impl GetSize for url::Url {
554 fn get_heap_size(&self) -> usize {
555 self.as_str().len()
556 }
557}
558
559#[cfg(feature = "bytes")]
560impl GetSize for bytes::Bytes {
561 fn get_heap_size(&self) -> usize {
562 self.len()
563 }
564}
565
566#[cfg(feature = "bytes")]
567impl GetSize for bytes::BytesMut {
568 fn get_heap_size(&self) -> usize {
569 self.len()
570 }
571}