Skip to main content

cranpose_core/slot/
introspection.rs

1use std::mem;
2
3use super::{
4    GroupRecord, SlotDebugAnchor, SlotDebugEntry, SlotDebugEntryKind, SlotDebugGroup,
5    SlotDebugScope, SlotDebugSnapshot, SlotTable, SlotTableLocalDebugStats,
6    SlotTableMutationDebugStats,
7};
8use crate::{Key, RecomposeScope, ScopeId};
9
10impl SlotTable {
11    fn group_heap_bytes(&self) -> usize {
12        self.groups.capacity() * mem::size_of::<GroupRecord>()
13    }
14
15    pub fn heap_bytes(&self) -> usize {
16        self.group_heap_bytes()
17            + self.payloads.heap_bytes()
18            + self.node_heap_bytes()
19            + self.anchors.heap_bytes()
20            + self.payload_anchors.heap_bytes()
21    }
22
23    pub fn debug_stats(&self) -> SlotTableLocalDebugStats {
24        SlotTableLocalDebugStats {
25            group_count: self.groups.len(),
26            group_capacity: self.groups.capacity(),
27            group_record_size: mem::size_of::<GroupRecord>(),
28            group_heap_bytes: self.group_heap_bytes(),
29            payload_count: self.total_payload_count(),
30            payload_capacity: self.payloads.capacity(),
31            active_payload_anchor_count: self.payload_anchors.active_len(),
32            payload_anchor_slot_count: self.payload_anchors.slot_len(),
33            detached_payload_anchor_count: self.payload_anchors.detached_len(),
34            invalidated_payload_anchor_count: self.payload_anchors.invalidated_len(),
35            free_payload_anchor_count: self.payload_anchors.free_len(),
36            payload_anchor_capacity: self.payload_anchors.capacity(),
37            payload_anchor_heap_bytes: self.payload_anchors.heap_bytes(),
38            node_count: self.total_node_count(),
39            node_capacity: self.node_debug_capacity(),
40            active_anchor_count: self.anchors.active_len(),
41            anchor_slot_count: self.anchors.slot_len(),
42            anchor_sparse_count: self.anchors.sparse_slot_len(),
43            detached_anchor_count: self.anchors.detached_len(),
44            invalidated_anchor_count: self.anchors.invalidated_len(),
45            free_anchor_count: self.anchors.free_len(),
46            anchor_capacity: self.anchors.capacity(),
47            anchor_heap_bytes: self.anchors.heap_bytes(),
48            mutation: SlotTableMutationDebugStats {
49                payload_shift_bytes: self.payloads.shift_bytes(),
50                ..self.diagnostics.mutation()
51            },
52        }
53    }
54
55    pub fn debug_dump_groups(&self) -> Vec<(usize, Key, Option<ScopeId>, usize)> {
56        self.groups
57            .iter()
58            .enumerate()
59            .map(|(index, group)| {
60                (
61                    index,
62                    group.key.static_key,
63                    group.scope.as_ref().map(RecomposeScope::id),
64                    group.subtree_len as usize,
65                )
66            })
67            .collect()
68    }
69
70    pub fn debug_snapshot(&self) -> SlotDebugSnapshot {
71        let active_groups = self
72            .groups
73            .iter()
74            .enumerate()
75            .map(|(index, group)| SlotDebugGroup {
76                index,
77                anchor: group.anchor,
78                parent_anchor: group.parent_anchor,
79                static_key: group.key.static_key,
80                explicit_key: group.key.explicit_key,
81                ordinal: group.key.ordinal,
82                scope_id: group.scope.as_ref().map(RecomposeScope::id),
83                depth: group.depth,
84                subtree_len: group.subtree_len,
85                payload_len: self.group_payload_len_at(index),
86                node_len: self.group_node_len_at(index),
87                subtree_node_count: group.subtree_node_count,
88            })
89            .collect::<Vec<_>>();
90        let mut anchors = self
91            .anchors
92            .active_entries()
93            .map(|(anchor, group_index)| SlotDebugAnchor {
94                anchor,
95                group_index,
96            })
97            .collect::<Vec<_>>();
98        anchors.sort_by_key(|entry| entry.group_index);
99
100        let mut scopes = self
101            .groups
102            .iter()
103            .enumerate()
104            .filter_map(|(group_index, group)| {
105                group.scope.as_ref().map(|scope| SlotDebugScope {
106                    scope_id: scope.id(),
107                    anchor: group.anchor,
108                    group_index,
109                })
110            })
111            .collect::<Vec<_>>();
112        scopes.sort_by_key(|entry| entry.scope_id);
113
114        SlotDebugSnapshot {
115            active_payload_count: self.total_payload_count(),
116            active_node_count: self.total_node_count(),
117            active_scope_count: scopes.len(),
118            active_groups,
119            anchors,
120            scopes,
121            retained_subtree_count: 0,
122            retained_group_count: 0,
123            retained_payload_count: 0,
124            retained_node_count: 0,
125            retained_scope_count: 0,
126        }
127    }
128
129    pub fn debug_dump_slot_entries(&self) -> Vec<SlotDebugEntry> {
130        let mut rows = Vec::new();
131        for (index, group) in self.groups.iter().enumerate() {
132            rows.push(SlotDebugEntry {
133                kind: SlotDebugEntryKind::Group,
134                path: format!("group[{index}]"),
135                line: format!(
136                    "Group(key={:?}, scope={:?}, subtree_len={}, payload_len={}, node_len={})",
137                    group.key,
138                    group.scope.as_ref().map(RecomposeScope::id),
139                    group.subtree_len,
140                    self.group_payload_len_at(index),
141                    self.group_node_len_at(index)
142                ),
143            });
144        }
145        for (group_index, group) in self.groups.iter().enumerate() {
146            for (payload_index, payload) in self.group_payload_records_at(group_index).enumerate() {
147                rows.push(SlotDebugEntry {
148                    kind: SlotDebugEntryKind::Payload,
149                    path: format!("group[{group_index}].payload[{payload_index}]"),
150                    line: format!(
151                        "Payload(owner={:?}, kind={}, type={})",
152                        group.anchor,
153                        payload.kind.label(),
154                        (payload.payload_type.type_name)()
155                    ),
156                });
157            }
158        }
159        for (group_index, _) in self.groups.iter().enumerate() {
160            for (node_index, node) in self.group_node_records_at(group_index).iter().enumerate() {
161                rows.push(SlotDebugEntry {
162                    kind: SlotDebugEntryKind::Node,
163                    path: format!("group[{group_index}].node[{node_index}]"),
164                    line: format!(
165                        "Node(owner={:?}, parent={:?}, id={}, gen={}, lifecycle={:?})",
166                        node.owner, node.parent_id, node.id, node.generation, node.lifecycle
167                    ),
168                });
169            }
170        }
171        rows
172    }
173}