size_of/support/
arcstr.rs

1#![cfg(feature = "arcstr")]
2
3use crate::{Context, SizeOf};
4use arcstr::{ArcStr, Substr};
5use core::mem::size_of;
6
7// https://docs.rs/arcstr/1.1.4/src/arcstr/arc_str.rs.html#751-757
8#[repr(C, align(8))]
9struct FakeThinInner {
10    len_flags: usize,
11    strong: usize,
12    data: [u8; 0],
13}
14
15impl SizeOf for ArcStr {
16    fn size_of_children(&self, context: &mut Context) {
17        // FIXME: I'd rather use some sort of `ArcStr::as_ptr()` if possible
18        if context.insert_ptr(self.as_ptr()) {
19            let bytes = size_of::<FakeThinInner>() + self.len();
20            context.add(bytes).add_shared(bytes);
21
22            // Static arcstrs don't create any allocations
23            if !ArcStr::is_static(self) {
24                context.add_distinct_allocation();
25            }
26        }
27    }
28}
29
30impl SizeOf for Substr {
31    #[inline]
32    fn size_of_children(&self, context: &mut Context) {
33        self.parent().size_of_children(context);
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::FakeThinInner;
40    use crate::{SizeOf, TotalSize};
41    use arcstr::{ArcStr, Substr};
42    use core::mem::size_of;
43
44    #[test]
45    fn arcstr_smoke() {
46        let empty = ArcStr::new();
47        assert_eq!(
48            empty.size_of(),
49            TotalSize::new(
50                size_of::<ArcStr>() + size_of::<FakeThinInner>(),
51                0,
52                size_of::<FakeThinInner>(),
53                0,
54            ),
55        );
56
57        let shared = size_of::<FakeThinInner>() + 4;
58        let total = size_of::<ArcStr>() + shared;
59
60        let static_string = arcstr::literal!("whee");
61        assert_eq!(static_string.size_of(), TotalSize::new(total, 0, shared, 0));
62
63        let allocated_string = ArcStr::from("whee");
64        assert_eq!(
65            allocated_string.size_of(),
66            TotalSize::new(total, 0, shared, 1),
67        );
68    }
69
70    #[test]
71    fn shared_arcstr() {
72        let string1 = ArcStr::from("whee");
73        let string2 = string1.clone();
74        let string3 = string1.clone();
75        let string4 = string1.clone();
76
77        let size =
78            crate::size_of_values([&string1 as _, &string2 as _, &string3 as _, &string4 as _]);
79
80        let shared = size_of::<FakeThinInner>() + 4;
81        let total = size_of::<ArcStr>() * 4 + shared;
82        assert_eq!(size, TotalSize::new(total, 0, shared, 1));
83    }
84
85    #[test]
86    fn substr_smoke() {
87        let empty = Substr::new();
88        assert_eq!(
89            empty.size_of(),
90            TotalSize::new(
91                size_of::<Substr>() + size_of::<FakeThinInner>(),
92                0,
93                size_of::<FakeThinInner>(),
94                0,
95            ),
96        );
97
98        let shared = size_of::<FakeThinInner>() + 4;
99        let total = size_of::<Substr>() + shared;
100
101        let static_substr = Substr::full(arcstr::literal!("whee"));
102        assert_eq!(static_substr.size_of(), TotalSize::new(total, 0, shared, 0));
103
104        let allocated_substr = Substr::full(ArcStr::from("whee"));
105        assert_eq!(
106            allocated_substr.size_of(),
107            TotalSize::new(total, 0, shared, 1),
108        );
109
110        let sliced_allocated_substr = ArcStr::from("whee").substr(..2);
111        assert_eq!(
112            sliced_allocated_substr.size_of(),
113            TotalSize::new(total, 0, shared, 1),
114        );
115    }
116}