Derive various num traits for newtypes#17
Conversation
|
Pushed a fix for rust 1.15 compatibility. |
079f045 to
b64a25e
Compare
|
I just noticed #1. I'm not sure if anything came of the more general |
fd55292 to
a69f860
Compare
|
Added some docs. Build failure looks spurious. |
cuviper
left a comment
There was a problem hiding this comment.
I restarted that failed build -- ✔️
This looks really good! My only concern is how to get proper support for 128-bit integers.
|
|
||
| #![crate_type = "proc-macro"] | ||
| #![doc(html_root_url = "https://docs.rs/num-derive/0.2")] | ||
| #![recursion_limit="512"] |
There was a problem hiding this comment.
Yeah... It may not need to be this high - I only know that 256 is not enough.
| None | ||
| } | ||
| } | ||
| _ => None, |
There was a problem hiding this comment.
It would be nice if this could also work with a single Fields::Named, but we can leave that as a future extension. I guess we'd have to return an extra token to abstract how to access .0 vs. .inner, and find some way to abstract the newtype constructor too.
There was a problem hiding this comment.
I added a specialised error message if the user tries to derive for a named-field-newtype. This is a lazy cop-out on my part, but I think it's better than nothing.
--> tests/newtype.rs:89:5
|
89 | Float,
| ^^^^^
|
= help: message: num-derive doesn't know how to handle newtypes with named fields yet. Please use a tuple-style newtype, or submit a PR!
| fn from_i32(n: i32) -> Option<Self> { | ||
| <#inner_ty as _num_traits::FromPrimitive>::from_i32(n).map(#name) | ||
| } | ||
| #[cfg(has_i128)] |
There was a problem hiding this comment.
Does this cfg actually work? I'm assuming that this is not interpreted locally, just quoted and emitted as-is to the derived code.
This is how the methods are defined in num-traits, but that has a build script to set the cfg, which only applies within that crate. So I think this derive will be missing out, unless the target crate also happens to set has_i128.
I think what we could do is add a similar build script to num-derive, and check #[cfg(has_i128)] locally (outside of quote!) to determine whether we should emit those methods in the derived output.
(The enum derivation doesn't worry about this yet, since repr128 is still unstable.)
There was a problem hiding this comment.
I see; you're saying that, in the end, these functions are unconditionally ignored. I'll implement your suggestion.
There was a problem hiding this comment.
Done; I confirmed that the functions are present in the expansion under 1.29, and it still builds with 1.15.
| }; | ||
|
|
||
| res.into() | ||
| dummy_const_trick("FromPrimative", &name, impl_).into() |
There was a problem hiding this comment.
spelling: FromPrimitive
(though I know this is hidden anyway)
This equates to deriving Add, Sub, Mul, Div, and Rem, where RHS=Self and Output=Self.
This is needed for older compilers, even though we know they won't have i128 support anyway...
cuviper
left a comment
There was a problem hiding this comment.
Looks great! I just added explicit tests for the 128-bit methods.
|
bors r+ |
17: Derive various num traits for newtypes r=cuviper a=asayers This PR adds deriving macros for the following traits: * FromPrimitive * ToPrimitive * NumOps<Self, Self> * NumCast * Zero * One * Num * Float These macros only work when applied to a newtype where the inner type already implements the trait in question. They produce the obvious "unwrap-call-rewrap" implementation. The `FromPrimative` and `ToPrimative` macros now handle both newtypes and the enums that they used to handle. The odd one out is `NumOps`, for two reasons. First, `NumOps` is just a trait alias for `Add + Sub + Mul + Div + Rem`, so those are the traits which the macro generates impls for. I suppose it's not a great user experience to say `#[derive(Foo)]` and end up with `impl Bar`, but I think in this case it's just about OK. After all, the user needs only to look at the definition of `NumOps` to know that this is only possible behaviour - there's no other way to get an impl for `NumOps`. The other reason this one is strange is that when the user says `#[derive(NumOps)]`, the macro decides that what they want is an impl for `NumOps<Rhs=Self, Output=Self>`. I think this makes sense though; these are the default type parameters, so when you say `NumOps` unqualified this is what it means. As you can probably tell, my objective here was to get to `Float`. That's why this PR only provides macros for a subset of the traits in `num_traits`. Our codebase has a bunch of newtyped `f64`s, and I don't want people unwrapping them all the time to work with them. ### To-do - [x] docs - [x] tests - [x] RELEASES entry Co-authored-by: Alex Sayers <alex.sayers@gmail.com> Co-authored-by: Josh Stone <cuviper@gmail.com>
Build succeeded |
|
Thanks @cuviper! |
This PR adds deriving macros for the following traits:
These macros only work when applied to a newtype where the inner type already
implements the trait in question. They produce the obvious
"unwrap-call-rewrap" implementation.
The
FromPrimativeandToPrimativemacros now handle both newtypes and theenums that they used to handle.
The odd one out is
NumOps, for two reasons. First,NumOpsis just a traitalias for
Add + Sub + Mul + Div + Rem, so those are the traits which themacro generates impls for. I suppose it's not a great user experience to say
#[derive(Foo)]and end up withimpl Bar, but I think in this case it's justabout OK. After all, the user needs only to look at the definition of
NumOpsto know that this is only possible behaviour - there's no other way to get an
impl for
NumOps.The other reason this one is strange is that when the user says
#[derive(NumOps)], the macro decides that what they want is an impl forNumOps<Rhs=Self, Output=Self>. I think this makes sense though; these arethe default type parameters, so when you say
NumOpsunqualified this is whatit means.
As you can probably tell, my objective here was to get to
Float. That's whythis PR only provides macros for a subset of the traits in
num_traits. Ourcodebase has a bunch of newtyped
f64s, and I don't want people unwrappingthem all the time to work with them.
To-do