Skip to content

Commit

Permalink
Add enums to deepsize_derive, migrate to 2015 edition
Browse files Browse the repository at this point in the history
Using the 2015 edition until rust-lang/rust#57407 is merged, so that the derive macro can be used within the crate (for tests)
  • Loading branch information
Aeledfyr committed Jan 25, 2019
1 parent 80d11dd commit 8c87216
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 63 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description = "A crate for measuring the total size of object on the stack and h
repository = "https://github.com/Aeledfyr/deepsize/"
readme = "README.md"
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE"]
edition = "2018"
edition = "2015"

[dependencies]
deepsize_derive = { path = "deepsize_derive", version = "0.1" }
2 changes: 1 addition & 1 deletion deepsize_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ license = "MIT"
description = "A crate for measuring the total size of object on the stack and heap"
repository = "https://github.com/Aeledfyr/deepsize/"
include = ["Cargo.toml", "src/**/*.rs", "../LICENSE"]
edition = "2018"
edition = "2015"

[lib]
proc-macro = true
Expand Down
143 changes: 113 additions & 30 deletions deepsize_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
/// Mainly from `syn`'s heap_size derive example:
/// https://github.com/dtolnay/syn/commits/master/examples/heapsize/heapsize_derive/src/lib.rs
extern crate proc_macro;
extern crate proc_macro2;
extern crate syn;
extern crate quote;

use proc_macro2::TokenStream;
use quote::{quote, quote_spanned};
Expand All @@ -24,7 +27,7 @@ pub fn derive_deep_size(input: proc_macro::TokenStream) -> proc_macro::TokenStre
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

// Generate an expression to sum up the size of each field.
let sum = deepsize_sum(&input.data);
let sum = deepsize_sum(&input.data, &name);

