use derive2::derive2;
trait HeapSize {
fn heap_size(&self) -> usize;
}
impl HeapSize for String {
fn heap_size(&self) -> usize {
self.capacity()
}
}
macro_rules! heap_size {
(
@impl
$(#[$meta:meta])*
$vis:vis struct $name:ident {
$(
$(#[$($field_meta_tokens:tt)*])*
$field_vis:vis $field_name:ident: $field_ty:ty
),*
$(,)?
}
) => {
#[automatically_derived]
impl $crate::HeapSize for $name {
fn heap_size(&self) -> usize {
0 $(+ $crate::heap_size!(
@parse_attrs &self.$field_name, $(#[$($field_meta_tokens)*])*
))*
}
}
};
(
@parse_attrs
$else:expr,
#[heap_size(skip)]
$(#[$($rest:tt)*])*
) => {
0
};
(
@parse_attrs
$else:expr,
#[heap_size(with = $with_expr:expr)]
$(#[$($rest:tt)*])*
) => {
($with_expr)($else)
};
(
@parse_attrs
$else:expr,
#[heap_size $($other:tt)*]
$(#[$($rest:tt)*])*
) => {
compile_error!(concat!(
"Unrecognised heap_size attribute: ",
stringify!(#[heap_size $($other)*])
))
};
(
@parse_attrs
$else:expr,
#[$($first:tt)*]
$(#[$($rest:tt)*])*
) => {
{
$crate::heap_size! {
@parse_attrs
$else,
$(#[$($rest)*])*
}
}
};
(
@parse_attrs
$else:expr,
) => {
$crate::HeapSize::heap_size($else)
};
(@impl $($other:tt)*) => {
compile_error!{
concat!("unrecognised macro input: ", stringify!($($other)*))
}
};
($($other:tt)*) => {
$crate::heap_size! {
@impl $($other)*
}
}
}
use heap_size;
#[derive2(heap_size)]
#[derive(Debug, Default)]
struct LotsOfFields {
#[heap_size(skip)]
a: i32,
#[heap_size(skip)]
b: u8,
c: String,
#[heap_size(with = |v: &Vec<i32>| { v.capacity() * size_of::<i32>() })]
d: Vec<i32>,
}
fn main() {
let mut lof = LotsOfFields::default();
println!("lof = {lof:?}, heap_size is {}", lof.heap_size());
assert!(lof.heap_size() == 0);
lof.a = 42;
lof.b = u8::MAX;
println!("lof = {lof:?}, heap_size is {}", lof.heap_size());
assert!(lof.heap_size() == 0);
lof.c.push_str("hello world");
println!("lof = {lof:?}, heap_size is {}", lof.heap_size());
assert!(lof.heap_size() >= "hello_world".len());
lof.d = vec![1, 2, 3];
println!("lof = {lof:?}, heap_size is {}", lof.heap_size());
assert!(lof.heap_size() >= size_of::<[i32; 3]>() + "hello_world".len());
lof.c = String::new();
println!("lof = {lof:?}, heap_size is {}", lof.heap_size());
assert!(lof.heap_size() >= size_of::<[i32; 3]>());
lof.d = Vec::new();
assert!(lof.heap_size() == 0);
println!("All assertions passed!");
}