(index<- )        ./libsyntax/ext/deriving/hash.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   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.
   4  //
   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.
  10  
  11  use ast;
  12  use ast::{MetaItem, Item, Expr, MutMutable};
  13  use codemap::Span;
  14  use ext::base::ExtCtxt;
  15  use ext::build::AstBuilder;
  16  use ext::deriving::generic::*;
  17  use parse::token::InternedString;
  18  
  19  pub fn expand_deriving_hash(cx: &mut ExtCtxt,
  20                              spanSpan,
  21                              mitem: @MetaItem,
  22                              item: @Item,
  23                              push: |@Item|) {
  24  
  25      let (path, generics, args) = if cx.ecfg.deriving_hash_type_parameter {
  26          (Path::new_(vec!("std", "hash", "Hash"), None,
  27                      vec!(box Literal(Path::new_local("__S"))), true),
  28           LifetimeBounds {
  29               lifetimes: Vec::new(),
  30               bounds: vec!(("__S", ast::StaticSize, vec!(Path::new(vec!("std", "io", "Writer"))))),
  31           },
  32           Path::new_local("__S"))
  33      } else {
  34          (Path::new(vec!("std", "hash", "Hash")),
  35           LifetimeBounds::empty(),
  36           Path::new(vec!("std", "hash", "sip", "SipState")))
  37      };
  38      let inline = cx.meta_word(span, InternedString::new("inline"));
  39      let attrs = vec!(cx.attribute(span, inline));
  40      let hash_trait_def = TraitDef {
  41          span: span,
  42          attributes: Vec::new(),
  43          path: path,
  44          additional_bounds: Vec::new(),
  45          generics: generics,
  46          methods: vec!(
  47              MethodDef {
  48                  name: "hash",
  49                  generics: LifetimeBounds::empty(),
  50                  explicit_self: borrowed_explicit_self(),
  51                  args: vec!(Ptr(box Literal(args), Borrowed(None, MutMutable))),
  52                  ret_ty: nil_ty(),
  53                  attributes: attrs,
  54                  const_nonmatching: false,
  55                  combine_substructure: combine_substructure(|a, b, c| {
  56                      hash_substructure(a, b, c)
  57                  })
  58              }
  59          )
  60      };
  61  
  62      hash_trait_def.expand(cx, mitem, item, push);
  63  }
  64  
  65  fn hash_substructure(cx: &mut ExtCtxt, trait_spanSpan, substr: &Substructure) -> @Expr {
  66      let state_expr = match substr.nonself_args {
  67          [state_expr] => state_expr,
  68          _ => cx.span_bug(trait_span, "incorrect number of arguments in `deriving(Hash)`")
  69      };
  70      let hash_ident = substr.method_ident;
  71      let call_hash = |span, thing_expr| {
  72          let expr = cx.expr_method_call(span, thing_expr, hash_ident, vec!(state_expr));
  73          cx.stmt_expr(expr)
  74      };
  75      let mut stmts = Vec::new();
  76  
  77      let fields = match *substr.fields {
  78          Struct(ref fs) => fs,
  79          EnumMatching(index, variant, ref fs) => {
  80              // Determine the discriminant. We will feed this value to the byte
  81              // iteration function.
  82              let discriminant = match variant.node.disr_expr {
  83                  Some(d) => d,
  84                  None => cx.expr_uint(trait_span, index)
  85              };
  86  
  87              stmts.push(call_hash(trait_span, discriminant));
  88  
  89              fs
  90          }
  91          _ => cx.span_bug(trait_span, "impossible substructure in `deriving(Hash)`")
  92      };
  93  
  94      for &FieldInfo { self_, span, .. } in fields.iter() {
  95          stmts.push(call_hash(span, self_));
  96      }
  97  
  98      if stmts.len() == 0 {
  99          cx.span_bug(trait_span, "#[deriving(Hash)] needs at least one field");
 100      }
 101  
 102      cx.expr_block(cx.block(trait_span, stmts, None))
 103  }