A complete working implementation of a custom derive. Written in Rust 2018 style but otherwise works on any Rust compiler 1.15+.
We are deriving the HeapSize trait which computes an estimate of the amount of
heap memory owned by a value.
pub trait HeapSize {
/// Total number of bytes of heap memory owned by `self`.
fn heap_size_of_children(&self) -> usize;
}The custom derive allows users to write #[derive(HeapSize)] on data structures
in their program.
#[derive(HeapSize)]
struct Demo<'a, T: ?Sized> {
a: Box<T>,
b: u8,
c: &'a str,
d: String,
}The trait impl generated by the custom derive here would look like:
impl<'a, T: ?Sized + ::heapsize::HeapSize> ::heapsize::HeapSize for Demo<'a, T> {
fn heap_size_of_children(&self) -> usize {
0 + ::heapsize::HeapSize::heap_size_of_children(&self.a)
+ ::heapsize::HeapSize::heap_size_of_children(&self.b)
+ ::heapsize::HeapSize::heap_size_of_children(&self.c)
+ ::heapsize::HeapSize::heap_size_of_children(&self.d)
}
}The implementation of heapsize_derive demonstrates some attention to "spans"
of error messages. For each subexpression in the generated code we apply the
span of the input fragment under which we would want to trigger a compiler error
if the subexpression fails to compile. In this example, each recursive call to
heap_size_of_children is associated with the span of the corresponding struct
field. Thus we get errors in the right place if any of the field types do not
implement the HeapSize trait.
error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied
--> src/main.rs:7:5
|
7 | bad: std::thread::Thread,
| ^^^ the trait `HeapSize` is not implemented for `std::thread::Thread`
Some unstable APIs in the proc-macro2 crate let us improve this further by
joining together the span of the field name and the field type. There is no
difference in our code -- everything is as shown in this directory -- but
building the example crate with cargo build shows errors like the one above
and building with RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo build is
able to show errors like the following.
error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied
--> src/main.rs:7:5
|
7 | bad: std::thread::Thread,
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `std::thread::Thread`