Skip to content

Commit 07f5ab1

Browse files
committed
Implement a deriving(Zero) attribute
1 parent eadd83d commit 07f5ab1

File tree

3 files changed

+138
-0
lines changed

3 files changed

+138
-0
lines changed

src/libsyntax/ext/deriving/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ pub mod encodable;
3232
pub mod decodable;
3333
pub mod rand;
3434
pub mod to_str;
35+
pub mod zero;
3536

3637
#[path="cmp/eq.rs"]
3738
pub mod eq;
@@ -99,6 +100,7 @@ pub fn expand_meta_deriving(cx: @ExtCtxt,
99100
"Rand" => expand!(rand::expand_deriving_rand),
100101

101102
"ToStr" => expand!(to_str::expand_deriving_to_str),
103+
"Zero" => expand!(zero::expand_deriving_zero),
102104

103105
ref tname => {
104106
cx.span_err(titem.span, fmt!("unknown \

src/libsyntax/ext/deriving/zero.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright 2012-2013 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 core::prelude::*;
12+
13+
use ast::{meta_item, item, expr};
14+
use codemap::span;
15+
use ext::base::ExtCtxt;
16+
use ext::build::AstBuilder;
17+
use ext::deriving::generic::*;
18+
19+
use core::vec;
20+
21+
pub fn expand_deriving_zero(cx: @ExtCtxt,
22+
span: span,
23+
mitem: @meta_item,
24+
in_items: ~[@item])
25+
-> ~[@item] {
26+
let trait_def = TraitDef {
27+
path: Path::new(~["std", "num", "Zero"]),
28+
additional_bounds: ~[],
29+
generics: LifetimeBounds::empty(),
30+
methods: ~[
31+
MethodDef {
32+
name: "zero",
33+
generics: LifetimeBounds::empty(),
34+
explicit_self: None,
35+
args: ~[],
36+
ret_ty: Self,
37+
const_nonmatching: false,
38+
combine_substructure: zero_substructure
39+
},
40+
MethodDef {
41+
name: "is_zero",
42+
generics: LifetimeBounds::empty(),
43+
explicit_self: borrowed_explicit_self(),
44+
args: ~[],
45+
ret_ty: Literal(Path::new(~["bool"])),
46+
const_nonmatching: false,
47+
combine_substructure: |cx, span, substr| {
48+
cs_and(|cx, span, _, _| cx.span_bug(span,
49+
"Non-matching enum \
50+
variant in \
51+
deriving(Zero)"),
52+
cx, span, substr)
53+
}
54+
}
55+
]
56+
};
57+
trait_def.expand(cx, span, mitem, in_items)
58+
}
59+
60+
fn zero_substructure(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr {
61+
let zero_ident = ~[
62+
cx.ident_of("std"),
63+
cx.ident_of("num"),
64+
cx.ident_of("Zero"),
65+
cx.ident_of("zero")
66+
];
67+
let zero_call = || {
68+
cx.expr_call_global(span, copy zero_ident, ~[])
69+
};
70+
71+
return match *substr.fields {
72+
StaticStruct(_, ref summary) => {
73+
match *summary {
74+
Left(count) => {
75+
if count == 0 {
76+
cx.expr_ident(span, substr.type_ident)
77+
} else {
78+
let exprs = vec::from_fn(count, |_| zero_call());
79+
cx.expr_call_ident(span, substr.type_ident, exprs)
80+
}
81+
}
82+
Right(ref fields) => {
83+
let zero_fields = do fields.map |ident| {
84+
cx.field_imm(span, *ident, zero_call())
85+
};
86+
cx.expr_struct_ident(span, substr.type_ident, zero_fields)
87+
}
88+
}
89+
}
90+
StaticEnum(*) => {
91+
cx.span_fatal(span, "`Zero` cannot be derived for enums, \
92+
only structs")
93+
}
94+
_ => cx.bug("Non-static method in `deriving(Zero)`")
95+
};
96+
}

src/test/run-pass/deriving-zero.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2012-2013 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 std::util;
12+
use std::num::Zero;
13+
14+
#[deriving(Zero)]
15+
struct A;
16+
#[deriving(Zero)]
17+
struct B(int);
18+
#[deriving(Zero)]
19+
struct C(int, int);
20+
#[deriving(Zero)]
21+
struct D { a: int }
22+
#[deriving(Zero)]
23+
struct E { a: int, b: int }
24+
25+
#[deriving(Zero)]
26+
struct Lots {
27+
a: ~str,
28+
b: @str,
29+
c: Option<util::NonCopyable>,
30+
d: u8,
31+
e: char,
32+
f: float,
33+
g: (f32, char),
34+
h: ~[util::NonCopyable],
35+
i: @mut (int, int),
36+
}
37+
38+
fn main() {
39+
assert!(Zero::zero::<Lots>().is_zero());
40+
}

0 commit comments

Comments
 (0)