this is not doable with the parenthesis syntax for the FnMut() trait, which forces you to name the ouptut associated type, but you can do it with the desugared syntax (which is unstable), or with a helper trait. below is an example I wrote, you can also use the fn-traits's definition instead:
trait MyFnMut1<Arg> {
type Output;
fn call(&mut self, arg: Arg)->Self::Output;
}
impl<Arg, Ret, F> MyFnMut1<Arg> for F where F: FnMut(Arg) -> Ret {
type Output = Ret;
fn call(&mut self, arg:Arg) -> Ret {
self(arg)
}
}
impl<State, Logic> Engine<State, Logic> {
fn run<>(mut self)
where
Logic: for<'a> MyFnMut1<&'a mut State, Output: Iterator<Item=usize>+'a>,
{
for x in self.logic.call(&mut self.state) {
println!("got {x}");
}
}
}
this uses the .call() method, if you want to use the call operator on self.logic as before, you can do it with the trick of adding the (redundent) FnMut() trait back:
impl<State, Logic> Engine<State, Logic> {
fn run<>(mut self)
where
Logic: for<'a> MyFnMut1<&'a mut State, Output: Iterator<Item=usize>+'a>,
Logic: for<'a> FnMut(&'a mut State) -> <Logic as MyFnMut1<&'a mut State>>::Output,
{
for x in (self.logic)(&mut self.state) {
println!("got {x}");
}
}
}
the arguments types are grouped into a tuple, and the output type is an associated type, just like the definition in fn-traits.
I remembered the syntax for Fn-family of traits are meant to be permanently unstable, exposing only the sugar form in the surface syntax. but I can't find where I saw this. maybe it's just my imagination.