Skip to content
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

#[derive(FromPrimitive)] panics on pub(crate) #2

Closed
cuviper opened this issue Dec 19, 2017 · 5 comments
Closed

#[derive(FromPrimitive)] panics on pub(crate) #2

cuviper opened this issue Dec 19, 2017 · 5 comments

Comments

@cuviper
Copy link
Member

cuviper commented Dec 19, 2017

From @hmvp on December 14, 2017 15:6

This does not compile:

#[derive(Debug, FromPrimitive)]
pub(crate) enum Foo {
    A = 1,
    B = 2,
}

removing (crate) makes it work

Copied from original issue: rust-num/num#352

@cuviper
Copy link
Member Author

cuviper commented Dec 19, 2017

From @hcpl on December 14, 2017 16:3

Applying this patch to num will make the OP's code compilable:

diff --git a/derive/Cargo.toml b/derive/Cargo.toml
index 2a17ce0..94cf68a 100644
--- a/derive/Cargo.toml
+++ b/derive/Cargo.toml
@@ -11,8 +11,8 @@ repository = "https://github.com/rust-num/num"
 version = "0.1.41"
 
 [dependencies]
-quote = "0.1.3"
-syn = "0.7.0"
+quote = "0.3.15"
+syn = "0.11.11"
 
 [dev-dependencies]
 compiletest_rs = "0.2.5"
diff --git a/derive/src/lib.rs b/derive/src/lib.rs
index e75fa06..8c0f420 100644
--- a/derive/src/lib.rs
+++ b/derive/src/lib.rs
@@ -42,8 +42,10 @@ pub fn from_primitive(input: TokenStream) -> TokenStream {
                     panic!("`FromPrimitive` can be applied only to unitary enums, {}::{} is either struct or tuple", name, ident)
                 },
             }
-            if let Some(val) = variant.discriminant {
-                idx = val.value;
+            if let Some(ref val) = variant.discriminant {
+                if let syn::ConstExpr::Lit(syn::Lit::Int(value, _)) = *val {
+                    idx = value;
+                }
             }
             let tt = quote!(#idx => Some(#name::#ident));
             idx += 1;
@@ -91,8 +93,10 @@ pub fn to_primitive(input: TokenStream) -> TokenStream {
                     panic!("`ToPrimitive` can be applied only to unitary enums, {}::{} is either struct or tuple", name, ident)
                 },
             }
-            if let Some(val) = variant.discriminant {
-                idx = val.value;
+            if let Some(ref val) = variant.discriminant {
+                if let syn::ConstExpr::Lit(syn::Lit::Int(value, _)) = *val {
+                    idx = value;
+                }
             }
             let tt = quote!(#name::#ident => #idx);
             idx += 1;

@cuviper, what do you think about this code and related compatibility issues? If everything is ok, I'll send a PR containing this patch.

@cuviper
Copy link
Member Author

cuviper commented Dec 19, 2017

From @hcpl on December 14, 2017 16:50

And I'd like to mention that

#[macro_use]
extern crate num_derive;

#[derive(Debug, FromPrimitive)]
pub(crate) enum Foo {
    A = 1,
    B = 2,
}

doesn't work because num-derive doesn't re-export traits from num-traits -- you also need extern crate num; (not even extern crate num-traits; can fix this because the derived code depends directly on num). This is something I'd also like to rectify when I get some time.

@cuviper
Copy link
Member Author

cuviper commented Dec 19, 2017

what do you think about this code and related compatibility issues?

The code is fine with me if it works. What exactly are the compatibility issues?

I think bumping semver on num-derive wouldn't be a problem, if needed. It's not the sort of crate that shows up as public dependencies -- only the traits it implements.

num-derive doesn't re-export traits from num-traits

I don't think proc-macro crates are even allowed to export anything but their #[proc_macro_derive] functions.

But I think it would be OK to make this depend on num-traits instead of num (as a breaking change).

@cuviper
Copy link
Member Author

cuviper commented Dec 19, 2017

From @hcpl on December 14, 2017 17:28

What exactly are the compatibility issues?

Well, my question was more like "is there any possibility for breaking changes to happen" if this patch gets accepted. Though you already said this is a non-issue, so we're good.

I don't think proc-macro crates are even allowed to export anything but their #[proc_macro_derive] functions.

Yeah, that was my mistake (funny thing, I crossed my part out right after you posted the comment 😄).

The thing is, we could make num-derive to (ab)use such a Rust construct:

const _IMPL_NUM_FROM_PRIMITIVE_FOR_Foo: () = {
    extern crate num_traits as _num_traits;
    /* ... */
};

like serde_derive does so that we would only need a num-traits = "0.1" entry in Cargo.toml but not extern crate num_traits; to make this work.

Replacing num with num-traits is another matter which is not that important compared to the above one, but is a nice thing for builds that don't need all num features.

@cuviper
Copy link
Member Author

cuviper commented Dec 19, 2017

Well, my question was more like "is there any possibility for breaking changes to happen" if this patch gets accepted. Though you already said this is a non-issue, so we're good.

It probably just depends on what the rustc minimum is for the newer syn/quote, but it looks like they both have CI for 1.15.1, so that should be fine. We could still bump for num-traits though.

(ab)use such a Rust construct: [...] like serde_derive does

I'm happy to follow serde's lead on this.

bors bot added a commit that referenced this issue Jan 22, 2018
3: Update deps and derivation algorithm r=cuviper a=hcpl

Fixes #2.

An updated version of rust-num/num#353 which includes suggestions outlined [here](rust-num/num#353 (review)) and [here](https://github.com/rust-num/num/pull/353/files/76b5b2189f2b45e864e14c38c7856be578125931#r157100221):

- Update `quote` and `syn` to parse new Rust syntax;
- Update `compiletest_rs` to solve Manishearth/compiletest-rs#86;
- Add support for arbitrary constant expressions as enum discriminants;
- Remove the need to `extern crate num` just for deriving.

Some notes:
- `#[derive(FromPrimitive)]` now uses if-else to do its job because non-literal expressions are not allowed for pattern matching.
- I added tests for self-containment of `#[derive]` alongside the code testing derivation functionality to keep the tests small. Would it be better to separate concerns?
- `with_custom_value` should have all three tests like `trivial`.
@bors bors bot closed this as completed in #3 Jan 22, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant