Reputation: 11
I am using the proptest crate to run some property tests in a no_std environment. proptest's default test_runner::TestRunner::run()
implementation takes some input (as a Strategy
or ValueTree
object defined in proptest) and a function closure as parameters so you can run however many tests you want with the values in the value tree or strategy.
I need to test a function call that takes as an argument a mutably borrowed struct. This won't compile:
error[E0596]: cannot borrow `*<obj>` as mutable, as it is a captured variable in a 'Fn' closure
obj
is the struct passed to test_runner
via a function call one level up as a mutably borrowed object.
Digging into the source code for proptest, it is clear the compilation error arises due to the function signature for test_runner::TestRunner::run()
:
pub fn run<S: Strategy>(
&mut self,
strategy: &S,
test: impl Fn(S::Value) -> TestCaseResult,
) -> TestRunResult<S>
The parameter would need to be FnMut
so that captured variables can be mutable in the function call. My question is: is there an idomatic rust way of doing this?
Here is the function passed from a conditionally compiled run func:
fn test_mod(runner: &mut TestRunner, obj: &mut MyObjStruct) -> Result<(), TestError(u32)>>{
runner.run(&(0x400_0000u32..0xe00_0000u32), |addr| {
if mod::test::test_page_map(addr, obj).is_ok() {
Ok(())
} else {
Err(TestCaseError::fail(Reason::from("Failed to map address")))
}
})
}
mod::test::test_page_map
takes obj
, uses relevant metadata in the struct, updates that data accordingly, and maps a page to the input address. It returns a result based on whether or not the map succeeded. It is worth noting that I am not able to clone the object.
Does anyone see a way around this problem that is in line with 'the Rust way'? Is there some mechanism available in no_std land like Cell
or something that I can wrap the mutable object with so it has interior mutability but can be passed as a captured variable to a 'Fn' closure? I am very new to Rust so unsure how this sort of thing is usually handled.
Upvotes: -1
Views: 111
Reputation: 11
Found an answer that works, although there are likely others. What I found works is to use core::cell::RefCell::new(obj)
to wrap the object. Then pass the RefCell
-wrapped object to the function as a mutable borrow, by calling the borrow_mut()
method provided by RefCell
Upvotes: 0