Crates.io | perfect-derive |
lib.rs | perfect-derive |
version | 0.1.3 |
source | src |
created_at | 2022-11-13 12:59:46.230484 |
updated_at | 2023-10-19 14:30:49.695737 |
description | Provides a prototype of the proposed perfect_derive macro |
homepage | https://github.com/LucentFlux/perfect-derive |
repository | https://github.com/LucentFlux/perfect-derive |
max_upload_size | |
id | 714184 |
size | 43,954 |
Adds derive macros for better bounds on generated Copy, Debug, etc. implementations.
See this blog post for a summary of the issue.
Since Rust cannot handle cyclic bounds, these macros won't always work. Ideally, in a few years this crate can become a no-op and there will be some way to do this in plain Rust, but until then this hack helps clean up some code.
Taken from Niko's blog above:
#[derive(Clone)]
struct List<T> {
data: Rc<T>,
next: Option<Rc<List<T>>>,
}
impl<T> Deref for List<T> {
type Target = T;
fn deref(&self) -> &T { &self.data }
}
Currently, derive is going to generate an impl that requires T: Clone
, like this…
impl<T> Clone for List<T>
where
T: Clone,
{
fn clone(&self) {
List {
value: self.value.clone(),
next: self.next.clone(),
}
}
}
The T: Clone
requirement here is not actually necessary. This is because the only T
in this struct is inside of an Rc
, and hence is reference counted. Cloning the Rc
only increments the reference count, it doesn’t actually create a new T
.
With perfect derive, we can do the following instead:
#[perfect_derive(Clone)]
struct List<T> { /* as before */ }
Which generates "better" bounds on the implementation:
impl<T> Clone for List<T>
where
Rc<T>: Clone, // type of the `value` field
Option<Rc<List<T>>: Clone, // type of the `next` field
{
fn clone(&self) { /* as before */ }
}
Note that these bounds do not require that T
is itself clonable.