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 higher-rank trait bound 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