derive_more
derive_more copied to clipboard
Add support for deriving Clone/Copy and other standard traits without generic type parameter transitiveness
The built-in #[derive(Copy, Clone)] and others in Rust have this rule that all generic type parameters must also implement Copy or Clone. Perhaps the logic relies on this to ensure that all fields really can be copied/cloned/compared?
However, this is not always desirable. For example, some generic type parameter might simply be used by reference:
trait Bar {}
#[derive(Copy, Clone)]
struct Foo<B: Bar> {
bar: &'static B
}
While the reference bar is perfectly copyable, Rust will complain here and say that Copy and Clone methods cannot be called because B: Clone is not satisfied: Rust Playground.
error[E0599]: the method `clone` exists for struct `Foo<BarImpl>`, but its trait bounds were not satisfied
--> src\main.rs:14:20
|
4 | struct Foo<B: Bar> {
| ------------------ method `clone` not found for this struct because it doesn't satisfy `Foo<BarImpl>: Clone`
...
8 | struct BarImpl;
| -------------- doesn't satisfy `BarImpl: Clone`
...
14 | let foo2 = foo.clone();
| ^^^^^ method cannot be called on `Foo<BarImpl>` due to unsatisfied trait bounds
|
note: trait bound `BarImpl: Clone` was not satisfied
--> src\main.rs:3:16
|
3 | #[derive(Copy, Clone)]
| ^^^^^ unsatisfied trait bound introduced in this `derive` macro
help: consider annotating `BarImpl` with `#[derive(Clone)]`
|
8 + #[derive(Clone)]
9 | struct BarImpl;
However, this check is excessively restrictive. Manually implementing Copy and Clone works fine because the type B is only used as a reference.
impl<B: Bar> Copy for Foo<B> {}
impl<B: Bar> Clone for Foo<B> {
fn clone(&self) -> Self {
Self { bar: self.bar.clone() }
}
}
The above compiles successfully and copies/clones the reference regardless of whether B itself impelments any of these traits.
trait Bar {}
#[derive(CopyMore, CloneMore)]
struct Foo<B: Bar> {
bar: &'static B
}
It would be very useful to have "explicit" variations of the built-in derive-macros for such situations, so we could #[derive(CopyMore, CloneMore, EqMore)] and just have an implementation generated that goes field by field without looking at the types and leaves it up to the compiler to detect actual field by field compatibility in the generated code.