1use crate::event_store::MemoryEvent;
4use crate::snapshot::{build_snapshot_from_events, ActiveAllocation, MemorySnapshot};
5use std::sync::Arc;
6
7use super::{FilterBuilder, ViewStats};
8
9#[derive(Clone)]
14pub struct MemoryView {
15 snapshot: MemorySnapshot,
16 events: Arc<[MemoryEvent]>,
17}
18
19impl MemoryView {
20 pub fn new(snapshot: MemorySnapshot, events: Vec<MemoryEvent>) -> Self {
22 Self {
23 snapshot,
24 events: events.into(),
25 }
26 }
27
28 pub fn from_tracker(
30 tracker: &crate::capture::backends::global_tracking::GlobalTracker,
31 ) -> Self {
32 let events = tracker.tracker().events();
33 let snapshot = build_snapshot_from_events(&events);
34 Self::new(snapshot, events)
35 }
36
37 pub fn from_events(events: Vec<MemoryEvent>) -> Self {
39 let snapshot = build_snapshot_from_events(&events);
40 Self::new(snapshot, events)
41 }
42
43 pub fn allocations(&self) -> Vec<&ActiveAllocation> {
45 self.snapshot.active_allocations.values().collect()
46 }
47
48 pub fn get_allocation(&self, ptr: usize) -> Option<&ActiveAllocation> {
50 self.snapshot.active_allocations.get(&ptr)
51 }
52
53 pub fn events(&self) -> &[MemoryEvent] {
55 &self.events
56 }
57
58 pub fn snapshot(&self) -> &MemorySnapshot {
60 &self.snapshot
61 }
62
63 pub fn stats(&self) -> ViewStats {
65 ViewStats::from_snapshot(&self.snapshot)
66 }
67
68 pub fn filter(&self) -> FilterBuilder<'_> {
70 FilterBuilder::new(self)
71 }
72
73 pub fn len(&self) -> usize {
75 self.snapshot.active_allocations.len()
76 }
77
78 pub fn is_empty(&self) -> bool {
80 self.snapshot.active_allocations.is_empty()
81 }
82
83 pub fn total_memory(&self) -> usize {
85 self.snapshot.stats.current_memory
86 }
87
88 pub fn thread_ids(&self) -> Vec<u64> {
90 self.snapshot.thread_stats.keys().copied().collect()
91 }
92}
93
94impl Default for MemoryView {
95 fn default() -> Self {
96 Self::from_events(vec![])
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn test_empty_view() {
106 let view = MemoryView::from_events(vec![]);
107 assert!(view.is_empty());
108 assert_eq!(view.len(), 0);
109 }
110
111 #[test]
112 fn test_single_allocation() {
113 let events = vec![MemoryEvent::allocate(0x1000, 64, 1)];
114 let view = MemoryView::from_events(events);
115 assert_eq!(view.len(), 1);
116 assert_eq!(view.total_memory(), 64);
117 }
118
119 #[test]
120 fn test_allocation_and_deallocation() {
121 let events = vec![
122 MemoryEvent::allocate(0x1000, 64, 1),
123 MemoryEvent::deallocate(0x1000, 64, 1),
124 ];
125 let view = MemoryView::from_events(events);
126 assert!(view.is_empty());
127 assert_eq!(view.total_memory(), 0);
128 }
129
130 #[test]
131 fn test_default_view() {
132 let view = MemoryView::default();
133 assert!(view.is_empty());
134 assert_eq!(view.len(), 0);
135 assert_eq!(view.total_memory(), 0);
136 }
137
138 #[test]
139 fn test_get_allocation_existing() {
140 let events = vec![MemoryEvent::allocate(0x1000, 128, 1)];
141 let view = MemoryView::from_events(events);
142
143 let alloc = view.get_allocation(0x1000);
144 assert!(alloc.is_some());
145 assert_eq!(alloc.unwrap().size, 128);
146 }
147
148 #[test]
149 fn test_get_allocation_not_found() {
150 let events = vec![MemoryEvent::allocate(0x1000, 64, 1)];
151 let view = MemoryView::from_events(events);
152
153 let alloc = view.get_allocation(0x2000);
154 assert!(alloc.is_none());
155 }
156
157 #[test]
158 fn test_allocations_multiple() {
159 let events = vec![
160 MemoryEvent::allocate(0x1000, 64, 1),
161 MemoryEvent::allocate(0x2000, 128, 1),
162 MemoryEvent::allocate(0x3000, 256, 1),
163 ];
164 let view = MemoryView::from_events(events);
165
166 let allocs = view.allocations();
167 assert_eq!(allocs.len(), 3);
168 }
169
170 #[test]
171 fn test_events_access() {
172 let events = vec![
173 MemoryEvent::allocate(0x1000, 64, 1),
174 MemoryEvent::deallocate(0x1000, 64, 1),
175 ];
176 let view = MemoryView::from_events(events);
177
178 let view_events = view.events();
179 assert_eq!(view_events.len(), 2);
180 }
181
182 #[test]
183 fn test_snapshot_access() {
184 let events = vec![MemoryEvent::allocate(0x1000, 64, 1)];
185 let view = MemoryView::from_events(events);
186
187 let snapshot = view.snapshot();
188 assert_eq!(snapshot.active_allocations.len(), 1);
189 }
190
191 #[test]
192 fn test_stats() {
193 let events = vec![
194 MemoryEvent::allocate(0x1000, 64, 1),
195 MemoryEvent::allocate(0x2000, 128, 1),
196 ];
197 let view = MemoryView::from_events(events);
198
199 let stats = view.stats();
200 assert_eq!(stats.allocation_count, 2);
201 assert_eq!(stats.total_bytes, 192);
202 }
203
204 #[test]
205 fn test_thread_ids() {
206 let events = vec![
207 MemoryEvent::allocate(0x1000, 64, 1),
208 MemoryEvent::allocate(0x2000, 128, 2),
209 MemoryEvent::allocate(0x3000, 256, 1),
210 ];
211 let view = MemoryView::from_events(events);
212
213 let threads = view.thread_ids();
214 assert_eq!(threads.len(), 2);
215 assert!(threads.contains(&1));
216 assert!(threads.contains(&2));
217 }
218
219 #[test]
220 fn test_filter_builder() {
221 let events = vec![
222 MemoryEvent::allocate(0x1000, 64, 1),
223 MemoryEvent::allocate(0x2000, 128, 2),
224 ];
225 let view = MemoryView::from_events(events);
226
227 let _filter = view.filter();
228 }
229
230 #[test]
231 fn test_clone() {
232 let events = vec![MemoryEvent::allocate(0x1000, 64, 1)];
233 let view = MemoryView::from_events(events);
234
235 let cloned = view.clone();
236 assert_eq!(cloned.len(), 1);
237 assert_eq!(cloned.total_memory(), 64);
238 }
239
240 #[test]
241 fn test_new_constructor() {
242 let events = vec![MemoryEvent::allocate(0x1000, 64, 1)];
243 let snapshot = build_snapshot_from_events(&events);
244 let view = MemoryView::new(snapshot, events);
245
246 assert_eq!(view.len(), 1);
247 }
248
249 #[test]
250 fn test_multiple_allocations_same_thread() {
251 let events = vec![
252 MemoryEvent::allocate(0x1000, 64, 1),
253 MemoryEvent::allocate(0x2000, 128, 1),
254 MemoryEvent::allocate(0x3000, 256, 1),
255 ];
256 let view = MemoryView::from_events(events);
257
258 assert_eq!(view.len(), 3);
259 assert_eq!(view.total_memory(), 448);
260
261 let threads = view.thread_ids();
262 assert_eq!(threads.len(), 1);
263 }
264
265 #[test]
266 fn test_partial_deallocation() {
267 let events = vec![
268 MemoryEvent::allocate(0x1000, 64, 1),
269 MemoryEvent::allocate(0x2000, 128, 1),
270 MemoryEvent::deallocate(0x1000, 64, 1),
271 ];
272 let view = MemoryView::from_events(events);
273
274 assert_eq!(view.len(), 1);
275 assert_eq!(view.total_memory(), 128);
276 }
277}