Here is a hacky debugging tool for refcell issues:
/// Put this at the root of the crate (lib.rs / main.rs)
::cfg_if::cfg_if! { if #[cfg(debug_assertions)] {
#[derive(
Debug,
Clone,
PartialEq, Eq,
PartialOrd, Ord,
)]
struct RefCell<T> {
ref_cell: ::core::cell::RefCell<T>,
last_borrow_context: ::core::cell::Cell<&'static str>,
}
impl<T> RefCell<T> {
fn new (value: T) -> Self
{
RefCell {
ref_cell: ::core::cell::RefCell::new(value),
last_borrow_context: ::core::cell::Cell::new(""),
}
}
}
macro_rules! borrow {(
$wrapper:expr
) => ({
let wrapper = &$wrapper;
if let Ok(ret) = wrapper.ref_cell.try_borrow() {
wrapper
.last_borrow_context
.set(concat!(
"was still borrowed from ",
file!(), ":", line!(), ":", column!(),
" on expression ",
stringify!($wrapper),
));
ret
} else {
panic!(
"Error, {} {}",
stringify!($wrapper),
wrapper.last_borrow_context.get(),
);
}
})}
macro_rules! borrow_mut {(
$wrapper:expr
) => ({
let wrapper = &$wrapper;
if let Ok(ret) = $wrapper.ref_cell.try_borrow_mut() {
$wrapper
.last_borrow_context
.set(concat!(
"was still mutably borrowed from ",
file!(), ":", line!(), ":", column!(),
" on expression ",
stringify!($wrapper),
));
ret
} else {
panic!(
"Error, {} {}",
stringify!($wrapper),
wrapper.last_borrow_context.get(),
);
}
})}
macro_rules! use_RefCell {() => (
use crate::RefCell;
)}
} else {
macro_rules! borrow {(
$ref_cell:expr
) => (
$ref_cell.borrow()
)}
macro_rules! borrow_mut {(
$ref_cell:expr
) => (
$ref_cell.borrow_mut()
)}
macro_rules! use_RefCell {() => (
use ::core::cell::RefCell;
)}
}}
So, the following buggy code:
fn main ()
{
use_RefCell!();
let x = RefCell::new(String::from("Hello"));
let print_x = {
let s = borrow!(x); // line 96
move || {
eprintln!("x = {:?}", &*s as &str);
}
};
print_x();
*borrow_mut!(x) += " World!";
print_x();
}
prints, on a release
build (no debug_assertions
):
x = "Hello"
thread 'main' panicked at 'already borrowed: BorrowMutError', src/libcore/result.rs:997:5
but, on a debug build, it prints:
x = "Hello"
thread 'main' panicked at 'Error, x was still borrowed from src/main.rs:96:17 on expression x', src/main.rs:102:6