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 — everything is as shown in this directory — 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