let expanded = quote! {
// The generated impl.
Expand All @@ -49,39 +52,119 @@ fn add_trait_bounds(mut generics: Generics) -> Generics {
generics
}

// Generate an expression to sum up the size of each field.
fn deepsize_sum(data: &Data) -> TokenStream {
match *data {
Data::Struct(ref data) => {
match data.fields {
Fields::Named(ref fields) => {
let recurse = fields.named.iter().map(|f| {
let name = &f.ident;
quote_spanned! {f.span()=>
::deepsize::DeepSizeOf::deep_size_of_children(&self.#name, context)
}
});
quote! {
0 #(+ #recurse)*
}
fn match_fields(fields: &syn::Fields) -> TokenStream {
match fields {
Fields::Named(ref fields) => {
let recurse = fields.named.iter().map(|f| {
let name = &f.ident;
quote_spanned! {f.span()=>
::deepsize::DeepSizeOf::deep_size_of_children(&self.#name, context)
}
});
quote! {
0 #(+ #recurse)*
}
}
Fields::Unnamed(ref fields) => {
let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
let index = Index::from(i);
quote_spanned! {f.span()=>
::deepsize::DeepSizeOf::deep_size_of_children(&self.#index, context)
}
});
quote! {
0 #(+ #recurse)*
}
}
Fields::Unit => {
// Unit structs cannot own more than 0 bytes of memory.
quote!(0)
}
}
}

fn match_enum_fields(fields: &syn::Fields) -> TokenStream {
match fields {
Fields::Named(ref fields) => {
let recurse = fields.named.iter().map(|f| {
let name = &f.ident;
quote_spanned! {f.span()=>
::deepsize::DeepSizeOf::deep_size_of_children(#name, context)
}
Fields::Unnamed(ref fields) => {
let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
let index = Index::from(i);
quote_spanned! {f.span()=>
::deepsize::DeepSizeOf::deep_size_of_children(&self.#index, context)
}
});
quote! {
0 #(+ #recurse)*
}
});
quote! {
0 #(+ #recurse)*
}
}
Fields::Unnamed(ref fields) => {
let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
let i = syn::Ident::new(&format!("_{}", i), proc_macro2::Span::call_site());
quote_spanned! {f.span()=>
::deepsize::DeepSizeOf::deep_size_of_children(#i, context)
}
Fields::Unit => {
// Unit structs cannot own more than 0 bytes of memory.
quote!(0)
});
quote! {
0 #(+ #recurse)*
}
}
Fields::Unit => {
// Unit structs cannot own more than 0 bytes of memory.
quote!(0)
}
}
}

fn get_matcher(var: &syn::Variant) -> TokenStream {
let matcher = match &var.fields {
Fields::Unit => TokenStream::new(),
Fields::Unnamed(fields) => {
let fields: TokenStream = (0..fields.unnamed.len())
.map(|n| {
let i = syn::Ident::new(&format!("_{}", n), proc_macro2::Span::call_site());
quote!(#i,)
})
.collect();
quote!((#fields))
}
Fields::Named(fields) => {
let fields: TokenStream = fields
.named
.iter()
.map(|f| {
let i = f.ident.as_ref().unwrap();
quote!(#i,)
})
.collect();
quote!({#fields})
}
};

quote!(#matcher)
}

// Generate an expression to sum up the size of each field.
fn deepsize_sum(data: &Data, struct_name: &proc_macro2::Ident) -> TokenStream {
match *data {
Data::Struct(ref inner) => {
match_fields(&inner.fields)
}
Data::Enum(ref inner) => {
let arms = inner.variants.iter()
.map(|var| {
let matcher = get_matcher(var);
let output = match_enum_fields(&var.fields);
let name = &var.ident;
let ident = quote!(#struct_name::#name);
quote!(#ident #matcher => #output,)
});

quote! {
match self {
#(#arms)*
_ => 0 // This is needed for empty enums
}
}
}
Data::Enum(_) | Data::Union(_) => unimplemented!(),
Data::Union(_) => unimplemented!(),
}
}
2 changes: 2 additions & 0 deletions examples/derive.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
extern crate deepsize;

use deepsize::DeepSizeOf;

#[derive(DeepSizeOf)]
Expand Down
52 changes: 23 additions & 29 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@
//! ```
//!
// Hack so that #[derive(DeepSizeOf)] is usable within the crate
// until [this](https://github.com/rust-lang/rust/pull/57407) stabalizes
// Also means that both crates need to be on the 2015 edition
mod deepsize { pub use super::*; }

extern crate deepsize_derive;

pub use deepsize_derive::*;

use std::collections::HashSet;
Expand Down Expand Up @@ -73,7 +80,7 @@ pub trait DeepSizeOf {
/// This is an internal function, and requires a [`Context`](Context)
/// to track visited references.
fn recurse_deep_size_of(&self, context: &mut Context) -> usize {
self.stack_size() + self.deep_size_of_children(context)
std::mem::size_of_val(self) + self.deep_size_of_children(context)
}

/// Returns an estimation of a total size of memory owned by the
Expand All @@ -85,13 +92,6 @@ pub trait DeepSizeOf {
/// This is an internal function, and requires a [`Context`](Context)
/// to track visited references.
fn deep_size_of_children(&self, context: &mut Context) -> usize;

/// Returns the size of the memory the object uses itself
///
/// This method is generally equivalent to [`size_of_val`](std::mem::size_of_val)
fn stack_size(&self) -> usize {
std::mem::size_of_val(self)
}
}


Expand Down Expand Up @@ -198,8 +198,8 @@ where
/// ```
fn deep_size_of_children(&self, context: &mut Context) -> usize {
self.iter()
.fold(0, |sum, child| sum + child.recurse_deep_size_of(context))
+ (self.capacity() - self.len()) * std::mem::size_of::<T>()
.fold(0, |sum, child| sum + child.deep_size_of_children(context))
+ self.capacity() * std::mem::size_of::<T>()
// Size of unused capacity
}
}
Expand Down Expand Up @@ -241,8 +241,8 @@ where
/// ```
fn deep_size_of_children(&self, context: &mut Context) -> usize {
self.iter()
.fold(0, |sum, child| sum + child.recurse_deep_size_of(context))
+ (self.capacity() - self.len()) * std::mem::size_of::<T>()
.fold(0, |sum, child| sum + child.deep_size_of_children(context))
+ self.capacity() * std::mem::size_of::<T>()
// Size of unused capacity
}
}
Expand Down Expand Up @@ -287,10 +287,9 @@ where
.fold(0, |sum, (key, val)| {
sum + key.deep_size_of_children(context)
+ val.deep_size_of_children(context)
+ std::mem::size_of::<Option<(u64, K, V)>>()
})
+ (self.capacity() - self.len()) * (std::mem::size_of::<Option<(u64, K, V)>>())
// Size of unused capacity
+ self.capacity() * std::mem::size_of::<Option<(u64, K, V)>>()
// Size of container capacity
}
}

Expand All @@ -302,10 +301,9 @@ where
self.iter()
.fold(0, |sum, item| {
sum + item.deep_size_of_children(context)
+ std::mem::size_of::<Option<(u64, T, ())>>()
})
+ (self.capacity() - self.len()) * (std::mem::size_of::<Option<(u64, T, ())>>())
// Size of unused capacity
+ self.capacity() * std::mem::size_of::<Option<(u64, T, ())>>()
// Size container storage
}
}

Expand All @@ -331,10 +329,10 @@ where

fn recurse_deep_size_of(&self, context: &mut Context) -> usize {
if context.contains_arc(self) {
self.stack_size()
std::mem::size_of::<Self>()
} else {
context.add_arc(self);
self.stack_size() + self.deep_size_of_children(context)
std::mem::size_of::<Self>() + self.deep_size_of_children(context)
}
}
}
Expand All @@ -350,10 +348,10 @@ where

fn recurse_deep_size_of(&self, context: &mut Context) -> usize {
if context.contains_rc(self) {
self.stack_size()
std::mem::size_of::<Self>()
} else {
context.add_rc(self);
self.stack_size() + self.deep_size_of_children(context)
std::mem::size_of::<Self>() + self.deep_size_of_children(context)
}
}
}
Expand All @@ -373,10 +371,10 @@ where

fn recurse_deep_size_of(&self, context: &mut Context) -> usize {
if context.contains_ref(&self) {
self.stack_size()
std::mem::size_of::<Self>()
} else {
context.add_ref(&self);
self.stack_size() + self.deep_size_of_children(context)
std::mem::size_of::<Self>() + self.deep_size_of_children(context)
}
}
}
Expand All @@ -387,10 +385,6 @@ where
{
fn deep_size_of_children(&self, context: &mut Context) -> usize {
self.iter()
.fold(0, |sum, child| sum + child.recurse_deep_size_of(context))
}

fn stack_size(&self) -> usize {
0
.fold(0, |sum, child| sum + child.deep_size_of_children(context))
}
}
15 changes: 13 additions & 2 deletions src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ fn alignment() {
assert_eq!(std::mem::size_of::<[Test; 3]>(), array.deep_size_of());

let vec = vec![Test(5), Test(16), Test(2)];
assert_eq!(array.deep_size_of(), 256 * 3);
assert_eq!(vec.deep_size_of(), 256 * 3 + 24);

let vec = vec![Test2(Test(5), 0), Test2(Test(16), 0), Test2(Test(2), 0)];
assert_eq!(array.deep_size_of(), 256 * 3);
assert_eq!(vec.deep_size_of(), 512 * 3 + 24);
}

mod context_tests {
Expand Down Expand Up @@ -94,3 +94,14 @@ mod context_tests {
}
}

fn test_derive() {

#[derive(DeepSizeOf)]
enum Example {
One,
Two(),
Three(u32, Box<u8>),
Four { name: Box<u32> },
Five { },
}
}

0 comments on commit 8c87216

Please sign in to comment.