| Crates.io | borrowscope-runtime |
| lib.rs | borrowscope-runtime |
| version | 0.1.2 |
| created_at | 2025-12-20 00:57:36.234496+00 |
| updated_at | 2026-01-13 09:42:39.761298+00 |
| description | Runtime tracking system for BorrowScope |
| homepage | |
| repository | https://github.com/mehmet-ylcnky/BorrowScope |
| max_upload_size | |
| id | 1995830 |
| size | 700,535 |
A comprehensive runtime tracking library for visualizing Rust's ownership and borrowing system. BorrowScope Runtime captures ownership transfers, borrows, smart pointer operations, and unsafe code patterns as they happen, generating structured event data for analysis and visualization.
Rust's ownership system operates at compile time, making it invisible during execution. BorrowScope Runtime bridges this gap by instrumenting your code to capture every ownership operation at runtime. Whether you're learning Rust, debugging complex ownership issues, or analyzing memory patterns, this library makes the invisible mechanics of Rust's memory model visible.
track feature is disabledAdd to your Cargo.toml:
[dependencies]
borrowscope-runtime = { version = "0.1", features = ["track"] }
Basic usage:
use borrowscope_runtime::*;
fn main() {
reset(); // Clear any previous tracking data
// Track variable creation
let data = track_new("data", vec![1, 2, 3]);
// Track borrowing
let r1 = track_borrow("r1", &data);
let r2 = track_borrow("r2", &data);
println!("Borrowed: {:?}, {:?}", r1, r2);
// Track drops
track_drop("r2");
track_drop("r1");
track_drop("data");
// Export events as JSON
let events = get_events();
println!("{}", serde_json::to_string_pretty(&events).unwrap());
// Build ownership graph
let graph = get_graph();
println!("Graph: {} variables, {} relationships",
graph.nodes.len(), graph.edges.len());
}
Track fundamental ownership operations:
// Variable creation and destruction
let x = track_new("x", 42); // Track variable creation
let y = track_move("y", x); // Track ownership transfer
track_drop("y"); // Track variable drop
// Borrowing operations
let data = track_new("data", vec![1, 2, 3]);
let r = track_borrow("r", &data); // Track immutable borrow
let r_mut = track_borrow_mut("r_mut", &mut data); // Track mutable borrow
Eliminate manual drop tracking with RAII guards:
{
let data = track_new_guard("data", vec![1, 2, 3]);
let r = track_borrow_guard("r", &*data);
let r_mut = track_borrow_mut_guard("r_mut", &mut *data);
// track_drop called automatically when guards go out of scope
}
// Guards support transparent access via Deref/DerefMut
let guard = track_new_guard("x", 42);
println!("{}", *guard); // Access inner value
Track reference-counted smart pointers with precise count monitoring:
use std::rc::Rc;
use std::sync::Arc;
// Rc<T> tracking
let rc1 = track_rc_new("rc1", Rc::new(42));
let rc2 = track_rc_clone("rc2", "rc1", rc1.clone());
// Automatically tracks strong_count and weak_count
// Arc<T> tracking (thread-safe)
let arc1 = track_arc_new("arc1", Arc::new(vec![1, 2, 3]));
let arc2 = track_arc_clone("arc2", "arc1", arc1.clone());
Monitor RefCell and Cell operations with runtime borrow checking:
use std::cell::{RefCell, Cell};
// RefCell tracking
let cell = track_refcell_new("cell", RefCell::new(42));
let borrow = refcell_borrow!("borrow", "cell", cell.borrow());
let borrow_mut = refcell_borrow_mut!("borrow_mut", "cell", cell.borrow_mut());
refcell_drop!("cell");
// Cell tracking
let cell = track_cell_new("cell", Cell::new(10));
let value = track_cell_get("cell", cell.get());
track_cell_set("cell");
Comprehensive tracking for unsafe operations:
// Raw pointer operations
let x = 42;
let ptr = track_raw_ptr("ptr", &x as *const i32);
let ptr_mut = track_raw_ptr_mut("ptr_mut", &mut x as *mut i32);
unsafe {
track_raw_ptr_deref("ptr");
let value = *ptr;
}
// Unsafe block tracking
unsafe {
track_unsafe_block_enter("block1");
// unsafe operations
track_unsafe_block_exit("block1");
}
// FFI and transmute tracking
track_ffi_call("libc_malloc");
track_transmute("u32_to_f32", "u32", "f32");
track_unsafe_fn_call("dangerous_function");
track_union_field_access("MyUnion", "field1");
Monitor global variable access patterns:
// Static variable tracking
static mut COUNTER: i32 = 0;
track_static_init("COUNTER", "COUNTER_id", "i32", true);
track_static_access("COUNTER_id", "COUNTER", true, "main.rs:10");
// Const evaluation tracking
const PI: f64 = 3.14159;
track_const_eval("PI", "PI_id", "f64", "main.rs:5");
Track async blocks and await expressions:
// Async block tracking
track_async_block_enter(1, "main.rs:10:5");
// ... async block body ...
track_async_block_exit(1, "main.rs:15:5");
// Await expression tracking
track_await_start(1, "fetch_data", "main.rs:12:9");
// ... await completes ...
track_await_end(1, "main.rs:12:9");
Track loops, branches, and control flow:
// Loop tracking
track_loop_enter(1, "for", "main.rs:10:5");
track_loop_iteration(1, 0, "main.rs:10:5");
track_loop_iteration(1, 1, "main.rs:10:5");
track_loop_exit(1, "main.rs:15:5");
// Match tracking
track_match_enter(1, "main.rs:20:5");
track_match_arm(1, 0, "Some(x)", "main.rs:21:9");
track_match_exit(1, "main.rs:25:5");
// Branch tracking
track_branch(1, "then", "main.rs:30:5");
// Return tracking
track_return(1, true, "main.rs:35:5");
// Try operator tracking
track_try(1, "main.rs:40:5");
Track common method calls:
// Clone tracking
track_clone(1, "data", "main.rs:10:5");
// Lock tracking (Mutex/RwLock)
track_lock(1, "mutex", "guard", "main.rs:15:5");
track_lock(2, "rwlock_read", "reader", "main.rs:20:5");
// Unwrap tracking
track_unwrap(1, "unwrap", "option", "main.rs:25:5");
track_unwrap(2, "expect", "result", "main.rs:30:5");
All tracking functions have _with_id variants for custom correlation:
let custom_id = "user_defined_123";
let x = track_new_with_id("x", custom_id, 42);
let r = track_borrow_with_id("r", "r_id", custom_id, &x);
Rich querying capabilities for event analysis:
// Get all events or filtered subsets
let all_events = get_events();
let new_events = get_new_events();
let borrow_events = get_borrow_events();
let move_events = get_move_events();
let drop_events = get_drop_events();
// Filter events by variable or criteria
let var_events = get_events_for_var("data");
let filtered = get_events_filtered(|event| event.is_unsafe());
// Get event statistics
let counts = get_event_counts();
let summary = get_summary();
print_summary();
Efficient batch processing for performance:
let var_names = vec!["x", "y", "z"];
track_drop_batch(&var_names);
Build and analyze ownership relationships:
let graph = get_graph();
// Graph statistics
let stats = graph.stats();
println!("Variables: {}, Relationships: {}",
stats.total_variables, stats.total_relationships);
// Find specific variables and relationships
let var = graph.find_variable("data");
let borrows = graph.find_borrows("data");
// Analyze ownership patterns
for relationship in &graph.edges {
match relationship {
Relationship::BorrowsImmut { from, to, start, end } => {
println!("{} borrows {} from {} to {}", from, to, start, end);
}
Relationship::BorrowsMut { from, to, start, end } => {
println!("{} mutably borrows {} from {} to {}", from, to, start, end);
}
Relationship::Owns { from, to } => {
println!("{} owns {}", from, to);
}
}
}
Advanced lifetime relationship analysis:
// Build timeline from events
let timeline = Timeline::from_events(&get_events());
// Analyze lifetime relationships
let relations = timeline.analyze_lifetimes();
for relation in relations {
match relation {
LifetimeRelation::Contains { outer, inner } => {
println!("Lifetime {} contains {}", outer, inner);
}
LifetimeRelation::Overlaps { first, second } => {
println!("Lifetimes {} and {} overlap", first, second);
}
}
}
// Detect elision rules
let elision_rules = timeline.detect_elision_rules();
Export tracking data for external analysis:
// Export to JSON file
export_json("ownership_analysis.json").unwrap();
// Manual export with custom data
let events = get_events();
let graph = get_graph();
let export_data = ExportData::new(graph, events);
export_data.to_file("custom_export.json").unwrap();
BorrowScope Runtime tracks 40+ event types covering all ownership patterns:
| Category | Events |
|---|---|
| Basic Ownership | New, Borrow, Move, Drop |
| Smart Pointers | RcNew, RcClone, ArcNew, ArcClone |
| Interior Mutability | RefCellNew, RefCellBorrow, RefCellDrop, CellNew, CellGet, CellSet |
| Static/Const | StaticInit, StaticAccess, ConstEval |
| Unsafe Operations | RawPtrCreated, RawPtrDeref, UnsafeBlockEnter, UnsafeBlockExit, UnsafeFnCall |
| FFI/Transmute | FfiCall, Transmute, UnionFieldAccess |
| Async | AsyncBlockEnter, AsyncBlockExit, AwaitStart, AwaitEnd |
| Loops | LoopEnter, LoopIteration, LoopExit |
| Control Flow | MatchEnter, MatchArm, MatchExit, Branch, Return, Try |
| Method Calls | Clone, Lock, Unwrap |
| Access | IndexAccess, FieldAccess, Call, Deref |
All events include timestamps and are serializable to JSON for analysis.
BorrowScope Runtime uses an event sourcing architecture:
Key components:
Optimized for minimal runtime overhead:
Thread safety achieved through:
parking_lot::Mutex for efficient locking (40-60% faster than std)AtomicU64 for lock-free timestamp generationtrack - Enables runtime tracking. Without this feature, all tracking functions compile to no-ops with zero overhead.# Development/debugging (with tracking)
[dependencies]
borrowscope-runtime = { version = "0.1", features = ["track"] }
# Production (zero overhead)
[dependencies]
borrowscope-runtime = "0.1"
Comprehensive test suite with 555+ tests:
# Run all tests
cargo test --package borrowscope-runtime --features track
# Run specific test categories
cargo test --package borrowscope-runtime --features track --test integration_tests
cargo test --package borrowscope-runtime --features track --test performance_tests
cargo test --package borrowscope-runtime --features track --test unsafe_code_tests
# Run benchmarks
cargo bench --package borrowscope-runtime
Robust error handling with comprehensive error types:
use borrowscope_runtime::{Result, Error};
match export_json("output.json") {
Ok(()) => println!("Export successful"),
Err(Error::SerializationError(e)) => eprintln!("JSON error: {}", e),
Err(Error::IoError(e)) => eprintln!("File error: {}", e),
Err(Error::ExportError(msg)) => eprintln!("Export failed: {}", msg),
Err(Error::InvalidEventSequence(msg)) => eprintln!("Invalid events: {}", msg),
Err(Error::LockError(msg)) => eprintln!("Lock error: {}", msg),
}
Generate and view complete API documentation:
cargo doc --package borrowscope-runtime --features track --open
Licensed under the Apache License, Version 2.0. See the main BorrowScope repository for full license information.