Skip to content

Commit

Permalink
derive: Emit only PartialOrd::partial_cmp for simple enums
Browse files Browse the repository at this point in the history
Using the same logic as for `PartialEq`, when possible define only
`partial_cmp` and leave `lt, le, gt, ge` to their default
implementations. This works well for c-like enums.
  • Loading branch information
bluss committed Mar 1, 2016
1 parent 57e0a7e commit edcc02b
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 24 deletions.
18 changes: 1 addition & 17 deletions src/libsyntax_ext/deriving/cmp/partial_eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,13 @@
use deriving::generic::*;
use deriving::generic::ty::*;

use syntax::ast::{MetaItem, Expr, BinOpKind, ItemKind};
use syntax::ast::{MetaItem, Expr, BinOpKind};
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::InternedString;
use syntax::ptr::P;

fn is_type_without_fields(item: &Annotatable) -> bool {
if let Annotatable::Item(ref item) = *item {
match item.node {
ItemKind::Enum(ref enum_def, _) => {
enum_def.variants.iter().all(|v| v.node.data.fields().is_empty())
}
ItemKind::Struct(ref variant_data, _) => {
variant_data.fields().is_empty()
}
_ => false
}
} else {
false
}
}

pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
Expand Down
23 changes: 16 additions & 7 deletions src/libsyntax_ext/deriving/cmp/partial_ord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,20 +67,29 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt,
}))
};

// avoid defining extra methods if we can
// c-like enums, enums without any fields and structs without fields
// can safely define only `partial_cmp`.
let methods = if is_type_without_fields(item) {
vec![partial_cmp_def]
} else {
vec![
partial_cmp_def,
md!("lt", true, false),
md!("le", true, true),
md!("gt", false, false),
md!("ge", false, true)
]
};

let trait_def = TraitDef {
span: span,
attributes: vec![],
path: path_std!(cx, core::cmp::PartialOrd),
additional_bounds: vec![],
generics: LifetimeBounds::empty(),
is_unsafe: false,
methods: vec![
partial_cmp_def,
md!("lt", true, false),
md!("le", true, true),
md!("gt", false, false),
md!("ge", false, true)
],
methods: methods,
associated_types: Vec::new(),
};
trait_def.expand(cx, mitem, item, push)
Expand Down
18 changes: 18 additions & 0 deletions src/libsyntax_ext/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1638,3 +1638,21 @@ pub fn cs_same_method<F>(f: F,
}
}
}

/// Return true if the type has no value fields
/// (for an enum, no variant has any fields)
pub fn is_type_without_fields(item: &Annotatable) -> bool {
if let Annotatable::Item(ref item) = *item {
match item.node {
ast::ItemKind::Enum(ref enum_def, _) => {
enum_def.variants.iter().all(|v| v.node.data.fields().is_empty())
}
ast::ItemKind::Struct(ref variant_data, _) => {
variant_data.fields().is_empty()
}
_ => false
}
} else {
false
}
}

0 comments on commit edcc02b

Please sign in to comment.