Let's suppose I have a Trait Tr, defined as such:
trait Tr {
fn tr(&self);
}
I have the Trait implemented for some type, say X:
struct X;
impl Tr for X {
fn tr(self) {}
}
Now I would like to impl Tr for any type which can be turned into an iterator over references to values implementing Tr.
I have tried this: (playground)
impl<T: IntoIterator<Item = impl Tr>> Tr for T {
fn tr(&self) { self.into_iter().for_each(|value| value.tr()) }
}
But it doesn't compile because IntoIterator::into_iter takes self by move and my trait only receives a reference.
With that, I attempted to make the trait take self by move as well and implement it for references: (playground)
struct X;
trait Tr {
fn tr(self);
}
impl Tr for &X {
fn tr(self) {}
}
impl<T: IntoIterator<Item = impl Tr>> Tr for T {
fn tr(self) { self.into_iter().for_each(|value| value.tr()) }
}
This compiles fine, but only works for collections which hold values of X. My goal is for it to work on collections holding references to X, e.g.: [&X].
To solve this, I have implemented Tr for double references to X, which works, but looks weird: (playground)
impl Tr for &&X {
fn tr(self) {}
}
This also doesn't allow me to call tr directly on instances of X as it was possible when using impl for a single reference: X.tr() and instead I have to put X behind at least one reference to call tr on it: (&X).tr(). This can of course be resolved by adding another impl for a single reference, but it increases the complexity a lot when I have many types that implement Tr.
The question is, is this the correct way to do this in Rust? Can I simplify the code in any way or get rid of the "take self by move" altogether?
Edit: Ideally, the result should allow all of the following:
X.tr();
[&X].tr();
vec![&X].tr();
(&[&X]).tr();
(&vec![&X]).tr();