I wish to have an implementation for a struct with a generic that works when the generic is of a certain trait and ALSO when it is a reference to a value of the trait without duplicated code.
Here is a short example of the functionality I wish to have:
struct Foo<T>(T);
impl<T> Foo<T>
where
T: Bar,
{
fn foo_bar(&self) {
self.0.trait_method();
}
}
trait Bar {
fn trait_method(&self) {
println!("trait method called");
}
}
struct Baz;
impl Bar for Baz {}
fn main() {
let baz_move = Baz;
let foo1 = Foo(baz_move);
// works as expected, outputting "trait method called":
foo1.foo_bar();
let baz_ref = Baz;
let foo2 = Foo(&baz_ref);
// doesn't compile:
// foo2.foo_bar();
}
I understand why it doesn't compile but is there a nice way to make it work without code repetition/duplication? And also preferably a solution in the case where you do not have "ownership" of the said trait (unlike the example where the trait is in the same module, of course).
But with both of these methods exist much boilerplate, such as the delegation from the reference to the value. Is there no way to do something like this in the struct implementation:
impl<T> Foo<T>
where T: Any<Bar>
{
// methods that work with both bar trait objects and references to them
}
And this way I also don't need to have ownership of the trait. If that's not possible is there at least some crate that removes this boilerplate or something along the lines of that? Weird inconvenience...
T and &T are different types with different properties and thus different implementations, you can make yourself a proc macro to quickly doing the method forwarding but honestly i think it's a case of just accepting a bit of harmless boilerplate
Just to double check, you're not trying to do something related to dyn Bar and getting an error, are you? (Asking because your sketch doesn't work with "bar trait objects" -- dyn Bar + '_ -- it works with Sized types that implement Bar. (dyn Bar is not Sized.))
The orphan rules don't prevent implementing for LocalTy<Anything>. But you might get a coherence error (overlapping implementations, or the potential thereof) if you're trying to implement for both Foo<&dyn Bar> and Foo<T: Bar> or such. (If you're getting an error, share it.)
But if this is just about the inconvenience of having multiple implementations... you could perhaps move the multiple implementations around by having your own trait or such, but there's no language support for auto-generating implementations for different types (beyond generics). There's may be crates that supply macros to do what you want.