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 NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
10 NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
11};
12use std::rc::{Rc, Weak as RcWeak};
13use std::sync::atomic::{
14 AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32,
15 AtomicU64, AtomicU8, 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!(v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8);
278 $name!(v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9);
279 $name!(v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10);
280 $name!(
281 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
282 V11
283 );
284 $name!(
285 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
286 V11, v12, V12
287 );
288 $name!(
289 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
290 V11, v12, V12, v13, V13
291 );
292 $name!(
293 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
294 V11, v12, V12, v13, V13, v14, V14
295 );
296 $name!(
297 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
298 V11, v12, V12, v13, V13, v14, V14, v15, V15
299 );
300 $name!(
301 v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11,
302 V11, v12, V12, v13, V13, v14, V14, v15, V15, v16, V16
303 );
304 };
305}
306
307execute_tuple_macro_16!(impl_size_tuple);
308
309impl<T, const SIZE: usize> GetSize for [T; SIZE]
310where
311 T: GetSize,
312{
313 fn get_heap_size(&self) -> usize {
314 let mut total = 0;
315
316 for element in self {
317 total += GetSize::get_heap_size(element);
319 }
320
321 total
322 }
323}
324
325impl<T> GetSize for &[T] where T: GetSize {}
326
327impl<T> GetSize for &T {}
328impl<T> GetSize for &mut T {}
329impl<T> GetSize for *const T {}
330impl<T> GetSize for *mut T {}
331
332impl<T> GetSize for Box<T>
333where
334 T: GetSize,
335{
336 fn get_heap_size(&self) -> usize {
337 GetSize::get_size(&**self)
338 }
339}
340
341impl<T> GetSize for Rc<T>
342where
343 T: GetSize + 'static,
344{
345 fn get_heap_size(&self) -> usize {
346 let tracker = StandardTracker::default();
347
348 let (total, _) = GetSize::get_heap_size_with_tracker(self, tracker);
349
350 total
351 }
352
353 fn get_heap_size_with_tracker<TR: GetSizeTracker>(&self, mut tracker: TR) -> (usize, TR) {
354 let strong_ref = Self::clone(self);
355
356 let addr = Self::as_ptr(&strong_ref);
357
358 if tracker.track(addr, strong_ref) {
359 GetSize::get_size_with_tracker(&**self, tracker)
360 } else {
361 (0, tracker)
362 }
363 }
364}
365
366impl<T> GetSize for RcWeak<T> {}
367
368impl<T> GetSize for Arc<T>
369where
370 T: GetSize + 'static,
371{
372 fn get_heap_size(&self) -> usize {
373 let tracker = StandardTracker::default();
374
375 let (total, _) = GetSize::get_heap_size_with_tracker(self, tracker);
376
377 total
378 }
379
380 fn get_heap_size_with_tracker<TR: GetSizeTracker>(&self, mut tracker: TR) -> (usize, TR) {
381 let strong_ref = Self::clone(self);
382
383 let addr = Self::as_ptr(&strong_ref);
384
385 if tracker.track(addr, strong_ref) {
386 GetSize::get_size_with_tracker(&**self, tracker)
387 } else {
388 (0, tracker)
389 }
390 }
391}
392
393impl<T> GetSize for ArcWeak<T> {}
394
395impl<T> GetSize for Option<T>
396where
397 T: GetSize,
398{
399 fn get_heap_size(&self) -> usize {
400 self.as_ref().map_or(0, |t| GetSize::get_heap_size(t))
401 }
402}
403
404impl<T, E> GetSize for Result<T, E>
405where
406 T: GetSize,
407 E: GetSize,
408{
409 fn get_heap_size(&self) -> usize {
410 match self {
411 Ok(t) => GetSize::get_heap_size(t),
413 Err(e) => GetSize::get_heap_size(e),
414 }
415 }
416}
417
418impl<T> GetSize for Mutex<T>
419where
420 T: GetSize,
421{
422 fn get_heap_size(&self) -> usize {
423 GetSize::get_heap_size(&*(self.lock().expect("Mutex is poisoned")))
425 }
426}
427
428impl<T> GetSize for RwLock<T>
429where
430 T: GetSize,
431{
432 fn get_heap_size(&self) -> usize {
433 GetSize::get_heap_size(&*(self.read().expect("RwLock is poisoned")))
435 }
436}
437
438impl GetSize for String {
439 fn get_heap_size(&self) -> usize {
440 self.capacity()
441 }
442}
443
444impl GetSize for &str {}
445
446impl GetSize for std::ffi::CString {
447 fn get_heap_size(&self) -> usize {
448 self.as_bytes_with_nul().len()
449 }
450}
451
452impl GetSize for &std::ffi::CStr {
453 fn get_heap_size(&self) -> usize {
454 self.to_bytes_with_nul().len()
455 }
456}
457
458impl GetSize for std::ffi::OsString {
459 fn get_heap_size(&self) -> usize {
460 self.len()
461 }
462}
463
464impl GetSize for &std::ffi::OsStr {
465 fn get_heap_size(&self) -> usize {
466 self.len()
467 }
468}
469
470impl GetSize for std::fs::DirBuilder {}
471impl GetSize for std::fs::DirEntry {}
472impl GetSize for std::fs::File {}
473impl GetSize for std::fs::FileType {}
474impl GetSize for std::fs::Metadata {}
475impl GetSize for std::fs::OpenOptions {}
476impl GetSize for std::fs::Permissions {}
477impl GetSize for std::fs::ReadDir {}
478
479impl<T> GetSize for std::io::BufReader<T>
480where
481 T: GetSize,
482{
483 fn get_heap_size(&self) -> usize {
484 let mut total = GetSize::get_heap_size(self.get_ref());
485
486 total += self.capacity();
487
488 total
489 }
490}
491
492impl<T> GetSize for std::io::BufWriter<T>
493where
494 T: GetSize + std::io::Write,
495{
496 fn get_heap_size(&self) -> usize {
497 let mut total = GetSize::get_heap_size(self.get_ref());
498
499 total += self.capacity();
500
501 total
502 }
503}
504
505impl GetSize for std::path::PathBuf {
506 fn get_heap_size(&self) -> usize {
507 self.capacity()
508 }
509}
510
511impl GetSize for &std::path::Path {}
512
513impl<T> GetSize for Box<[T]>
514where
515 T: GetSize,
516{
517 fn get_heap_size(&self) -> usize {
518 self.iter().map(GetSize::get_size).sum()
519 }
520}
521
522#[cfg(feature = "chrono")]
523mod chrono {
524 use crate::GetSize;
525
526 impl GetSize for chrono::NaiveDate {}
527 impl GetSize for chrono::NaiveTime {}
528 impl GetSize for chrono::NaiveDateTime {}
529 impl GetSize for chrono::Utc {}
530 impl GetSize for chrono::FixedOffset {}
531 impl GetSize for chrono::TimeDelta {}
532
533 impl<Tz: chrono::TimeZone> GetSize for chrono::DateTime<Tz>
534 where
535 Tz::Offset: GetSize,
536 {
537 fn get_heap_size(&self) -> usize {
538 GetSize::get_heap_size(self.offset())
539 }
540 }
541}
542
543#[cfg(feature = "chrono-tz")]
544impl GetSize for chrono_tz::TzOffset {}
545
546#[cfg(feature = "url")]
547impl GetSize for url::Url {
548 fn get_heap_size(&self) -> usize {
549 self.as_str().len()
550 }
551}