loupe/memory_usage/
sync.rs

1#[cfg(test)]
2use crate::{assert_size_of_val_eq, POINTER_BYTE_SIZE};
3use crate::{MemoryUsage, MemoryUsageTracker};
4use std::mem;
5use std::sync::{
6    atomic::{
7        AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32,
8        AtomicU64, AtomicU8, AtomicUsize,
9    },
10    Arc, Mutex, RwLock, Weak,
11};
12
13macro_rules! impl_memory_usage_for_numeric {
14    ( $type:ty ) => {
15        impl MemoryUsage for $type {
16            fn size_of_val(&self, _: &mut dyn MemoryUsageTracker) -> usize {
17                mem::size_of_val(self)
18            }
19        }
20    };
21
22    ( $( $type:ty ),+ $(,)* ) => {
23        $( impl_memory_usage_for_numeric!( $type ); )+
24    }
25}
26
27impl_memory_usage_for_numeric!(
28    AtomicBool,
29    AtomicI8,
30    AtomicI16,
31    AtomicI32,
32    AtomicI64,
33    AtomicIsize,
34    AtomicU8,
35    AtomicU16,
36    AtomicU32,
37    AtomicU64,
38    AtomicUsize,
39);
40
41impl<T> MemoryUsage for Arc<T>
42where
43    T: MemoryUsage + ?Sized,
44{
45    fn size_of_val(&self, tracker: &mut dyn MemoryUsageTracker) -> usize {
46        mem::size_of_val(self)
47            + if tracker.track(Arc::as_ptr(self) as *const ()) {
48                self.as_ref().size_of_val(tracker)
49            } else {
50                0
51            }
52    }
53}
54
55impl<T> MemoryUsage for Weak<T>
56where
57    T: MemoryUsage + ?Sized,
58{
59    fn size_of_val(&self, tracker: &mut dyn MemoryUsageTracker) -> usize {
60        mem::size_of_val(self)
61            + if tracker.track(Weak::as_ptr(self) as *const ()) {
62                Weak::upgrade(self)
63                    .map(|arc| arc.as_ref().size_of_val(tracker))
64                    .unwrap_or(0)
65            } else {
66                0
67            }
68    }
69}
70
71impl<T> MemoryUsage for Mutex<T>
72where
73    T: MemoryUsage + ?Sized,
74{
75    fn size_of_val(&self, tracker: &mut dyn MemoryUsageTracker) -> usize {
76        mem::size_of_val(self) + self.lock().unwrap().size_of_val(tracker)
77    }
78}
79
80impl<T> MemoryUsage for RwLock<T>
81where
82    T: MemoryUsage + ?Sized,
83{
84    fn size_of_val(&self, tracker: &mut dyn MemoryUsageTracker) -> usize {
85        mem::size_of_val(self) + self.read().unwrap().size_of_val(tracker)
86    }
87}
88
89#[cfg(test)]
90mod test_sync_types {
91    use super::*;
92
93    macro_rules! test_memory_usage_for_numeric {
94        ($test_name:ident: ($value:expr) == $expected:expr) => {
95            #[test]
96            fn $test_name() {
97                assert_size_of_val_eq!($value, $expected);
98            }
99        };
100
101        ( $( $test_name:ident: ($value:expr) == $expected:expr );+ $(;)* ) => {
102            $( test_memory_usage_for_numeric!( $test_name: ($value) == $expected); )+
103        }
104    }
105
106    test_memory_usage_for_numeric!(
107        test_atomic_bool: (AtomicBool::new(true)) == 1;
108        test_atomic_i8: (AtomicI8::new(1i8)) == 1;
109        test_atomic_i16: (AtomicI16::new(1i16)) == 2;
110        test_atomic_i32: (AtomicI32::new(1i32)) == 4;
111        test_atomic_i64: (AtomicI64::new(1i64)) == 8;
112        test_atomic_isize: (AtomicIsize::new(1isize)) == POINTER_BYTE_SIZE;
113        test_atomic_u8: (AtomicU8::new(1u8)) == 1;
114        test_atomic_u16: (AtomicU16::new(1u16)) == 2;
115        test_atomic_u32: (AtomicU32::new(1u32)) == 4;
116        test_atomic_u64: (AtomicU64::new(1u64)) == 8;
117        test_atomic_usize: (AtomicUsize::new(1usize)) == POINTER_BYTE_SIZE;
118    );
119
120    #[test]
121    fn test_arc() {
122        let empty_arc_size = mem::size_of_val(&Arc::new(()));
123
124        let arc: Arc<i32> = Arc::new(1);
125        assert_size_of_val_eq!(arc, empty_arc_size + 4);
126
127        let arc: Arc<Option<i32>> = Arc::new(Some(1));
128        assert_size_of_val_eq!(arc, empty_arc_size + POINTER_BYTE_SIZE + 4);
129    }
130
131    #[test]
132    fn test_weak() {
133        let empty_weak_size = mem::size_of_val(&Arc::downgrade(&Arc::new(())));
134
135        let arc: Arc<i32> = Arc::new(1);
136        let weak: Weak<i32> = Arc::downgrade(&arc);
137        assert_size_of_val_eq!(weak, empty_weak_size + 4);
138
139        let arc: Arc<Option<i32>> = Arc::new(Some(1));
140        let weak: Weak<Option<i32>> = Arc::downgrade(&arc);
141        assert_size_of_val_eq!(weak, empty_weak_size + POINTER_BYTE_SIZE + 4);
142
143        let weak: Weak<i32> = {
144            let arc: Arc<i32> = Arc::new(5);
145            Arc::downgrade(&arc)
146        };
147        assert_size_of_val_eq!(weak, empty_weak_size);
148    }
149
150    #[test]
151    fn test_mutex() {
152        let empty_mutex_size = mem::size_of_val(&Mutex::new(()));
153
154        let mutex: Mutex<i32> = Mutex::new(1);
155        assert_size_of_val_eq!(mutex, empty_mutex_size + 4);
156
157        let mutex: Mutex<Option<i32>> = Mutex::new(Some(1));
158        assert_size_of_val_eq!(mutex, empty_mutex_size + 2 * POINTER_BYTE_SIZE + 4);
159    }
160
161    #[test]
162    fn test_rwlock() {
163        let empty_rwlock_size = mem::size_of_val(&RwLock::new(()));
164
165        let rwlock: RwLock<i32> = RwLock::new(1);
166        assert_size_of_val_eq!(rwlock, empty_rwlock_size + 4);
167
168        let rwlock: RwLock<Option<i32>> = RwLock::new(Some(1));
169        assert_size_of_val_eq!(rwlock, empty_rwlock_size + 2 * POINTER_BYTE_SIZE + 4);
170    }
171}