In a trait, what is the type for a Fn that accepts all lifetimes?

Viewed 81

I'm building a pipelining tool, and this is my main trait:

trait Transform<A, B> {
    fn transform(&self, input: A, out: &dyn Fn(B));
}

which works out nicely for owned values, e.g.

struct Repeat { times: usize }

impl<A: Clone> Transform<A, A> for Repeat {
    fn transform(&self, input: A, out: &dyn Fn(A)) {
        std::iter::repeat(input)
            .take(self.times)
            .for_each(|v| (out)(v))
    }
}

This does not work if B is a borrow of A.

In this contrived example (a more realistic case is transforming a Read into tar::Entry<'a, R>..):

use std::io::{Stdin, StdinLock};

struct Lock { }

impl Transform<Stdin, StdinLock> for Lock {
    fn transform(&self, input: Stdin, out: &dyn Fn(StdinLock)) {
        (out)(input.lock())
    }
}
error[E0053]: method `transform` has an incompatible type for trait
  --> min.rs:25:5
   |
4  |     fn transform(&self, input: A, out: &dyn Fn(B));
   |     ----------------------------------------------- type in trait
...
25 |     fn transform(&self, input: Stdin, out: &dyn Fn(StdinLock)) {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime
   |
   = note: expected fn pointer `fn(&Lock, std::io::Stdin, &dyn std::ops::Fn(std::io::StdinLock<'_>))`
              found fn pointer `fn(&Lock, std::io::Stdin, &dyn for<'r> std::ops::Fn(std::io::StdinLock<'r>))`

Fair enough, the following works:

impl Lock {
    // desugars into
    // fn transform(input: Stdin, out: &dyn for<'r> Fn(StdinLock<'r>))
    fn transform(input: Stdin, out: &dyn Fn(StdinLock)) {
        (out)(input.lock())
    }
}

I don't know how I can include this HRTB in my trait. I've tried, to no avail:

trait TransformTmp<'r, A, B: 'r> {
    fn transform(input: A, out: &dyn Fn(B));
}

trait TransformTmpAll<A, B>: for<'r> TransformTmp<'r, A, B> {}
32 | impl<'r> TransformTmp<'r, Stdin, StdinLock<'r>> for Lock {
   |      -- lifetime `'r` defined here
33 |     fn transform(input: Stdin, out: &dyn Fn(StdinLock<'r>)) {
34 |         (out)(input.lock())
   |         ------^^^^^--------
   |         |     |
   |         |     borrowed value does not live long enough
   |         argument requires that `input` is borrowed for `'r`
35 |     }
   |     - `input` dropped here while still borrowed
0 Answers
Related