• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1A derive macro that generates trait impls.
2
3- [`heapsize/src/lib.rs`](heapsize/src/lib.rs)
4- [`heapsize_derive/src/lib.rs`](heapsize_derive/src/lib.rs)
5- [`example/src/main.rs`](example/src/main.rs)
6
7We are deriving the `HeapSize` trait which computes an estimate of the amount of
8heap memory owned by a value.
9
10```rust
11pub trait HeapSize {
12    /// Total number of bytes of heap memory owned by `self`.
13    fn heap_size_of_children(&self) -> usize;
14}
15```
16
17The derive macro allows users to write `#[derive(HeapSize)]` on data structures
18in their program.
19
20```rust
21#[derive(HeapSize)]
22struct Demo<'a, T: ?Sized> {
23    a: Box<T>,
24    b: u8,
25    c: &'a str,
26    d: String,
27}
28```
29
30The trait impl generated by the derive macro here would look like:
31
32```rust
33impl<'a, T: ?Sized + heapsize::HeapSize> heapsize::HeapSize for Demo<'a, T> {
34    fn heap_size_of_children(&self) -> usize {
35        0 + heapsize::HeapSize::heap_size_of_children(&self.a)
36            + heapsize::HeapSize::heap_size_of_children(&self.b)
37            + heapsize::HeapSize::heap_size_of_children(&self.c)
38            + heapsize::HeapSize::heap_size_of_children(&self.d)
39    }
40}
41```
42
43The implementation of `heapsize_derive` demonstrates some attention to "spans"
44of error messages. For each subexpression in the generated code we apply the
45span of the input fragment under which we would want to trigger a compiler error
46if the subexpression fails to compile. In this example, each recursive call to
47`heap_size_of_children` is associated with the span of the corresponding struct
48field. Thus we get errors in the right place if any of the field types do not
49implement the `HeapSize` trait.
50
51```
52error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied
53 --> src/main.rs:7:5
54  |
557 |     bad: std::thread::Thread,
56  |     ^^^ the trait `HeapSize` is not implemented for `std::thread::Thread`
57```
58
59Some unstable APIs in the `proc-macro2` crate let us improve this further by
60joining together the span of the field name and the field type. There is no
61difference in our code &mdash; everything is as shown in this directory &mdash;
62but building the example crate with `cargo build` shows errors like the one
63above and building with `RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo build`
64is able to show errors like the following.
65
66```
67error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied
68 --> src/main.rs:7:5
69  |
707 |     bad: std::thread::Thread,
71  |     ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `std::thread::Thread`
72```
73