1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use ast
::{MetaItem, Expr, MutMutable}
;
13 use ext
::base
::{ExtCtxt, Annotatable}
;
14 use ext
::build
::AstBuilder
;
15 use ext
::deriving
::generic
::*;
16 use ext
::deriving
::generic
::ty
::*;
19 pub fn expand_deriving_hash(cx
: &mut ExtCtxt
,
23 push
: &mut FnMut(Annotatable
))
26 let path
= Path
::new_(pathvec_std
!(cx
, core
::hash
::Hash
), None
,
28 let arg
= Path
::new_local("__H");
29 let hash_trait_def
= TraitDef
{
31 attributes
: Vec
::new(),
33 additional_bounds
: Vec
::new(),
34 generics
: LifetimeBounds
::empty(),
38 generics
: LifetimeBounds
{
39 lifetimes
: Vec
::new(),
41 vec
![path_std
!(cx
, core
::hash
::Hasher
)])],
43 explicit_self
: borrowed_explicit_self(),
44 args
: vec
!(Ptr(Box
::new(Literal(arg
)), Borrowed(None
, MutMutable
))),
47 combine_substructure
: combine_substructure(Box
::new(|a
, b
, c
| {
48 hash_substructure(a
, b
, c
)
52 associated_types
: Vec
::new(),
55 hash_trait_def
.expand(cx
, mitem
, &item
, push
);
58 fn hash_substructure(cx
: &mut ExtCtxt
, trait_span
: Span
, substr
: &Substructure
) -> P
<Expr
> {
59 let state_expr
= match (substr
.nonself_args
.len(), substr
.nonself_args
.get(0)) {
60 (1, Some(o_f
)) => o_f
,
61 _
=> cx
.span_bug(trait_span
, "incorrect number of arguments in `derive(Hash)`")
63 let call_hash
= |span
, thing_expr
| {
66 cx
.ident_of_std("core"),
72 cx
.expr_path(cx
.path_global(span
, strs
))
74 let ref_thing
= cx
.expr_addr_of(span
, thing_expr
);
75 let expr
= cx
.expr_call(span
, hash_path
, vec
!(ref_thing
, state_expr
.clone()));
78 let mut stmts
= Vec
::new();
80 let fields
= match *substr
.fields
{
82 EnumMatching(index
, variant
, ref fs
) => {
83 // Determine the discriminant. We will feed this value to the byte
84 // iteration function.
85 let discriminant
= match variant
.node
.disr_expr
{
86 Some(ref d
) => d
.clone(),
87 None
=> cx
.expr_usize(trait_span
, index
)
90 stmts
.push(call_hash(trait_span
, discriminant
));
94 _
=> cx
.span_bug(trait_span
, "impossible substructure in `derive(Hash)`")
97 for &FieldInfo { ref self_, span, .. }
in fields
{
98 stmts
.push(call_hash(span
, self_
.clone()));
101 cx
.expr_block(cx
.block(trait_span
, stmts
, None
))