1#![allow(dead_code)]
2mod error;
85mod event;
86mod export;
87mod graph;
88mod guard;
89mod lifetime;
90mod tracker;
91
92#[cfg(test)]
93mod test_utils;
94
95pub use error::{Error, Result};
96pub use event::Event;
97pub use export::{ExportData, ExportEdge, ExportMetadata};
98pub use graph::{build_graph, GraphStats, OwnershipGraph, Relationship, Variable};
99pub use guard::{
100 track_borrow_guard, track_borrow_mut_guard, track_new_guard, BorrowGuard, BorrowMutGuard,
101 TrackGuard,
102};
103pub use lifetime::{ElisionRule, LifetimeRelation, Timeline};
104pub use tracker::{
105 __track_new_with_id_helper, get_borrow_events, get_drop_events, get_event_counts, get_events,
106 get_events_filtered, get_events_for_var, get_move_events, get_new_events, get_summary,
107 print_summary, reset, track_arc_clone, track_arc_clone_with_id, track_arc_new,
108 track_arc_new_with_id, track_borrow, track_borrow_mut, track_borrow_mut_with_id,
109 track_borrow_with_id, track_cell_get, track_cell_new, track_cell_set, track_const_eval,
110 track_drop, track_drop_batch, track_drop_with_id, track_ffi_call, track_move,
111 track_move_with_id, track_new, track_new_with_id, track_raw_ptr, track_raw_ptr_deref,
112 track_raw_ptr_mut, track_rc_clone, track_rc_clone_with_id, track_rc_new, track_rc_new_with_id,
113 track_refcell_borrow, track_refcell_borrow_mut, track_refcell_drop, track_refcell_new,
114 track_static_access, track_static_init, track_transmute, track_union_field_access,
115 track_unsafe_block_enter, track_unsafe_block_exit, track_unsafe_fn_call, TrackingSummary,
116};
117
118#[macro_export]
120macro_rules! refcell_borrow {
121 ($name:expr, $id:expr, $guard:expr) => {
122 $crate::track_refcell_borrow($name, $id, concat!(file!(), ":", line!()), $guard)
123 };
124}
125
126#[macro_export]
128macro_rules! refcell_borrow_mut {
129 ($name:expr, $id:expr, $guard:expr) => {
130 $crate::track_refcell_borrow_mut($name, $id, concat!(file!(), ":", line!()), $guard)
131 };
132}
133
134#[macro_export]
136macro_rules! refcell_drop {
137 ($name:expr) => {
138 $crate::track_refcell_drop($name, concat!(file!(), ":", line!()))
139 };
140}
141
142pub fn get_graph() -> OwnershipGraph {
144 let events = get_events();
145 build_graph(&events)
146}
147
148pub fn export_json<P: AsRef<std::path::Path>>(path: P) -> Result<()> {
150 let events = get_events();
151 let graph = build_graph(&events);
152 let export = ExportData::new(graph, events);
153 export.to_file(path)
154}
155
156#[cfg(test)]
157mod integration_tests {
158 use super::*;
159 use crate::test_utils::TEST_LOCK;
160
161 #[test]
162 fn test_simple_tracking() {
163 let _lock = TEST_LOCK.lock();
164
165 reset();
166
167 let x = track_new("x", 5);
168 assert_eq!(x, 5);
169
170 let events = get_events();
171 assert_eq!(events.len(), 1);
172 assert!(events[0].is_new());
173 }
174
175 #[test]
176 fn test_borrow_tracking() {
177 let _lock = TEST_LOCK.lock();
178
179 reset();
180
181 let s = track_new("s", String::from("hello"));
182 let r = track_borrow("r", &s);
183
184 assert_eq!(r, "hello");
185
186 let events = get_events();
187 assert_eq!(events.len(), 2);
188 assert!(events[0].is_new());
189 assert!(events[1].is_borrow());
190 }
191
192 #[test]
193 fn test_multiple_variables() {
194 let _lock = TEST_LOCK.lock();
195
196 reset();
197
198 let x = track_new("x", 5);
199 let y = track_new("y", 10);
200 let z = x + y;
201
202 track_drop("y");
203 track_drop("x");
204
205 let events = get_events();
206 assert_eq!(events.len(), 4);
207
208 assert_eq!(z, 15);
209 }
210
211 #[test]
212 fn test_mutable_borrow() {
213 let _lock = TEST_LOCK.lock();
214
215 reset();
216
217 let mut x = track_new("x", vec![1, 2, 3]);
218 let r = track_borrow_mut("r", &mut x);
219 r.push(4);
220
221 assert_eq!(r.len(), 4);
222
223 let events = get_events();
224 assert_eq!(events.len(), 2);
225 }
226
227 #[test]
228 fn test_graph_building() {
229 let _lock = TEST_LOCK.lock();
230
231 reset();
232
233 let x = track_new("x", 5);
234 let _r = track_borrow("r", &x);
235 track_drop("x");
237
238 let graph = get_graph();
239 assert_eq!(graph.nodes.len(), 1);
241 assert_eq!(graph.edges.len(), 0);
243
244 let stats = graph.stats();
245 assert_eq!(stats.total_variables, 1);
246 }
247
248 #[test]
249 fn test_export_json() {
250 let _lock = TEST_LOCK.lock();
251
252 reset();
253
254 let x = track_new("x", 5);
255 let _r = track_borrow("r", &x);
256 track_drop("x");
257
258 let temp_path = std::env::temp_dir().join("borrowscope_test.json");
260 export_json(&temp_path).unwrap();
261
262 let contents = std::fs::read_to_string(&temp_path).unwrap();
264 let parsed: serde_json::Value = serde_json::from_str(&contents).unwrap();
265
266 assert!(parsed["nodes"].is_array());
267 assert!(parsed["events"].is_array());
268 assert!(parsed["metadata"].is_object());
269
270 std::fs::remove_file(&temp_path).ok();
272 }
273}