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}