use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::codemap::Span;
use syntax::ptr::P;
use syntax::ast::*;
use syntax::ext::build::AstBuilder;
use syntax_ext::deriving::generic::*;
pub fn expand_heap_size(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem,
item: &Annotatable, push: &mut FnMut(Annotatable)) {
let trait_def = TraitDef {
is_unsafe: false,
span: span,
attributes: Vec::new(),
path: ty::Path::new(vec!("heapsize", "HeapSizeOf")),
additional_bounds: Vec::new(),
generics: ty::LifetimeBounds::empty(),
supports_unions: true,
methods: vec![
MethodDef {
name: "heap_size_of_children",
generics: ty::LifetimeBounds::empty(),
explicit_self: ty::borrowed_explicit_self(),
args: vec!(),
ret_ty: ty::Literal(ty::Path::new_local("usize")),
attributes: vec!(),
is_unsafe: false,
combine_substructure: combine_substructure(Box::new(heap_size_substructure)),
unify_fieldless_variants: true,
}
],
associated_types: vec![],
};
trait_def.expand(cx, mitem, item, push)
}
fn heap_size_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
let fields = match *substr.fields {
Struct(_, ref fs) | EnumMatching(_, _, ref fs) => fs,
_ => cx.span_bug(trait_span, "impossible substructure in `#[derive(HeapSizeOf)]`")
};
fields.iter().fold(cx.expr_usize(trait_span, 0), |acc, ref item| {
let has_ignore = item.attrs.iter()
.find(|ref a| {
if a.check_name("ignore_heap_size_of") {
match a.node.value.node {
MetaItemKind::NameValue(..) => (),
_ => cx.span_err(a.span, "#[ignore_heap_size_of] \
should have an explanation, \
e.g. #[ignore_heap_size_of = \"\"]")
}
true
} else {
false
}
})
.is_some();
if has_ignore {
acc
} else {
cx.expr_binary(item.span, BinOpKind::Add, acc,
cx.expr_method_call(item.span,
item.self_.clone(),
substr.method_ident,
Vec::new()))
}
})
}