How do I make a FnMutOnce?


#1

I want to move a value into a mutable closure. FnOnce is very close to what I need, but I also want to mutate some values just outside the closure as well. Is it possible to make a FnMutOnce?, If not, I’ll just re-arrange some code.

I have a with_frp_context with one type signature in observe:

fn observe<F,F2>(&self, env: &mut ENV, with_frp_context: &F, observer: F2) -> Box<Fn(&mut Self)>
where
F:Fn(&mut ENV,&FnOnce(&mut FrpContext<ENV>)),
F2:Fn(&mut ENV,&A) + 'static {
    let observer_id = self.free_observer_id;
    with_frp_context(
        env,
        &move |frp_context| {
            if let Some(cell) = frp_context.cell_map.get_mut(&observer_id) {
                cell.free_observer_id = cell.free_observer_id + 1;
                cell.observer_map.insert(observer_id, Box::new(
                    move |env, value| {
                        match value.as_ref().downcast_ref::<A>() {
                            Some(value) => observer(env, value),
                            None => ()
                        }
                    }
                ));
            }
        }
    );
    Box::new(move |cell| {
        cell.observer_map.remove(&observer_id);
    })
}

Then a different type signature in another method:

pub fn transaction<F,F2>(env: &mut ENV, with_frp_context: &F, k: &mut F2)
where F:Fn(&mut ENV, &FnMut(&mut FrpContext<ENV>)), F2: FnMut(&mut ENV, &F)
{
    with_frp_context(
        env,
        &|frp_context| {
            frp_context.transaction_depth = frp_context.transaction_depth + 1;
        }
    );
    k(env, with_frp_context);
    let mut final_transaction_depth = 0;
    with_frp_context(
        env,
        &mut |frp_context| {
            frp_context.transaction_depth = frp_context.transaction_depth - 1;
            final_transaction_depth = frp_context.transaction_depth;
        }
    );
    if final_transaction_depth == 0 {
        FrpContext::propergate(env, with_frp_context);
    }
}

However I’d like to use the same type signature for with_frp_context in all methods for consistency and ease of use.

I might be able to just make another trait like:

pub trait WithFrpContext<ENV> {
    fn call<S>(env: &mut ENV, state: &mut S, k: &FnOnce(&mut FrpContext<ENV>, &mut S));
}

But would be a little in-convenient to the end-user as they can not use closure syntax.


#2

You should be able to specify FnOnce and pass a FnMut as well (FnMut: FnOnce).


#3

Nice one. I did not realise FnMut: FnOnce. Thanks


#4

Actually I needed to go:

pub trait WithFrpContext<ENV> {
    fn with_frp_context<F>(&self, &mut ENV, k: F)
    where F: FnOnce(&mut FrpContext<ENV>);
}

Because a &FnOnce(...) is not executable. Finally working :smiley: