1use std::sync::LazyLock;
2
3use crate::ordered_hash_map::OrderedHashMap;
4use crate::ordered_hash_set::OrderedHashSet;
5
6static COUNT_SHARED_ALLOCATIONS: LazyLock<bool> = LazyLock::new(|| {
10 std::env::var("CAIRO_HEAPSIZE_COUNT_SHARED")
11 .map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
12 .unwrap_or(false)
13});
14
15pub trait HeapSize {
19 fn heap_size(&self) -> usize;
22}
23
24impl<T: HeapSize> HeapSize for Vec<T> {
26 fn heap_size(&self) -> usize {
27 self.capacity() * std::mem::size_of::<T>()
29 + self.iter().map(|x| x.heap_size()).sum::<usize>()
30 }
31}
32
33impl HeapSize for String {
34 fn heap_size(&self) -> usize {
35 self.capacity()
36 }
37}
38
39impl<T: HeapSize> HeapSize for Option<T> {
40 fn heap_size(&self) -> usize {
41 match self {
42 Some(x) => x.heap_size(),
43 None => 0,
44 }
45 }
46}
47
48impl<T: HeapSize, E: HeapSize> HeapSize for Result<T, E> {
49 fn heap_size(&self) -> usize {
50 match self {
51 Ok(value) => value.heap_size(),
52 Err(err) => err.heap_size(),
53 }
54 }
55}
56
57impl<T: HeapSize> HeapSize for Box<T> {
58 fn heap_size(&self) -> usize {
59 std::mem::size_of::<T>() + self.as_ref().heap_size()
60 }
61}
62
63impl<T: HeapSize> HeapSize for std::sync::Arc<T> {
64 fn heap_size(&self) -> usize {
65 if *COUNT_SHARED_ALLOCATIONS {
66 std::mem::size_of::<T>() + self.as_ref().heap_size()
69 } else {
70 0
72 }
73 }
74}
75
76impl<T: HeapSize> HeapSize for std::rc::Rc<T> {
77 fn heap_size(&self) -> usize {
78 if *COUNT_SHARED_ALLOCATIONS {
79 std::mem::size_of::<T>() + self.as_ref().heap_size()
82 } else {
83 0
85 }
86 }
87}
88
89impl HeapSize for u8 {
91 fn heap_size(&self) -> usize {
92 0
93 }
94}
95
96impl HeapSize for i8 {
97 fn heap_size(&self) -> usize {
98 0
99 }
100}
101
102impl HeapSize for i32 {
103 fn heap_size(&self) -> usize {
104 0
105 }
106}
107
108impl HeapSize for u32 {
109 fn heap_size(&self) -> usize {
110 0
111 }
112}
113
114impl HeapSize for i64 {
115 fn heap_size(&self) -> usize {
116 0
117 }
118}
119
120impl HeapSize for u64 {
121 fn heap_size(&self) -> usize {
122 0
123 }
124}
125
126impl HeapSize for usize {
127 fn heap_size(&self) -> usize {
128 0
129 }
130}
131
132impl HeapSize for isize {
133 fn heap_size(&self) -> usize {
134 0
135 }
136}
137
138impl HeapSize for bool {
139 fn heap_size(&self) -> usize {
140 0
141 }
142}
143
144impl HeapSize for char {
145 fn heap_size(&self) -> usize {
146 0
147 }
148}
149
150impl<T> HeapSize for std::marker::PhantomData<T> {
151 fn heap_size(&self) -> usize {
152 0
153 }
154}
155
156impl HeapSize for std::path::PathBuf {
157 fn heap_size(&self) -> usize {
158 self.capacity()
159 }
160}
161
162#[expect(clippy::disallowed_types)]
163impl<K: HeapSize, V: HeapSize> HeapSize for std::collections::HashMap<K, V> {
164 fn heap_size(&self) -> usize {
165 self.capacity() * (std::mem::size_of::<K>() + std::mem::size_of::<V>())
167 + self.iter().map(|(k, v)| k.heap_size() + v.heap_size()).sum::<usize>()
168 }
169}
170
171#[expect(clippy::disallowed_types)]
172impl<T: HeapSize> HeapSize for std::collections::HashSet<T> {
173 fn heap_size(&self) -> usize {
174 self.capacity() * std::mem::size_of::<T>()
175 + self.iter().map(|x| x.heap_size()).sum::<usize>()
176 }
177}
178
179impl<T: HeapSize> HeapSize for std::collections::BTreeSet<T> {
180 fn heap_size(&self) -> usize {
181 self.len() * std::mem::size_of::<T>() + self.iter().map(|x| x.heap_size()).sum::<usize>()
183 }
184}
185
186impl<K: HeapSize, V: HeapSize, BH> HeapSize for OrderedHashMap<K, V, BH> {
187 fn heap_size(&self) -> usize {
188 self.iter().map(|(k, v)| k.heap_size() + v.heap_size()).sum()
189 }
190}
191
192impl<K: HeapSize, BH> HeapSize for OrderedHashSet<K, BH> {
193 fn heap_size(&self) -> usize {
194 self.iter().map(|k| k.heap_size()).sum()
195 }
196}
197
198impl HeapSize for smol_str::SmolStr {
200 fn heap_size(&self) -> usize {
201 if *COUNT_SHARED_ALLOCATIONS && self.is_heap_allocated() {
202 self.len()
205 } else {
206 0
207 }
208 }
209}
210
211impl HeapSize for num_bigint::BigUint {
213 fn heap_size(&self) -> usize {
214 let bits = self.bits() as usize;
216 bits.div_ceil(8)
217 }
218}
219
220impl HeapSize for num_bigint::BigInt {
221 fn heap_size(&self) -> usize {
222 self.magnitude().heap_size()
223 }
224}
225
226impl HeapSize for () {
228 fn heap_size(&self) -> usize {
229 0
230 }
231}
232
233impl<T0: HeapSize> HeapSize for (T0,) {
234 fn heap_size(&self) -> usize {
235 self.0.heap_size()
236 }
237}
238
239impl<T0: HeapSize, T1: HeapSize> HeapSize for (T0, T1) {
240 fn heap_size(&self) -> usize {
241 self.0.heap_size() + self.1.heap_size()
242 }
243}
244
245impl<T0: HeapSize, T1: HeapSize, T2: HeapSize> HeapSize for (T0, T1, T2) {
246 fn heap_size(&self) -> usize {
247 self.0.heap_size() + self.1.heap_size() + self.2.heap_size()
248 }
249}
250
251impl<T0: HeapSize, T1: HeapSize, T2: HeapSize, T3: HeapSize> HeapSize for (T0, T1, T2, T3) {
252 fn heap_size(&self) -> usize {
253 self.0.heap_size() + self.1.heap_size() + self.2.heap_size() + self.3.heap_size()
254 }
255}
256
257impl<T0: HeapSize, T1: HeapSize, T2: HeapSize, T3: HeapSize, T4: HeapSize> HeapSize
258 for (T0, T1, T2, T3, T4)
259{
260 fn heap_size(&self) -> usize {
261 self.0.heap_size()
262 + self.1.heap_size()
263 + self.2.heap_size()
264 + self.3.heap_size()
265 + self.4.heap_size()
266 }
267}
268
269impl<T0: HeapSize, T1: HeapSize, T2: HeapSize, T3: HeapSize, T4: HeapSize, T5: HeapSize> HeapSize
270 for (T0, T1, T2, T3, T4, T5)
271{
272 fn heap_size(&self) -> usize {
273 self.0.heap_size()
274 + self.1.heap_size()
275 + self.2.heap_size()
276 + self.3.heap_size()
277 + self.4.heap_size()
278 + self.5.heap_size()
279 }
280}
281
282impl<
283 T0: HeapSize,
284 T1: HeapSize,
285 T2: HeapSize,
286 T3: HeapSize,
287 T4: HeapSize,
288 T5: HeapSize,
289 T6: HeapSize,
290> HeapSize for (T0, T1, T2, T3, T4, T5, T6)
291{
292 fn heap_size(&self) -> usize {
293 self.0.heap_size()
294 + self.1.heap_size()
295 + self.2.heap_size()
296 + self.3.heap_size()
297 + self.4.heap_size()
298 + self.5.heap_size()
299 + self.6.heap_size()
300 }
301}
302
303impl<
304 T0: HeapSize,
305 T1: HeapSize,
306 T2: HeapSize,
307 T3: HeapSize,
308 T4: HeapSize,
309 T5: HeapSize,
310 T6: HeapSize,
311 T7: HeapSize,
312> HeapSize for (T0, T1, T2, T3, T4, T5, T6, T7)
313{
314 fn heap_size(&self) -> usize {
315 self.0.heap_size()
316 + self.1.heap_size()
317 + self.2.heap_size()
318 + self.3.heap_size()
319 + self.4.heap_size()
320 + self.5.heap_size()
321 + self.6.heap_size()
322 + self.7.heap_size()
323 }
324}
325
326impl<
327 T0: HeapSize,
328 T1: HeapSize,
329 T2: HeapSize,
330 T3: HeapSize,
331 T4: HeapSize,
332 T5: HeapSize,
333 T6: HeapSize,
334 T7: HeapSize,
335 T8: HeapSize,
336> HeapSize for (T0, T1, T2, T3, T4, T5, T6, T7, T8)
337{
338 fn heap_size(&self) -> usize {
339 self.0.heap_size()
340 + self.1.heap_size()
341 + self.2.heap_size()
342 + self.3.heap_size()
343 + self.4.heap_size()
344 + self.5.heap_size()
345 + self.6.heap_size()
346 + self.7.heap_size()
347 + self.8.heap_size()
348 }
349}
350
351impl<
352 T0: HeapSize,
353 T1: HeapSize,
354 T2: HeapSize,
355 T3: HeapSize,
356 T4: HeapSize,
357 T5: HeapSize,
358 T6: HeapSize,
359 T7: HeapSize,
360 T8: HeapSize,
361 T9: HeapSize,
362> HeapSize for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9)
363{
364 fn heap_size(&self) -> usize {
365 self.0.heap_size()
366 + self.1.heap_size()
367 + self.2.heap_size()
368 + self.3.heap_size()
369 + self.4.heap_size()
370 + self.5.heap_size()
371 + self.6.heap_size()
372 + self.7.heap_size()
373 + self.8.heap_size()
374 + self.9.heap_size()
375 }
376}
377
378impl<
379 T0: HeapSize,
380 T1: HeapSize,
381 T2: HeapSize,
382 T3: HeapSize,
383 T4: HeapSize,
384 T5: HeapSize,
385 T6: HeapSize,
386 T7: HeapSize,
387 T8: HeapSize,
388 T9: HeapSize,
389 T10: HeapSize,
390> HeapSize for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)
391{
392 fn heap_size(&self) -> usize {
393 self.0.heap_size()
394 + self.1.heap_size()
395 + self.2.heap_size()
396 + self.3.heap_size()
397 + self.4.heap_size()
398 + self.5.heap_size()
399 + self.6.heap_size()
400 + self.7.heap_size()
401 + self.8.heap_size()
402 + self.9.heap_size()
403 + self.10.heap_size()
404 }
405}
406
407impl<
408 T0: HeapSize,
409 T1: HeapSize,
410 T2: HeapSize,
411 T3: HeapSize,
412 T4: HeapSize,
413 T5: HeapSize,
414 T6: HeapSize,
415 T7: HeapSize,
416 T8: HeapSize,
417 T9: HeapSize,
418 T10: HeapSize,
419 T11: HeapSize,
420> HeapSize for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)
421{
422 fn heap_size(&self) -> usize {
423 self.0.heap_size()
424 + self.1.heap_size()
425 + self.2.heap_size()
426 + self.3.heap_size()
427 + self.4.heap_size()
428 + self.5.heap_size()
429 + self.6.heap_size()
430 + self.7.heap_size()
431 + self.8.heap_size()
432 + self.9.heap_size()
433 + self.10.heap_size()
434 + self.11.heap_size()
435 }
436}