-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Add {To,From}Primitive conversion trait, add #[deriving(FromPrimitive)] for enums #9250
Conversation
#[inline] | ||
fn to_i64(&self) -> Option<i64> { | ||
// XXX: Check for range. | ||
self.to_int().and_then(|x| Some(x as i64)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this correct on 32-bit platforms? (I guess it's not, and so, should this truncation be the default behaviour?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll change the unimplemented version to be .to_i64()
. I was guessing the people would reach first towards implementing .to_int()
and .to_uint()
, but you're right, it'd be better to avoid truncation by default.
Looks pretty nifty, will certainly reduce the number of #[deriving(FromPrimitive)]
struct Foo { x: int }
#[deriving(FromPrimitive)]
enum Bar { A(int), B(uint) }
#[deriving(FromPrimitive)]
enum Baz { S { x: int } } so we should test to stop them regressing accidentally. |
return match *substr.fields { | ||
StaticEnum(enum_def, _) => { | ||
if enum_def.variants.is_empty() { | ||
cx.span_fatal(span, "`FromPrimitive` cannot be derived for enums with no variants"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this still makes sense, and probably doesn't need special treatment at all, since the loop below will just not run?
It just returns None
on every possible conversion: i.e. having 0 variants mean the numbers in the (empty) set [0, 0)
are valid to convert from, and anything else (i.e. everything) gives None
.
I'd be happy to r+ this, but it seems like a large enough change to be worth getting input from someone else. |
impl_to_primitive!(f64) | ||
impl_to_primitive!(float) | ||
|
||
/// A generic trait for converting an number to a value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: s/an/a
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks! I've got it fixed in my upcoming rebase of this PR.
This has been rebased to HEAD and is ready for review again. |
#[deriving(FromPrimitive)] | ||
struct A { x: int } | ||
//~^^ ERROR `FromPrimitive` cannot be derived for structs | ||
//~^^^ ERROR `FromPrimitive` cannot be derived for structs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are each of the error messages doubled in this test? I would imagine that only one should be printed each time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Downside to the #[deriving(FromPrimitive)]
implementation. syntax::ext::deriving::generic::*
works a method at a time. Because FromPrimitive
requires at least two methods to be implemented, both generating both methods ends up reporting an error. This wouldn't be that difficult to change. We would just have to modify TraitDef.expand_struct_def
and TraitDef.expand_enum_def
to return either an Option<@ast::item>
or Result<@ast::item,~str>
and use that to signal that it's not worth implementing the rest of the methods.
I'm a little uneasy with this change in general. I think that the That being said, this seems like it might be a brainchild of discussion in #4819, which I haven't been following that closely. Is there an intent on using |
@alexcrichton I'd say that if we're going to be avoid static methods in traits because they're hard to use, we need to fix that, rather than just avoiding them entirely even when they are the appropriate thing to use. (Also, I think that |
@alexcrichton: This PR only partially implements my plans, I wanted to submit it early before I invested too much into this work in case the community decided I was going in a wrong direction. There's a couple things left to do:
Finally, I agree it is a pain to write |
This needs a rebase. |
r=me if this gets consensus. |
This latest version adds:
|
I r+'ed this. It's pretty big and I haven't followed it closely, but the response appears to be mostly favorable. Like all things it can be tweaked later. |
The run-pass tests need |
Right now this only works for c-style enums.
…rsion One downside with this current implementation is that since BigInt's default is now 64 bit, we can convert larger BigInt's to a primitive, however the current implementation on 32 bit architectures does not take advantage of this fact.
This allows the default methods to be properly range checked.
This PR solves one of the pain points with c-style enums. Simplifies writing a fn to convert from an int/uint to an enum. It does this through a `#[deriving(FromPrimitive)]` syntax extension. Before this is committed though, we need to discuss if `ToPrimitive`/`FromPrimitive` has the right design (cc #4819). I've changed all the `.to_int()` and `from_int()` style functions to return `Option<int>` so we can handle partial functions. For this PR though only enums and `extra::num::bigint::*` take advantage of returning None for unrepresentable values. In the long run it'd be better if `i64.to_i8()` returned `None` if the value was too large, but I'll save this for a future PR. Closes #3868.
/// Converts the value of `self` to an `u64`. | ||
#[inline] | ||
fn to_u64(&self) -> Option<u64> { | ||
self.to_u64().and_then(|x| x.to_u64()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I venture to suggest this is not what was intended. self.to_i64()
, perhaps? (Either that or omit the default implementation.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! I'll fix it.
This PR solves one of the pain points with c-style enums. Simplifies writing a fn to convert from an int/uint to an enum. It does this through a
#[deriving(FromPrimitive)]
syntax extension.Before this is committed though, we need to discuss if
ToPrimitive
/FromPrimitive
has the right design (cc #4819). I've changed all the.to_int()
andfrom_int()
style functions to returnOption<int>
so we can handle partial functions. For this PR though only enums andextra::num::bigint::*
take advantage of returning None for unrepresentable values. In the long run it'd be better ifi64.to_i8()
returnedNone
if the value was too large, but I'll save this for a future PR.Closes #3868.