Skip to content

Add Enumerable trait and deriving mode #14002

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/libstd/enums.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Functions for enum types.

use vec;

/// Trait for enumerating all possible values in an enum
pub trait Enumerable {
/// Function to get all possible values of an enum
fn values() -> vec::Vec<Self>;
}
1 change: 1 addition & 0 deletions src/libstd/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ pub mod unit;
pub mod bool;
pub mod char;
pub mod tuple;
pub mod enums;

pub mod slice;
pub mod vec;
Expand Down
99 changes: 99 additions & 0 deletions src/libsyntax/ext/deriving/enumerable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use ast::{MetaItem, Item, Expr};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use parse::token::InternedString;

pub fn expand_deriving_enumerable(cx: &mut ExtCtxt,
span: Span,
mitem: @MetaItem,
item: @Item,
push: |@Item|) {
let self_vec_path = Path::new_(vec!("std", "vec", "Vec"), None, vec!(~Self), true);
let inline = cx.meta_word(span, InternedString::new("inline"));
let attrs = vec!(cx.attribute(span, inline));
let trait_def = TraitDef {
span: span,
attributes: Vec::new(),
path: Path::new(vec!("std", "enums", "Enumerable")),
additional_bounds: Vec::new(),
generics: LifetimeBounds::empty(),
methods: vec!(
MethodDef {
name: "values",
generics: LifetimeBounds::empty(),
explicit_self: None,
args: Vec::new(),
ret_ty: Literal(self_vec_path),
attributes: attrs,
const_nonmatching: false,
combine_substructure: combine_substructure(|a, b, c| {
values_substructure(a, b, c)
})
})
};
trait_def.expand(cx, mitem, item, push)
}

fn values_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
let vec_new_ident = vec!(
cx.ident_of("std"),
cx.ident_of("vec"),
cx.ident_of("Vec"),
cx.ident_of("new")
);

let mk_vec_new_expr = |span| cx.expr_call_global(span, vec_new_ident.clone(), vec!());
let mk_vec_push_expr = |span, id, e| cx.expr_method_call(span, cx.expr_ident(span, id), cx.ident_of("push"), vec!(e));

return match *substr.fields {
StaticEnum(_, ref variants) => {
let ret_ident = cx.ident_of("ret");
let mut stmts = vec!(cx.stmt_let(trait_span, true, ret_ident, mk_vec_new_expr(trait_span)));
let mut pushes = vec!();
let mut clike = true;

for &(ref ident, ref span, ref flds) in variants.iter() {
match *flds {
Unnamed(ref flds) => {
if flds.len() > 0 {
clike = false;
} else {
pushes.push(cx.stmt_expr(mk_vec_push_expr(*span, ret_ident, cx.expr_ident(*span, *ident))));
}
}
Named(_) => {
clike = false;
}
}
}

if !clike {
cx.span_err(trait_span, "`Enumerable` can only be derived for C-like enums");
} else {
stmts.extend(pushes.move_iter());
}

let block = cx.block(trait_span, stmts, Some(cx.expr_ident(trait_span, ret_ident)));

cx.expr_block(block)
}
StaticStruct(..) => {
cx.span_err(trait_span, "`Enumerable` can only be derived for enums, not structs");
// let compilation continue
cx.expr_uint(trait_span, 0)
}
_ => cx.span_bug(trait_span, "Non-static method in `deriving(Enumerable)`")
};
}
3 changes: 3 additions & 0 deletions src/libsyntax/ext/deriving/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub mod show;
pub mod zero;
pub mod default;
pub mod primitive;
pub mod enumerable;

#[path="cmp/eq.rs"]
pub mod eq;
Expand Down Expand Up @@ -88,6 +89,8 @@ pub fn expand_meta_deriving(cx: &mut ExtCtxt,
"Zero" => expand!(zero::expand_deriving_zero),
"Default" => expand!(default::expand_deriving_default),

"Enumerable" => expand!(enumerable::expand_deriving_enumerable),

"FromPrimitive" => expand!(primitive::expand_deriving_from_primitive),

ref tname => {
Expand Down