I'm trying to hide nix::dir::{Dir, Entry, Iter}
behind a trait so that I can fuzz test my app without scrambling my real file system by providing a mock implementation of that trait.
As a simplified model of the problem, I wrote this:
#[derive(Debug)]
pub struct Source(u8);
// this is similar to nix::dir::Dir;
#[derive(Debug)]
pub struct Ref<'a>(&'a mut Source, usize);
// this is similar to nix::dir::Iter
// which implements Iterator<Item = nix::Result<nix::dir::Entry>>
trait Foo<T, R> {
fn borrow(&self, source: &mut T) -> R;
}
impl Foo<Source, Ref<'_>> for () {
fn borrow<'a>(&self, source: &'a mut Source) -> Ref<'a> {
Ref(source, 0)
}
}
fn main() {
println!("{:#?}", ().borrow(&mut Source(13)));
}
When I try to compile this with cargo run --bin sandbox
on a stable Rust, I get this error:
error: `impl` item signature doesn't match `trait` item signature
--> src/sandbox.rs:14:5
|
10 | fn borrow(&self, source: &mut T) -> R;
| -------------------------------------- expected fn(&(), &mut Source) -> Ref<'_>
...
14 | fn borrow<'a>(&self, source: &'a mut Source) -> Ref<'a> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&(), &mut Source) -> Ref<'_>
|
= note: expected `fn(&(), &mut Source) -> Ref<'_>`
found `fn(&(), &mut Source) -> Ref<'_>`
The "expected" and "found" parts look equal to me. What's going on?
Where (if anywhere) do I put the lifetime parameters such that I can return a new object containing a mutable reference to an argument from a trait method, when that object's type is parameterized by a lifetime?
I guess instead of returning an iterator I could have my trait implementations be responsible for doing the iteration and returning a vector, or I can take a callback, or whatever—I'm confident I can solve my practical problem, but I would love to understand Rust a little better.