rusty_prawn
rusty_prawn

Reputation: 11

How to handle passing a mutably borrowed struct to function closure?

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

Answers (1)

rusty_prawn
rusty_prawn

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

Related Questions