aboutsummaryrefslogtreecommitdiff
path: root/syn/examples/heapsize/README.md
blob: e78955990d8e7b7f9a5cecf3e84778a57fb02769 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
A derive macro that generates trait impls.

- [`heapsize/src/lib.rs`](heapsize/src/lib.rs)
- [`heapsize_derive/src/lib.rs`](heapsize_derive/src/lib.rs)
- [`example/src/main.rs`](example/src/main.rs)

We are deriving the `HeapSize` trait which computes an estimate of the amount of
heap memory owned by a value.

```rust
pub trait HeapSize {
    /// Total number of bytes of heap memory owned by `self`.
    fn heap_size_of_children(&self) -> usize;
}
```

The derive macro allows users to write `#[derive(HeapSize)]` on data structures
in their program.

```rust
#[derive(HeapSize)]
struct Demo<'a, T: ?Sized> {
    a: Box<T>,
    b: u8,
    c: &'a str,
    d: String,
}
```

The trait impl generated by the derive macro here would look like:

```rust
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 &mdash; everything is as shown in this directory &mdash;
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`
```