diff options
Diffstat (limited to 'syn/examples/heapsize')
-rw-r--r-- | syn/examples/heapsize/Cargo.toml | 2 | ||||
-rw-r--r-- | syn/examples/heapsize/README.md | 72 | ||||
-rw-r--r-- | syn/examples/heapsize/example/Cargo.toml | 9 | ||||
-rw-r--r-- | syn/examples/heapsize/example/src/main.rs | 28 | ||||
-rw-r--r-- | syn/examples/heapsize/heapsize/Cargo.toml | 9 | ||||
-rw-r--r-- | syn/examples/heapsize/heapsize/src/lib.rs | 64 | ||||
-rw-r--r-- | syn/examples/heapsize/heapsize_derive/Cargo.toml | 14 | ||||
-rw-r--r-- | syn/examples/heapsize/heapsize_derive/src/lib.rs | 96 |
8 files changed, 0 insertions, 294 deletions
diff --git a/syn/examples/heapsize/Cargo.toml b/syn/examples/heapsize/Cargo.toml deleted file mode 100644 index 9b19214..0000000 --- a/syn/examples/heapsize/Cargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[workspace] -members = ["example", "heapsize", "heapsize_derive"] diff --git a/syn/examples/heapsize/README.md b/syn/examples/heapsize/README.md deleted file mode 100644 index e789559..0000000 --- a/syn/examples/heapsize/README.md +++ /dev/null @@ -1,72 +0,0 @@ -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 — 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` -``` diff --git a/syn/examples/heapsize/example/Cargo.toml b/syn/examples/heapsize/example/Cargo.toml deleted file mode 100644 index 85c7699..0000000 --- a/syn/examples/heapsize/example/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "heapsize_example" -version = "0.0.0" -authors = ["David Tolnay <dtolnay@gmail.com>"] -edition = "2018" -publish = false - -[dependencies] -heapsize = { path = "../heapsize" } diff --git a/syn/examples/heapsize/example/src/main.rs b/syn/examples/heapsize/example/src/main.rs deleted file mode 100644 index 9332b11..0000000 --- a/syn/examples/heapsize/example/src/main.rs +++ /dev/null @@ -1,28 +0,0 @@ -use heapsize::HeapSize; - -#[derive(HeapSize)] -struct Demo<'a, T: ?Sized> { - a: Box<T>, - b: u8, - c: &'a str, - d: String, -} - -fn main() { - let demo = Demo { - a: b"bytestring".to_vec().into_boxed_slice(), - b: 255, - c: "&'static str", - d: "String".to_owned(), - }; - - // 10 + 0 + 0 + 6 = 16 - println!( - "heap size = {} + {} + {} + {} = {}", - demo.a.heap_size_of_children(), - demo.b.heap_size_of_children(), - demo.c.heap_size_of_children(), - demo.d.heap_size_of_children(), - demo.heap_size_of_children() - ); -} diff --git a/syn/examples/heapsize/heapsize/Cargo.toml b/syn/examples/heapsize/heapsize/Cargo.toml deleted file mode 100644 index 27bb954..0000000 --- a/syn/examples/heapsize/heapsize/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "heapsize" -version = "0.0.0" -authors = ["David Tolnay <dtolnay@gmail.com>"] -edition = "2018" -publish = false - -[dependencies] -heapsize_derive = { path = "../heapsize_derive" } diff --git a/syn/examples/heapsize/heapsize/src/lib.rs b/syn/examples/heapsize/heapsize/src/lib.rs deleted file mode 100644 index 30bb6d6..0000000 --- a/syn/examples/heapsize/heapsize/src/lib.rs +++ /dev/null @@ -1,64 +0,0 @@ -use std::mem; - -pub use heapsize_derive::*; - -pub trait HeapSize { - /// Total number of bytes of heap memory owned by `self`. - /// - /// Does not include the size of `self` itself, which may or may not be on - /// the heap. Includes only children of `self`, meaning things pointed to by - /// `self`. - fn heap_size_of_children(&self) -> usize; -} - -// -// In a real version of this library there would be lots more impls here, but -// here are some interesting ones. -// - -impl HeapSize for u8 { - /// A `u8` does not own any heap memory. - fn heap_size_of_children(&self) -> usize { - 0 - } -} - -impl HeapSize for String { - /// A `String` owns enough heap memory to hold its reserved capacity. - fn heap_size_of_children(&self) -> usize { - self.capacity() - } -} - -impl<T> HeapSize for Box<T> -where - T: ?Sized + HeapSize, -{ - /// A `Box` owns however much heap memory was allocated to hold the value of - /// type `T` that we placed on the heap, plus transitively however much `T` - /// itself owns. - fn heap_size_of_children(&self) -> usize { - mem::size_of_val(&**self) + (**self).heap_size_of_children() - } -} - -impl<T> HeapSize for [T] -where - T: HeapSize, -{ - /// Sum of heap memory owned by each element of a dynamically sized slice of - /// `T`. - fn heap_size_of_children(&self) -> usize { - self.iter().map(HeapSize::heap_size_of_children).sum() - } -} - -impl<'a, T> HeapSize for &'a T -where - T: ?Sized, -{ - /// A shared reference does not own heap memory. - fn heap_size_of_children(&self) -> usize { - 0 - } -} diff --git a/syn/examples/heapsize/heapsize_derive/Cargo.toml b/syn/examples/heapsize/heapsize_derive/Cargo.toml deleted file mode 100644 index f4357b9..0000000 --- a/syn/examples/heapsize/heapsize_derive/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "heapsize_derive" -version = "0.0.0" -authors = ["David Tolnay <dtolnay@gmail.com>"] -edition = "2018" -publish = false - -[lib] -proc-macro = true - -[dependencies] -proc-macro2 = "1.0" -quote = "1.0" -syn = { path = "../../.." } diff --git a/syn/examples/heapsize/heapsize_derive/src/lib.rs b/syn/examples/heapsize/heapsize_derive/src/lib.rs deleted file mode 100644 index 9176b29..0000000 --- a/syn/examples/heapsize/heapsize_derive/src/lib.rs +++ /dev/null @@ -1,96 +0,0 @@ -extern crate proc_macro; - -use proc_macro2::TokenStream; -use quote::{quote, quote_spanned}; -use syn::spanned::Spanned; -use syn::{parse_macro_input, parse_quote, Data, DeriveInput, Fields, GenericParam, Generics, Index}; - -#[proc_macro_derive(HeapSize)] -pub fn derive_heap_size(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - // Parse the input tokens into a syntax tree. - let input = parse_macro_input!(input as DeriveInput); - - // Used in the quasi-quotation below as `#name`. - let name = input.ident; - - // Add a bound `T: HeapSize` to every type parameter T. - let generics = add_trait_bounds(input.generics); - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - - // Generate an expression to sum up the heap size of each field. - let sum = heap_size_sum(&input.data); - - let expanded = quote! { - // The generated impl. - impl #impl_generics heapsize::HeapSize for #name #ty_generics #where_clause { - fn heap_size_of_children(&self) -> usize { - #sum - } - } - }; - - // Hand the output tokens back to the compiler. - proc_macro::TokenStream::from(expanded) -} - -// Add a bound `T: HeapSize` to every type parameter T. -fn add_trait_bounds(mut generics: Generics) -> Generics { - for param in &mut generics.params { - if let GenericParam::Type(ref mut type_param) = *param { - type_param.bounds.push(parse_quote!(heapsize::HeapSize)); - } - } - generics -} - -// Generate an expression to sum up the heap size of each field. -fn heap_size_sum(data: &Data) -> TokenStream { - match *data { - Data::Struct(ref data) => { - match data.fields { - Fields::Named(ref fields) => { - // Expands to an expression like - // - // 0 + self.x.heap_size() + self.y.heap_size() + self.z.heap_size() - // - // but using fully qualified function call syntax. - // - // We take some care to use the span of each `syn::Field` as - // the span of the corresponding `heap_size_of_children` - // call. This way if one of the field types does not - // implement `HeapSize` then the compiler's error message - // underlines which field it is. An example is shown in the - // readme of the parent directory. - let recurse = fields.named.iter().map(|f| { - let name = &f.ident; - quote_spanned! {f.span()=> - heapsize::HeapSize::heap_size_of_children(&self.#name) - } - }); - quote! { - 0 #(+ #recurse)* - } - } - Fields::Unnamed(ref fields) => { - // Expands to an expression like - // - // 0 + self.0.heap_size() + self.1.heap_size() + self.2.heap_size() - let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| { - let index = Index::from(i); - quote_spanned! {f.span()=> - heapsize::HeapSize::heap_size_of_children(&self.#index) - } - }); - quote! { - 0 #(+ #recurse)* - } - } - Fields::Unit => { - // Unit structs cannot own more than 0 bytes of heap memory. - quote!(0) - } - } - } - Data::Enum(_) | Data::Union(_) => unimplemented!(), - } -} |