Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upAdd {To,From}Primitive conversion trait, add #[deriving(FromPrimitive)] for enums #9250
Conversation
huonw
reviewed
Sep 17, 2013
View changes
| #[inline] | ||
| fn to_i64(&self) -> Option<i64> { | ||
| // XXX: Check for range. | ||
| self.to_int().and_then(|x| Some(x as i64)) |
This comment has been minimized.
This comment has been minimized.
huonw
Sep 17, 2013
Member
Is this correct on 32-bit platforms? (I guess it's not, and so, should this truncation be the default behaviour?)
This comment has been minimized.
This comment has been minimized.
erickt
Sep 17, 2013
Author
Contributor
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.
huonw
reviewed
Sep 17, 2013
View changes
| #[inline] | ||
| fn to_u64(&self) -> Option<u64> { | ||
| // XXX: Check for range. | ||
| self.to_uint().and_then(|x| Some(x as u64)) |
This comment has been minimized.
This comment has been minimized.
huonw
reviewed
Sep 17, 2013
View changes
| arms.push(arm); | ||
| } | ||
| ast::struct_variant_kind(_) => { | ||
| cx.span_fatal(span, "`FromPrimitive` cannot be derived for enums \ |
This comment has been minimized.
This comment has been minimized.
huonw
Sep 17, 2013
Member
Could this be span_err rather than span_fatal? (We can continue from here to possibly pick up more errors later in expansion, so no particular need to stop the entire build.)
huonw
reviewed
Sep 17, 2013
|
|
||
| cx.expr_match(span, n, arms) | ||
| } | ||
| _ => cx.bug("expected StaticEnum in deriving(FromPrimitive)") |
This comment has been minimized.
This comment has been minimized.
huonw
Sep 17, 2013
Member
I think this will ICE on #[deriving(FromPrimitive)] struct Foo { .. }? Could there be an arm with a span_err for the StaticStruct case? (You can use the expr_unreachable to make a "dummy" expression to satisfy the return value.)
This comment has been minimized.
This comment has been minimized.
|
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. |
huonw
reviewed
Sep 17, 2013
View changes
| 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"); |
This comment has been minimized.
This comment has been minimized.
huonw
Sep 17, 2013
Member
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.
alexcrichton
reviewed
Sep 17, 2013
View changes
| impl IntConvertible for BigInt { | ||
| impl ToPrimitive for BigInt { | ||
| #[inline] | ||
| fn to_int(&self) -> Option<int> { |
This comment has been minimized.
This comment has been minimized.
alexcrichton
Sep 17, 2013
Member
It seems that the behavior of this is that to_int would return None if the value is out of bounds of an int's range. However when calling to_i8, silent truncation happens when something is between the ranges of i8 and int.
I'm ok with this behavior, but I think that it should be well documented. I'm also more ok with this when the methods to implement are for i64 and u64 because that's just saying that you need to be within the threshold of machine integers to return Some, which isn't so bad.
This comment has been minimized.
This comment has been minimized.
|
I'd be happy to r+ this, but it seems like a large enough change to be worth getting input from someone else. |
tikue
reviewed
Sep 19, 2013
View changes
| impl_to_primitive!(f64) | ||
| impl_to_primitive!(float) | ||
|
|
||
| /// A generic trait for converting an number to a value. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
This has been rebased to HEAD and is ready for review again. |
alexcrichton
reviewed
Sep 23, 2013
| #[deriving(FromPrimitive)] | ||
| struct A { x: int } | ||
| //~^^ ERROR `FromPrimitive` cannot be derived for structs | ||
| //~^^^ ERROR `FromPrimitive` cannot be derived for structs |
This comment has been minimized.
This comment has been minimized.
alexcrichton
Sep 23, 2013
Member
Why are each of the error messages doubled in this test? I would imagine that only one should be printed each time.
This comment has been minimized.
This comment has been minimized.
erickt
Sep 24, 2013
Author
Contributor
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.
This comment has been minimized.
This comment has been minimized.
|
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 |
This comment has been minimized.
This comment has been minimized.
|
@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 |
This comment has been minimized.
This comment has been minimized.
|
@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 comment has been minimized.
This comment has been minimized.
|
This needs a rebase. |
This comment has been minimized.
This comment has been minimized.
|
r=me if this gets consensus. |
This comment has been minimized.
This comment has been minimized.
|
This latest version adds:
|
This comment has been minimized.
This comment has been minimized.
|
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. |
This comment has been minimized.
This comment has been minimized.
|
The run-pass tests need |
bors
added a commit
that referenced
this pull request
Sep 29, 2013
erickt
added some commits
Sep 15, 2013
erickt
added some commits
Sep 26, 2013
This comment has been minimized.
This comment has been minimized.
|
r+ |
This comment has been minimized.
This comment has been minimized.
|
saw approval from erickt |
This comment has been minimized.
This comment has been minimized.
|
merging erickt/rust/num = 0e8ad4d into auto |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
fast-forwarding master to auto = 2733b18 |
bors
added a commit
that referenced
this pull request
Oct 5, 2013
bors
closed this
Oct 5, 2013
bors
merged commit 0e8ad4d
into
rust-lang:master
Oct 5, 2013
1 check passed
chris-morgan
reviewed
Oct 7, 2013
| /// Converts the value of `self` to an `u64`. | ||
| #[inline] | ||
| fn to_u64(&self) -> Option<u64> { | ||
| self.to_u64().and_then(|x| x.to_u64()) |
This comment has been minimized.
This comment has been minimized.
chris-morgan
Oct 7, 2013
Member
I venture to suggest this is not what was intended. self.to_i64(), perhaps? (Either that or omit the default implementation.)
erickt commentedSep 17, 2013
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/FromPrimitivehas 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()returnedNoneif the value was too large, but I'll save this for a future PR.Closes #3868.