Import num-derive 0.3.3 upstream upstream/0.3.3
authorWoohyun Jung <wh0705.jung@samsung.com>
Tue, 21 Mar 2023 05:28:27 +0000 (14:28 +0900)
committerWoohyun Jung <wh0705.jung@samsung.com>
Tue, 21 Mar 2023 05:28:27 +0000 (14:28 +0900)
19 files changed:
.cargo_vcs_info.json [new file with mode: 0644]
.gitignore [new file with mode: 0644]
Cargo.toml [new file with mode: 0644]
Cargo.toml.orig [new file with mode: 0644]
LICENSE-APACHE [new file with mode: 0644]
LICENSE-MIT [new file with mode: 0644]
README.md [new file with mode: 0644]
RELEASES.md [new file with mode: 0644]
src/lib.rs [new file with mode: 0644]
src/test.rs [new file with mode: 0644]
tests/empty_enum.rs [new file with mode: 0644]
tests/issue-6.rs [new file with mode: 0644]
tests/issue-9.rs [new file with mode: 0644]
tests/newtype-2015.rs [new file with mode: 0644]
tests/newtype.rs [new file with mode: 0644]
tests/num_derive_without_num.rs [new file with mode: 0644]
tests/trivial-2015.rs [new file with mode: 0644]
tests/trivial.rs [new file with mode: 0644]
tests/with_custom_values.rs [new file with mode: 0644]

diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644 (file)
index 0000000..ccd68a1
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "git": {
+    "sha1": "61a6e5294ec133448b1fb8da35e152a0cedbf870"
+  }
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..fa8d85a
--- /dev/null
@@ -0,0 +1,2 @@
+Cargo.lock
+target
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644 (file)
index 0000000..90c5d27
--- /dev/null
@@ -0,0 +1,55 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+edition = "2018"
+name = "num-derive"
+version = "0.3.3"
+authors = ["The Rust Project Developers"]
+exclude = ["/bors.toml", "/ci/*", "/.github/*"]
+description = "Numeric syntax extensions"
+homepage = "https://github.com/rust-num/num-derive"
+documentation = "https://docs.rs/num-derive"
+readme = "README.md"
+keywords = ["mathematics", "numerics"]
+categories = ["science"]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/rust-num/num-derive"
+
+[lib]
+name = "num_derive"
+test = false
+proc-macro = true
+
+[[test]]
+name = "newtype-2015"
+edition = "2015"
+
+[[test]]
+name = "trivial-2015"
+edition = "2015"
+[dependencies.proc-macro2]
+version = "1"
+
+[dependencies.quote]
+version = "1"
+
+[dependencies.syn]
+version = "1"
+[dev-dependencies.num]
+version = "0.3"
+
+[dev-dependencies.num-traits]
+version = "0.2"
+
+[features]
+full-syntax = ["syn/full"]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644 (file)
index 0000000..5addf90
--- /dev/null
@@ -0,0 +1,42 @@
+[package]
+authors = ["The Rust Project Developers"]
+description = "Numeric syntax extensions"
+documentation = "https://docs.rs/num-derive"
+homepage = "https://github.com/rust-num/num-derive"
+keywords = ["mathematics", "numerics"]
+categories = [ "science" ]
+license = "MIT OR Apache-2.0"
+name = "num-derive"
+repository = "https://github.com/rust-num/num-derive"
+version = "0.3.3"
+readme = "README.md"
+exclude = ["/bors.toml", "/ci/*", "/.github/*"]
+edition = "2018"
+
+[dependencies]
+proc-macro2 = "1"
+quote = "1"
+syn = "1"
+
+[dev-dependencies]
+num = "0.3"
+num-traits = "0.2"
+
+[features]
+full-syntax = ["syn/full"]
+
+[lib]
+name = "num_derive"
+proc-macro = true
+test = false
+
+# Most of the tests are left implicily detected, compiled for Rust 2018,
+# but let's try a few of them with the old 2015 edition too.
+
+[[test]]
+name = "newtype-2015"
+edition = "2015"
+
+[[test]]
+name = "trivial-2015"
+edition = "2015"
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
new file mode 100644 (file)
index 0000000..16fe87b
--- /dev/null
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644 (file)
index 0000000..39d4bdb
--- /dev/null
@@ -0,0 +1,25 @@
+Copyright (c) 2014 The Rust Project Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..9826cdf
--- /dev/null
+++ b/README.md
@@ -0,0 +1,69 @@
+# num-derive
+
+[![crate](https://img.shields.io/crates/v/num-derive.svg)](https://crates.io/crates/num-derive)
+[![documentation](https://docs.rs/num-derive/badge.svg)](https://docs.rs/num-derive)
+[![minimum rustc 1.31](https://img.shields.io/badge/rustc-1.31+-red.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
+[![build status](https://github.com/rust-num/num-derive/workflows/master/badge.svg)](https://github.com/rust-num/num-derive/actions)
+
+Procedural macros to derive numeric traits in Rust.
+
+## Usage
+
+Add this to your `Cargo.toml`:
+
+```toml
+[dependencies]
+num-traits = "0.2"
+num-derive = "0.3"
+```
+
+and this to your crate root:
+
+```rust
+#[macro_use]
+extern crate num_derive;
+```
+
+Then you can derive traits on your own types:
+
+```rust
+#[derive(FromPrimitive, ToPrimitive)]
+enum Color {
+    Red,
+    Blue,
+    Green,
+}
+```
+
+## Optional features
+
+- **`full-syntax`** — Enables `num-derive` to handle enum discriminants
+  represented by complex expressions. Usually can be avoided by
+  [utilizing constants], so only use this feature if namespace pollution is
+  undesired and [compile time doubling] is acceptable.
+
+[utilizing constants]: https://github.com/rust-num/num-derive/pull/3#issuecomment-359044704
+[compile time doubling]: https://github.com/rust-num/num-derive/pull/3#issuecomment-359172588
+
+## Releases
+
+Release notes are available in [RELEASES.md](RELEASES.md).
+
+## Compatibility
+
+The `num-derive` crate is tested for rustc 1.31 and greater.
+
+## License
+
+Licensed under either of
+
+ * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
+ * [MIT license](http://opensource.org/licenses/MIT)
+
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
+dual licensed as above, without any additional terms or conditions.
diff --git a/RELEASES.md b/RELEASES.md
new file mode 100644 (file)
index 0000000..c3e18cc
--- /dev/null
@@ -0,0 +1,105 @@
+# Release 0.3.3 (2020-10-29)
+
+- [Make `NumOps` work with `no_std`][41] -- thanks @jedrzejboczar!
+
+[41]: https://github.com/rust-num/num-derive/pull/41
+
+# Release 0.3.2 (2020-08-24)
+
+- [Add `#[inline]` to all derived functions][40] -- thanks @Amanieu!
+
+[40]: https://github.com/rust-num/num-derive/pull/40
+
+# Release 0.3.1 (2020-07-28)
+
+- [Add `num_traits` proc_macro helper for explicit import][35] - thanks @jean-airoldie!
+- [Provide nicer parse errors and suggest "full-syntax"][39]
+
+[35]: https://github.com/rust-num/num-derive/pull/35
+[39]: https://github.com/rust-num/num-derive/pull/39
+
+# Release 0.3.0 (2019-09-27)
+
+- [Updated the `proc-macro2`, `quote`, and `syn` dependencies to 1.0][28],
+  which raises the minimum supported rustc to 1.31.
+
+[28]: https://github.com/rust-num/num-derive/pull/28
+
+# Release 0.2.5 (2019-04-23)
+
+- [Improved the masking of lints in derived code][23].
+
+[23]: https://github.com/rust-num/num-derive/pull/23
+
+# Release 0.2.4 (2019-01-25)
+
+- [Adjusted dependencies to allow no-std targets][22].
+
+[22]: https://github.com/rust-num/num-derive/pull/22
+
+# Release 0.2.3 (2018-10-03)
+
+- [Added newtype deriving][17] for `FromPrimitive`, `ToPrimitive`,
+  `NumOps<Self, Self>`, `NumCast`, `Zero`, `One`, `Num`, and `Float`.
+  Thanks @asayers!
+
+[17]: https://github.com/rust-num/num-derive/pull/17
+
+# Release 0.2.2 (2018-05-22)
+
+- [Updated dependencies][14].
+
+[14]: https://github.com/rust-num/num-derive/pull/14
+
+# Release 0.2.1 (2018-05-09)
+
+- [Updated dependencies][12] -- thanks @spearman!
+
+[12]: https://github.com/rust-num/num-derive/pull/12
+
+# Release 0.2.0 (2018-02-21)
+
+- [Discriminant matching is now simplified][10], casting values directly by
+  name, rather than trying to compute offsets from known values manually.
+- **breaking change**: [Derivations now import the traits from `num-traits`][11]
+  instead of the full `num` crate.  These are still compatible, but users need
+  to have an explicit `num-traits = "0.2"` dependency in their `Cargo.toml`.
+
+[10]: https://github.com/rust-num/num-derive/pull/10
+[11]: https://github.com/rust-num/num-derive/pull/11
+
+
+# Release 0.1.44 (2018-01-26)
+
+- [The derived code now explicitly allows `unused_qualifications`][9], so users
+  that globally deny that lint don't encounter an error.
+
+[9]: https://github.com/rust-num/num-derive/pull/9
+
+
+# Release 0.1.43 (2018-01-23)
+
+- [The derived code now explicitly allows `trivial_numeric_casts`][7], so users
+  that globally deny that lint don't encounter an error.
+
+[7]: https://github.com/rust-num/num-derive/pull/7
+
+
+# Release 0.1.42 (2018-01-22)
+
+- [num-derive now has its own source repository][num-356] at [rust-num/num-derive][home].
+- [The derivation macros have been updated][3] to using `syn` 0.12.  Support for complex
+  expressions in enum values can be enabled with the `full-syntax` feature.
+
+Thanks to @cuviper and @hcpl for their contributions!
+
+[home]: https://github.com/rust-num/num-derive
+[num-356]: https://github.com/rust-num/num/pull/356
+[3]: https://github.com/rust-num/num-derive/pull/3
+
+
+# Prior releases
+
+No prior release notes were kept.  Thanks all the same to the many
+contributors that have made this crate what it is!
+
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644 (file)
index 0000000..ef55e4b
--- /dev/null
@@ -0,0 +1,958 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "proc-macro"]
+#![doc(html_root_url = "https://docs.rs/num-derive/0.3")]
+#![recursion_limit = "512"]
+
+//! Procedural macros to derive numeric traits in Rust.
+//!
+//! ## Usage
+//!
+//! Add this to your `Cargo.toml`:
+//!
+//! ```toml
+//! [dependencies]
+//! num-traits = "0.2"
+//! num-derive = "0.3"
+//! ```
+//!
+//! Then you can derive traits on your own types:
+//!
+//! ```rust
+//! #[macro_use]
+//! extern crate num_derive;
+//!
+//! #[derive(FromPrimitive, ToPrimitive)]
+//! enum Color {
+//!     Red,
+//!     Blue,
+//!     Green,
+//! }
+//! # fn main() {}
+//! ```
+//!
+//! ## Explicit import
+//!
+//! By default the `num_derive` procedural macros assume that the
+//! `num_traits` crate is a direct dependency. If `num_traits` is instead
+//! a transitive dependency, the `num_traits` helper attribute can be
+//! used to tell `num_derive` to use a specific identifier for its imports.
+//!
+//! ```rust
+//! #[macro_use]
+//! extern crate num_derive;
+//! // Lets pretend this is a transitive dependency from another crate
+//! // reexported as `some_other_ident`.
+//! extern crate num_traits as some_other_ident;
+//!
+//! #[derive(FromPrimitive, ToPrimitive)]
+//! #[num_traits = "some_other_ident"]
+//! enum Color {
+//!     Red,
+//!     Blue,
+//!     Green,
+//! }
+//! # fn main() {}
+//! ```
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+use proc_macro2::{Span, TokenStream as TokenStream2};
+use quote::quote;
+use syn::{Data, Fields, Ident};
+
+/// Try to parse the tokens, or else return a compilation error
+/// suggesting "full-syntax" if that's not already enabled.
+macro_rules! parse {
+    ($tokens:ident as $type:ty) => {
+        match syn::parse::<$type>($tokens) {
+            Ok(parsed) => parsed,
+            Err(mut error) => {
+                if cfg!(not(feature = "full-syntax")) {
+                    let hint = syn::Error::new(
+                        Span::call_site(),
+                        r#"this might need the "full-syntax" feature of `num-derive`"#,
+                    );
+                    error.combine(hint);
+                }
+                return TokenStream::from(error.to_compile_error());
+            }
+        }
+    };
+}
+
+// Within `exp`, you can bring things into scope with `extern crate`.
+//
+// We don't want to assume that `num_traits::` is in scope - the user may have imported it under a
+// different name, or may have imported it in a non-toplevel module (common when putting impls
+// behind a feature gate).
+//
+// Solution: let's just generate `extern crate num_traits as _num_traits` and then refer to
+// `_num_traits` in the derived code.  However, macros are not allowed to produce `extern crate`
+// statements at the toplevel.
+//
+// Solution: let's generate `mod _impl_foo` and import num_traits within that.  However, now we
+// lose access to private members of the surrounding module.  This is a problem if, for example,
+// we're deriving for a newtype, where the inner type is defined in the same module, but not
+// exported.
+//
+// Solution: use the dummy const trick.  For some reason, `extern crate` statements are allowed
+// here, but everything from the surrounding module is in scope.  This trick is taken from serde.
+fn dummy_const_trick(trait_: &str, name: &Ident, exp: TokenStream2) -> TokenStream2 {
+    let dummy_const = Ident::new(
+        &format!("_IMPL_NUM_{}_FOR_{}", trait_, unraw(name)),
+        Span::call_site(),
+    );
+    quote! {
+        #[allow(non_upper_case_globals, unused_qualifications)]
+        const #dummy_const: () = {
+            #[allow(clippy::useless_attribute)]
+            #[allow(rust_2018_idioms)]
+            extern crate num_traits as _num_traits;
+            #exp
+        };
+    }
+}
+
+fn unraw(ident: &Ident) -> String {
+    ident.to_string().trim_start_matches("r#").to_owned()
+}
+
+// If `data` is a newtype, return the type it's wrapping.
+fn newtype_inner(data: &syn::Data) -> Option<syn::Type> {
+    match *data {
+        Data::Struct(ref s) => {
+            match s.fields {
+                Fields::Unnamed(ref fs) => {
+                    if fs.unnamed.len() == 1 {
+                        Some(fs.unnamed[0].ty.clone())
+                    } else {
+                        None
+                    }
+                }
+                Fields::Named(ref fs) => {
+                    if fs.named.len() == 1 {
+                        panic!("num-derive doesn't know how to handle newtypes with named fields yet. \
+                           Please use a tuple-style newtype, or submit a PR!");
+                    }
+                    None
+                }
+                _ => None,
+            }
+        }
+        _ => None,
+    }
+}
+
+struct NumTraits {
+    import: Ident,
+    explicit: bool,
+}
+
+impl quote::ToTokens for NumTraits {
+    fn to_tokens(&self, tokens: &mut TokenStream2) {
+        self.import.to_tokens(tokens);
+    }
+}
+
+impl NumTraits {
+    fn new(ast: &syn::DeriveInput) -> Self {
+        // If there is a `num_traits` MetaNameValue attribute on the input,
+        // retrieve its value, and use it to create an `Ident` to be used
+        // to import the `num_traits` crate.
+        for attr in &ast.attrs {
+            if let Ok(syn::Meta::NameValue(mnv)) = attr.parse_meta() {
+                if mnv.path.is_ident("num_traits") {
+                    if let syn::Lit::Str(lit_str) = mnv.lit {
+                        return NumTraits {
+                            import: syn::Ident::new(&lit_str.value(), lit_str.span()),
+                            explicit: true,
+                        };
+                    } else {
+                        panic!("#[num_traits] attribute value must be a str");
+                    }
+                }
+            }
+        }
+
+        // Otherwise, we'll implicitly import our own.
+        NumTraits {
+            import: Ident::new("_num_traits", Span::call_site()),
+            explicit: false,
+        }
+    }
+
+    fn wrap(&self, trait_: &str, name: &Ident, output: TokenStream2) -> TokenStream2 {
+        if self.explicit {
+            output
+        } else {
+            dummy_const_trick(trait_, &name, output)
+        }
+    }
+}
+
+/// Derives [`num_traits::FromPrimitive`][from] for simple enums and newtypes.
+///
+/// [from]: https://docs.rs/num-traits/0.2/num_traits/cast/trait.FromPrimitive.html
+///
+/// # Examples
+///
+/// Simple enums can be derived:
+///
+/// ```rust
+/// # #[macro_use]
+/// # extern crate num_derive;
+///
+/// #[derive(FromPrimitive)]
+/// enum Color {
+///     Red,
+///     Blue,
+///     Green = 42,
+/// }
+/// # fn main() {}
+/// ```
+///
+/// Enums that contain data are not allowed:
+///
+/// ```compile_fail
+/// # #[macro_use]
+/// # extern crate num_derive;
+///
+/// #[derive(FromPrimitive)]
+/// enum Color {
+///     Rgb(u8, u8, u8),
+///     Hsv(u8, u8, u8),
+/// }
+/// # fn main() {}
+/// ```
+///
+/// Structs are not allowed:
+///
+/// ```compile_fail
+/// # #[macro_use]
+/// # extern crate num_derive;
+/// #[derive(FromPrimitive)]
+/// struct Color {
+///     r: u8,
+///     g: u8,
+///     b: u8,
+/// }
+/// # fn main() {}
+/// ```
+#[proc_macro_derive(FromPrimitive, attributes(num_traits))]
+pub fn from_primitive(input: TokenStream) -> TokenStream {
+    let ast = parse!(input as syn::DeriveInput);
+    let name = &ast.ident;
+
+    let import = NumTraits::new(&ast);
+
+    let impl_ = if let Some(inner_ty) = newtype_inner(&ast.data) {
+        quote! {
+            impl #import::FromPrimitive for #name {
+                #[inline]
+                fn from_i64(n: i64) -> Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_i64(n).map(#name)
+                }
+                #[inline]
+                fn from_u64(n: u64) -> Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_u64(n).map(#name)
+                }
+                #[inline]
+                fn from_isize(n: isize) -> Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_isize(n).map(#name)
+                }
+                #[inline]
+                fn from_i8(n: i8) -> Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_i8(n).map(#name)
+                }
+                #[inline]
+                fn from_i16(n: i16) -> Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_i16(n).map(#name)
+                }
+                #[inline]
+                fn from_i32(n: i32) -> Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_i32(n).map(#name)
+                }
+                #[inline]
+                fn from_i128(n: i128) -> Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_i128(n).map(#name)
+                }
+                #[inline]
+                fn from_usize(n: usize) -> Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_usize(n).map(#name)
+                }
+                #[inline]
+                fn from_u8(n: u8) -> Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_u8(n).map(#name)
+                }
+                #[inline]
+                fn from_u16(n: u16) -> Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_u16(n).map(#name)
+                }
+                #[inline]
+                fn from_u32(n: u32) -> Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_u32(n).map(#name)
+                }
+                #[inline]
+                fn from_u128(n: u128) -> Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_u128(n).map(#name)
+                }
+                #[inline]
+                fn from_f32(n: f32) -> Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_f32(n).map(#name)
+                }
+                #[inline]
+                fn from_f64(n: f64) -> Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_f64(n).map(#name)
+                }
+            }
+        }
+    } else {
+        let variants = match ast.data {
+            Data::Enum(ref data_enum) => &data_enum.variants,
+            _ => panic!(
+                "`FromPrimitive` can be applied only to enums and newtypes, {} is neither",
+                name
+            ),
+        };
+
+        let from_i64_var = quote! { n };
+        let clauses: Vec<_> = variants
+            .iter()
+            .map(|variant| {
+                let ident = &variant.ident;
+                match variant.fields {
+                    Fields::Unit => (),
+                    _ => panic!(
+                        "`FromPrimitive` can be applied only to unitary enums and newtypes, \
+                         {}::{} is either struct or tuple",
+                        name, ident
+                    ),
+                }
+
+                quote! {
+                    if #from_i64_var == #name::#ident as i64 {
+                        Some(#name::#ident)
+                    }
+                }
+            })
+            .collect();
+
+        let from_i64_var = if clauses.is_empty() {
+            quote!(_)
+        } else {
+            from_i64_var
+        };
+
+        quote! {
+            impl #import::FromPrimitive for #name {
+                #[allow(trivial_numeric_casts)]
+                #[inline]
+                fn from_i64(#from_i64_var: i64) -> Option<Self> {
+                    #(#clauses else)* {
+                        None
+                    }
+                }
+
+                #[inline]
+                fn from_u64(n: u64) -> Option<Self> {
+                    Self::from_i64(n as i64)
+                }
+            }
+        }
+    };
+
+    import.wrap("FromPrimitive", &name, impl_).into()
+}
+
+/// Derives [`num_traits::ToPrimitive`][to] for simple enums and newtypes.
+///
+/// [to]: https://docs.rs/num-traits/0.2/num_traits/cast/trait.ToPrimitive.html
+///
+/// # Examples
+///
+/// Simple enums can be derived:
+///
+/// ```rust
+/// # #[macro_use]
+/// # extern crate num_derive;
+///
+/// #[derive(ToPrimitive)]
+/// enum Color {
+///     Red,
+///     Blue,
+///     Green = 42,
+/// }
+/// # fn main() {}
+/// ```
+///
+/// Enums that contain data are not allowed:
+///
+/// ```compile_fail
+/// # #[macro_use]
+/// # extern crate num_derive;
+///
+/// #[derive(ToPrimitive)]
+/// enum Color {
+///     Rgb(u8, u8, u8),
+///     Hsv(u8, u8, u8),
+/// }
+/// # fn main() {}
+/// ```
+///
+/// Structs are not allowed:
+///
+/// ```compile_fail
+/// # #[macro_use]
+/// # extern crate num_derive;
+/// #[derive(ToPrimitive)]
+/// struct Color {
+///     r: u8,
+///     g: u8,
+///     b: u8,
+/// }
+/// # fn main() {}
+/// ```
+#[proc_macro_derive(ToPrimitive, attributes(num_traits))]
+pub fn to_primitive(input: TokenStream) -> TokenStream {
+    let ast = parse!(input as syn::DeriveInput);
+    let name = &ast.ident;
+
+    let import = NumTraits::new(&ast);
+
+    let impl_ = if let Some(inner_ty) = newtype_inner(&ast.data) {
+        quote! {
+            impl #import::ToPrimitive for #name {
+                #[inline]
+                fn to_i64(&self) -> Option<i64> {
+                    <#inner_ty as #import::ToPrimitive>::to_i64(&self.0)
+                }
+                #[inline]
+                fn to_u64(&self) -> Option<u64> {
+                    <#inner_ty as #import::ToPrimitive>::to_u64(&self.0)
+                }
+                #[inline]
+                fn to_isize(&self) -> Option<isize> {
+                    <#inner_ty as #import::ToPrimitive>::to_isize(&self.0)
+                }
+                #[inline]
+                fn to_i8(&self) -> Option<i8> {
+                    <#inner_ty as #import::ToPrimitive>::to_i8(&self.0)
+                }
+                #[inline]
+                fn to_i16(&self) -> Option<i16> {
+                    <#inner_ty as #import::ToPrimitive>::to_i16(&self.0)
+                }
+                #[inline]
+                fn to_i32(&self) -> Option<i32> {
+                    <#inner_ty as #import::ToPrimitive>::to_i32(&self.0)
+                }
+                #[inline]
+                fn to_i128(&self) -> Option<i128> {
+                    <#inner_ty as #import::ToPrimitive>::to_i128(&self.0)
+                }
+                #[inline]
+                fn to_usize(&self) -> Option<usize> {
+                    <#inner_ty as #import::ToPrimitive>::to_usize(&self.0)
+                }
+                #[inline]
+                fn to_u8(&self) -> Option<u8> {
+                    <#inner_ty as #import::ToPrimitive>::to_u8(&self.0)
+                }
+                #[inline]
+                fn to_u16(&self) -> Option<u16> {
+                    <#inner_ty as #import::ToPrimitive>::to_u16(&self.0)
+                }
+                #[inline]
+                fn to_u32(&self) -> Option<u32> {
+                    <#inner_ty as #import::ToPrimitive>::to_u32(&self.0)
+                }
+                #[inline]
+                fn to_u128(&self) -> Option<u128> {
+                    <#inner_ty as #import::ToPrimitive>::to_u128(&self.0)
+                }
+                #[inline]
+                fn to_f32(&self) -> Option<f32> {
+                    <#inner_ty as #import::ToPrimitive>::to_f32(&self.0)
+                }
+                #[inline]
+                fn to_f64(&self) -> Option<f64> {
+                    <#inner_ty as #import::ToPrimitive>::to_f64(&self.0)
+                }
+            }
+        }
+    } else {
+        let variants = match ast.data {
+            Data::Enum(ref data_enum) => &data_enum.variants,
+            _ => panic!(
+                "`ToPrimitive` can be applied only to enums and newtypes, {} is neither",
+                name
+            ),
+        };
+
+        let variants: Vec<_> = variants
+            .iter()
+            .map(|variant| {
+                let ident = &variant.ident;
+                match variant.fields {
+                    Fields::Unit => (),
+                    _ => {
+                        panic!("`ToPrimitive` can be applied only to unitary enums and newtypes, {}::{} is either struct or tuple", name, ident)
+                    },
+                }
+
+                // NB: We have to check each variant individually, because we'll only have `&self`
+                // for the input.  We can't move from that, and it might not be `Clone` or `Copy`.
+                // (Otherwise we could just do `*self as i64` without a `match` at all.)
+                quote!(#name::#ident => #name::#ident as i64)
+            })
+            .collect();
+
+        let match_expr = if variants.is_empty() {
+            // No variants found, so do not use Some to not to trigger `unreachable_code` lint
+            quote! {
+                match *self {}
+            }
+        } else {
+            quote! {
+                Some(match *self {
+                    #(#variants,)*
+                })
+            }
+        };
+
+        quote! {
+            impl #import::ToPrimitive for #name {
+                #[inline]
+                #[allow(trivial_numeric_casts)]
+                fn to_i64(&self) -> Option<i64> {
+                    #match_expr
+                }
+
+                #[inline]
+                fn to_u64(&self) -> Option<u64> {
+                    self.to_i64().map(|x| x as u64)
+                }
+            }
+        }
+    };
+
+    import.wrap("ToPrimitive", &name, impl_).into()
+}
+
+const NEWTYPE_ONLY: &str = "This trait can only be derived for newtypes";
+
+/// Derives [`num_traits::NumOps`][num_ops] for newtypes.  The inner type must already implement
+/// `NumOps`.
+///
+/// [num_ops]: https://docs.rs/num-traits/0.2/num_traits/trait.NumOps.html
+///
+/// Note that, since `NumOps` is really a trait alias for `Add + Sub + Mul + Div + Rem`, this macro
+/// generates impls for _those_ traits.  Furthermore, in all generated impls, `RHS=Self` and
+/// `Output=Self`.
+#[proc_macro_derive(NumOps)]
+pub fn num_ops(input: TokenStream) -> TokenStream {
+    let ast = parse!(input as syn::DeriveInput);
+    let name = &ast.ident;
+    let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+    let impl_ = quote! {
+        impl ::core::ops::Add for #name {
+            type Output = Self;
+            #[inline]
+            fn add(self, other: Self) -> Self {
+                #name(<#inner_ty as ::core::ops::Add>::add(self.0, other.0))
+            }
+        }
+        impl ::core::ops::Sub for #name {
+            type Output = Self;
+            #[inline]
+            fn sub(self, other: Self) -> Self {
+                #name(<#inner_ty as ::core::ops::Sub>::sub(self.0, other.0))
+            }
+        }
+        impl ::core::ops::Mul for #name {
+            type Output = Self;
+            #[inline]
+            fn mul(self, other: Self) -> Self {
+                #name(<#inner_ty as ::core::ops::Mul>::mul(self.0, other.0))
+            }
+        }
+        impl ::core::ops::Div for #name {
+            type Output = Self;
+            #[inline]
+            fn div(self, other: Self) -> Self {
+                #name(<#inner_ty as ::core::ops::Div>::div(self.0, other.0))
+            }
+        }
+        impl ::core::ops::Rem for #name {
+            type Output = Self;
+            #[inline]
+            fn rem(self, other: Self) -> Self {
+                #name(<#inner_ty as ::core::ops::Rem>::rem(self.0, other.0))
+            }
+        }
+    };
+    impl_.into()
+}
+
+/// Derives [`num_traits::NumCast`][num_cast] for newtypes.  The inner type must already implement
+/// `NumCast`.
+///
+/// [num_cast]: https://docs.rs/num-traits/0.2/num_traits/cast/trait.NumCast.html
+#[proc_macro_derive(NumCast, attributes(num_traits))]
+pub fn num_cast(input: TokenStream) -> TokenStream {
+    let ast = parse!(input as syn::DeriveInput);
+    let name = &ast.ident;
+    let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+
+    let import = NumTraits::new(&ast);
+
+    let impl_ = quote! {
+        impl #import::NumCast for #name {
+            #[inline]
+            fn from<T: #import::ToPrimitive>(n: T) -> Option<Self> {
+                <#inner_ty as #import::NumCast>::from(n).map(#name)
+            }
+        }
+    };
+
+    import.wrap("NumCast", &name, impl_).into()
+}
+
+/// Derives [`num_traits::Zero`][zero] for newtypes.  The inner type must already implement `Zero`.
+///
+/// [zero]: https://docs.rs/num-traits/0.2/num_traits/identities/trait.Zero.html
+#[proc_macro_derive(Zero, attributes(num_traits))]
+pub fn zero(input: TokenStream) -> TokenStream {
+    let ast = parse!(input as syn::DeriveInput);
+    let name = &ast.ident;
+    let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+
+    let import = NumTraits::new(&ast);
+
+    let impl_ = quote! {
+        impl #import::Zero for #name {
+            #[inline]
+            fn zero() -> Self {
+                #name(<#inner_ty as #import::Zero>::zero())
+            }
+            #[inline]
+            fn is_zero(&self) -> bool {
+                <#inner_ty as #import::Zero>::is_zero(&self.0)
+            }
+        }
+    };
+
+    import.wrap("Zero", &name, impl_).into()
+}
+
+/// Derives [`num_traits::One`][one] for newtypes.  The inner type must already implement `One`.
+///
+/// [one]: https://docs.rs/num-traits/0.2/num_traits/identities/trait.One.html
+#[proc_macro_derive(One, attributes(num_traits))]
+pub fn one(input: TokenStream) -> TokenStream {
+    let ast = parse!(input as syn::DeriveInput);
+    let name = &ast.ident;
+    let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+
+    let import = NumTraits::new(&ast);
+
+    let impl_ = quote! {
+        impl #import::One for #name {
+            #[inline]
+            fn one() -> Self {
+                #name(<#inner_ty as #import::One>::one())
+            }
+            #[inline]
+            fn is_one(&self) -> bool {
+                <#inner_ty as #import::One>::is_one(&self.0)
+            }
+        }
+    };
+
+    import.wrap("One", &name, impl_).into()
+}
+
+/// Derives [`num_traits::Num`][num] for newtypes.  The inner type must already implement `Num`.
+///
+/// [num]: https://docs.rs/num-traits/0.2/num_traits/trait.Num.html
+#[proc_macro_derive(Num, attributes(num_traits))]
+pub fn num(input: TokenStream) -> TokenStream {
+    let ast = parse!(input as syn::DeriveInput);
+    let name = &ast.ident;
+    let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+
+    let import = NumTraits::new(&ast);
+
+    let impl_ = quote! {
+        impl #import::Num for #name {
+            type FromStrRadixErr = <#inner_ty as #import::Num>::FromStrRadixErr;
+            #[inline]
+            fn from_str_radix(s: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
+                <#inner_ty as #import::Num>::from_str_radix(s, radix).map(#name)
+            }
+        }
+    };
+
+    import.wrap("Num", &name, impl_).into()
+}
+
+/// Derives [`num_traits::Float`][float] for newtypes.  The inner type must already implement
+/// `Float`.
+///
+/// [float]: https://docs.rs/num-traits/0.2/num_traits/float/trait.Float.html
+#[proc_macro_derive(Float, attributes(num_traits))]
+pub fn float(input: TokenStream) -> TokenStream {
+    let ast = parse!(input as syn::DeriveInput);
+    let name = &ast.ident;
+    let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+
+    let import = NumTraits::new(&ast);
+
+    let impl_ = quote! {
+        impl #import::Float for #name {
+            #[inline]
+            fn nan() -> Self {
+                #name(<#inner_ty as #import::Float>::nan())
+            }
+            #[inline]
+            fn infinity() -> Self {
+                #name(<#inner_ty as #import::Float>::infinity())
+            }
+            #[inline]
+            fn neg_infinity() -> Self {
+                #name(<#inner_ty as #import::Float>::neg_infinity())
+            }
+            #[inline]
+            fn neg_zero() -> Self {
+                #name(<#inner_ty as #import::Float>::neg_zero())
+            }
+            #[inline]
+            fn min_value() -> Self {
+                #name(<#inner_ty as #import::Float>::min_value())
+            }
+            #[inline]
+            fn min_positive_value() -> Self {
+                #name(<#inner_ty as #import::Float>::min_positive_value())
+            }
+            #[inline]
+            fn max_value() -> Self {
+                #name(<#inner_ty as #import::Float>::max_value())
+            }
+            #[inline]
+            fn is_nan(self) -> bool {
+                <#inner_ty as #import::Float>::is_nan(self.0)
+            }
+            #[inline]
+            fn is_infinite(self) -> bool {
+                <#inner_ty as #import::Float>::is_infinite(self.0)
+            }
+            #[inline]
+            fn is_finite(self) -> bool {
+                <#inner_ty as #import::Float>::is_finite(self.0)
+            }
+            #[inline]
+            fn is_normal(self) -> bool {
+                <#inner_ty as #import::Float>::is_normal(self.0)
+            }
+            #[inline]
+            fn classify(self) -> ::std::num::FpCategory {
+                <#inner_ty as #import::Float>::classify(self.0)
+            }
+            #[inline]
+            fn floor(self) -> Self {
+                #name(<#inner_ty as #import::Float>::floor(self.0))
+            }
+            #[inline]
+            fn ceil(self) -> Self {
+                #name(<#inner_ty as #import::Float>::ceil(self.0))
+            }
+            #[inline]
+            fn round(self) -> Self {
+                #name(<#inner_ty as #import::Float>::round(self.0))
+            }
+            #[inline]
+            fn trunc(self) -> Self {
+                #name(<#inner_ty as #import::Float>::trunc(self.0))
+            }
+            #[inline]
+            fn fract(self) -> Self {
+                #name(<#inner_ty as #import::Float>::fract(self.0))
+            }
+            #[inline]
+            fn abs(self) -> Self {
+                #name(<#inner_ty as #import::Float>::abs(self.0))
+            }
+            #[inline]
+            fn signum(self) -> Self {
+                #name(<#inner_ty as #import::Float>::signum(self.0))
+            }
+            #[inline]
+            fn is_sign_positive(self) -> bool {
+                <#inner_ty as #import::Float>::is_sign_positive(self.0)
+            }
+            #[inline]
+            fn is_sign_negative(self) -> bool {
+                <#inner_ty as #import::Float>::is_sign_negative(self.0)
+            }
+            #[inline]
+            fn mul_add(self, a: Self, b: Self) -> Self {
+                #name(<#inner_ty as #import::Float>::mul_add(self.0, a.0, b.0))
+            }
+            #[inline]
+            fn recip(self) -> Self {
+                #name(<#inner_ty as #import::Float>::recip(self.0))
+            }
+            #[inline]
+            fn powi(self, n: i32) -> Self {
+                #name(<#inner_ty as #import::Float>::powi(self.0, n))
+            }
+            #[inline]
+            fn powf(self, n: Self) -> Self {
+                #name(<#inner_ty as #import::Float>::powf(self.0, n.0))
+            }
+            #[inline]
+            fn sqrt(self) -> Self {
+                #name(<#inner_ty as #import::Float>::sqrt(self.0))
+            }
+            #[inline]
+            fn exp(self) -> Self {
+                #name(<#inner_ty as #import::Float>::exp(self.0))
+            }
+            #[inline]
+            fn exp2(self) -> Self {
+                #name(<#inner_ty as #import::Float>::exp2(self.0))
+            }
+            #[inline]
+            fn ln(self) -> Self {
+                #name(<#inner_ty as #import::Float>::ln(self.0))
+            }
+            #[inline]
+            fn log(self, base: Self) -> Self {
+                #name(<#inner_ty as #import::Float>::log(self.0, base.0))
+            }
+            #[inline]
+            fn log2(self) -> Self {
+                #name(<#inner_ty as #import::Float>::log2(self.0))
+            }
+            #[inline]
+            fn log10(self) -> Self {
+                #name(<#inner_ty as #import::Float>::log10(self.0))
+            }
+            #[inline]
+            fn max(self, other: Self) -> Self {
+                #name(<#inner_ty as #import::Float>::max(self.0, other.0))
+            }
+            #[inline]
+            fn min(self, other: Self) -> Self {
+                #name(<#inner_ty as #import::Float>::min(self.0, other.0))
+            }
+            #[inline]
+            fn abs_sub(self, other: Self) -> Self {
+                #name(<#inner_ty as #import::Float>::abs_sub(self.0, other.0))
+            }
+            #[inline]
+            fn cbrt(self) -> Self {
+                #name(<#inner_ty as #import::Float>::cbrt(self.0))
+            }
+            #[inline]
+            fn hypot(self, other: Self) -> Self {
+                #name(<#inner_ty as #import::Float>::hypot(self.0, other.0))
+            }
+            #[inline]
+            fn sin(self) -> Self {
+                #name(<#inner_ty as #import::Float>::sin(self.0))
+            }
+            #[inline]
+            fn cos(self) -> Self {
+                #name(<#inner_ty as #import::Float>::cos(self.0))
+            }
+            #[inline]
+            fn tan(self) -> Self {
+                #name(<#inner_ty as #import::Float>::tan(self.0))
+            }
+            #[inline]
+            fn asin(self) -> Self {
+                #name(<#inner_ty as #import::Float>::asin(self.0))
+            }
+            #[inline]
+            fn acos(self) -> Self {
+                #name(<#inner_ty as #import::Float>::acos(self.0))
+            }
+            #[inline]
+            fn atan(self) -> Self {
+                #name(<#inner_ty as #import::Float>::atan(self.0))
+            }
+            #[inline]
+            fn atan2(self, other: Self) -> Self {
+                #name(<#inner_ty as #import::Float>::atan2(self.0, other.0))
+            }
+            #[inline]
+            fn sin_cos(self) -> (Self, Self) {
+                let (x, y) = <#inner_ty as #import::Float>::sin_cos(self.0);
+                (#name(x), #name(y))
+            }
+            #[inline]
+            fn exp_m1(self) -> Self {
+                #name(<#inner_ty as #import::Float>::exp_m1(self.0))
+            }
+            #[inline]
+            fn ln_1p(self) -> Self {
+                #name(<#inner_ty as #import::Float>::ln_1p(self.0))
+            }
+            #[inline]
+            fn sinh(self) -> Self {
+                #name(<#inner_ty as #import::Float>::sinh(self.0))
+            }
+            #[inline]
+            fn cosh(self) -> Self {
+                #name(<#inner_ty as #import::Float>::cosh(self.0))
+            }
+            #[inline]
+            fn tanh(self) -> Self {
+                #name(<#inner_ty as #import::Float>::tanh(self.0))
+            }
+            #[inline]
+            fn asinh(self) -> Self {
+                #name(<#inner_ty as #import::Float>::asinh(self.0))
+            }
+            #[inline]
+            fn acosh(self) -> Self {
+                #name(<#inner_ty as #import::Float>::acosh(self.0))
+            }
+            #[inline]
+            fn atanh(self) -> Self {
+                #name(<#inner_ty as #import::Float>::atanh(self.0))
+            }
+            #[inline]
+            fn integer_decode(self) -> (u64, i16, i8) {
+                <#inner_ty as #import::Float>::integer_decode(self.0)
+            }
+            #[inline]
+            fn epsilon() -> Self {
+                #name(<#inner_ty as #import::Float>::epsilon())
+            }
+            #[inline]
+            fn to_degrees(self) -> Self {
+                #name(<#inner_ty as #import::Float>::to_degrees(self.0))
+            }
+            #[inline]
+            fn to_radians(self) -> Self {
+                #name(<#inner_ty as #import::Float>::to_radians(self.0))
+            }
+        }
+    };
+
+    import.wrap("Float", &name, impl_).into()
+}
+
+mod test;
diff --git a/src/test.rs b/src/test.rs
new file mode 100644 (file)
index 0000000..c4cd7fe
--- /dev/null
@@ -0,0 +1,31 @@
+//! This module uses doc-tests on modules for `compile_fail`
+
+// We need "syn/full" to parse macros.
+// Use `--nocapture` to check the quality of the error message.
+#[cfg(not(feature = "full-syntax"))]
+/// ```compile_fail
+/// macro_rules! get_an_isize {
+///     () => (0_isize)
+/// }
+///
+/// #[derive(num_derive::FromPrimitive)]
+/// pub enum CLikeEnum {
+///     VarA = get_an_isize!(), // error without "syn/full"
+///     VarB = 2,
+/// }
+/// ```
+mod issue16 {}
+
+#[cfg(feature = "full-syntax")]
+/// ```
+/// macro_rules! get_an_isize {
+///     () => (0_isize)
+/// }
+///
+/// #[derive(num_derive::FromPrimitive)]
+/// pub enum CLikeEnum {
+///     VarA = get_an_isize!(), // ok with "syn/full"
+///     VarB = 2,
+/// }
+/// ```
+mod issue16 {}
diff --git a/tests/empty_enum.rs b/tests/empty_enum.rs
new file mode 100644 (file)
index 0000000..173996c
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate num as num_renamed;
+#[macro_use]
+extern crate num_derive;
+
+#[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)]
+enum Color {}
+
+#[test]
+fn test_empty_enum() {
+    let v: [Option<Color>; 1] = [num_renamed::FromPrimitive::from_u64(0)];
+
+    assert_eq!(v, [None]);
+}
diff --git a/tests/issue-6.rs b/tests/issue-6.rs
new file mode 100644 (file)
index 0000000..9eae7fb
--- /dev/null
@@ -0,0 +1,17 @@
+#![deny(trivial_numeric_casts)]
+
+#[macro_use]
+extern crate num_derive;
+
+#[derive(FromPrimitive, ToPrimitive)]
+pub enum SomeEnum {
+    A = 1,
+}
+
+#[test]
+fn test_trivial_numeric_casts() {
+    use num::{FromPrimitive, ToPrimitive};
+    assert!(SomeEnum::from_u64(1).is_some());
+    assert!(SomeEnum::from_i64(-1).is_none());
+    assert_eq!(SomeEnum::A.to_u64(), Some(1));
+}
diff --git a/tests/issue-9.rs b/tests/issue-9.rs
new file mode 100644 (file)
index 0000000..30c04d2
--- /dev/null
@@ -0,0 +1,18 @@
+#![deny(unused_qualifications)]
+
+#[macro_use]
+extern crate num_derive;
+use num::FromPrimitive;
+use num::ToPrimitive;
+
+#[derive(FromPrimitive, ToPrimitive)]
+pub enum SomeEnum {
+    A = 1,
+}
+
+#[test]
+fn test_unused_qualifications() {
+    assert!(SomeEnum::from_u64(1).is_some());
+    assert!(SomeEnum::from_i64(-1).is_none());
+    assert!(SomeEnum::A.to_i64().is_some());
+}
diff --git a/tests/newtype-2015.rs b/tests/newtype-2015.rs
new file mode 100644 (file)
index 0000000..2b58190
--- /dev/null
@@ -0,0 +1,2 @@
+// Same source, just compiled for 2015 edition
+include!("newtype.rs");
diff --git a/tests/newtype.rs b/tests/newtype.rs
new file mode 100644 (file)
index 0000000..6eafd09
--- /dev/null
@@ -0,0 +1,89 @@
+extern crate num as num_renamed;
+#[macro_use]
+extern crate num_derive;
+
+use crate::num_renamed::{Float, FromPrimitive, Num, NumCast, One, ToPrimitive, Zero};
+use std::ops::Neg;
+
+#[derive(
+    Debug,
+    Clone,
+    Copy,
+    PartialEq,
+    PartialOrd,
+    ToPrimitive,
+    FromPrimitive,
+    NumOps,
+    NumCast,
+    One,
+    Zero,
+    Num,
+    Float,
+)]
+struct MyFloat(f64);
+
+impl Neg for MyFloat {
+    type Output = MyFloat;
+    fn neg(self) -> Self {
+        MyFloat(self.0.neg())
+    }
+}
+
+#[test]
+fn test_from_primitive() {
+    assert_eq!(MyFloat::from_u32(25), Some(MyFloat(25.0)));
+}
+
+#[test]
+fn test_from_primitive_128() {
+    assert_eq!(
+        MyFloat::from_i128(std::i128::MIN),
+        Some(MyFloat((-2.0).powi(127)))
+    );
+}
+
+#[test]
+fn test_to_primitive() {
+    assert_eq!(MyFloat(25.0).to_u32(), Some(25));
+}
+
+#[test]
+fn test_to_primitive_128() {
+    let f = MyFloat::from_f32(std::f32::MAX).unwrap();
+    assert_eq!(f.to_i128(), None);
+    assert_eq!(f.to_u128(), Some(0xffff_ff00_0000_0000_0000_0000_0000_0000));
+}
+
+#[test]
+fn test_num_ops() {
+    assert_eq!(MyFloat(25.0) + MyFloat(10.0), MyFloat(35.0));
+    assert_eq!(MyFloat(25.0) - MyFloat(10.0), MyFloat(15.0));
+    assert_eq!(MyFloat(25.0) * MyFloat(2.0), MyFloat(50.0));
+    assert_eq!(MyFloat(25.0) / MyFloat(10.0), MyFloat(2.5));
+    assert_eq!(MyFloat(25.0) % MyFloat(10.0), MyFloat(5.0));
+}
+
+#[test]
+fn test_num_cast() {
+    assert_eq!(<MyFloat as NumCast>::from(25u8), Some(MyFloat(25.0)));
+}
+
+#[test]
+fn test_zero() {
+    assert_eq!(MyFloat::zero(), MyFloat(0.0));
+}
+
+#[test]
+fn test_one() {
+    assert_eq!(MyFloat::one(), MyFloat(1.0));
+}
+
+#[test]
+fn test_num() {
+    assert_eq!(MyFloat::from_str_radix("25", 10).ok(), Some(MyFloat(25.0)));
+}
+
+#[test]
+fn test_float() {
+    assert_eq!(MyFloat(4.0).log(MyFloat(2.0)), MyFloat(2.0));
+}
diff --git a/tests/num_derive_without_num.rs b/tests/num_derive_without_num.rs
new file mode 100644 (file)
index 0000000..edebbec
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[macro_use]
+extern crate num_derive;
+
+#[derive(Debug, FromPrimitive, ToPrimitive)]
+enum Direction {
+    Up,
+    Down,
+    Left,
+    Right,
+}
diff --git a/tests/trivial-2015.rs b/tests/trivial-2015.rs
new file mode 100644 (file)
index 0000000..8309f0e
--- /dev/null
@@ -0,0 +1,2 @@
+// Same source, just compiled for 2015 edition
+include!("trivial.rs");
diff --git a/tests/trivial.rs b/tests/trivial.rs
new file mode 100644 (file)
index 0000000..d3b56b6
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate num as num_renamed;
+#[macro_use]
+extern crate num_derive;
+
+#[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)]
+enum Color {
+    Red,
+    Blue,
+    Green,
+}
+
+#[test]
+fn test_from_primitive_for_trivial_case() {
+    let v: [Option<Color>; 4] = [
+        num_renamed::FromPrimitive::from_u64(0),
+        num_renamed::FromPrimitive::from_u64(1),
+        num_renamed::FromPrimitive::from_u64(2),
+        num_renamed::FromPrimitive::from_u64(3),
+    ];
+
+    assert_eq!(
+        v,
+        [
+            Some(Color::Red),
+            Some(Color::Blue),
+            Some(Color::Green),
+            None
+        ]
+    );
+}
+
+#[test]
+fn test_to_primitive_for_trivial_case() {
+    let v: [Option<u64>; 3] = [
+        num_renamed::ToPrimitive::to_u64(&Color::Red),
+        num_renamed::ToPrimitive::to_u64(&Color::Blue),
+        num_renamed::ToPrimitive::to_u64(&Color::Green),
+    ];
+
+    assert_eq!(v, [Some(0), Some(1), Some(2)]);
+}
+
+#[test]
+fn test_reflexive_for_trivial_case() {
+    let before: [u64; 3] = [0, 1, 2];
+    let after: Vec<Option<u64>> = before
+        .iter()
+        .map(|&x| -> Option<Color> { num_renamed::FromPrimitive::from_u64(x) })
+        .map(|x| x.and_then(|x| num_renamed::ToPrimitive::to_u64(&x)))
+        .collect();
+    let before = before.iter().cloned().map(Some).collect::<Vec<_>>();
+
+    assert_eq!(before, after);
+}
diff --git a/tests/with_custom_values.rs b/tests/with_custom_values.rs
new file mode 100644 (file)
index 0000000..94c8445
--- /dev/null
@@ -0,0 +1,70 @@
+// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![cfg(feature = "full-syntax")]
+
+extern crate num as num_renamed;
+#[macro_use]
+extern crate num_derive;
+
+#[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)]
+enum Color {
+    Red,
+    Blue = 5,
+    Green,
+    Alpha = (-3 - (-5isize)) - 10,
+}
+
+#[test]
+fn test_from_primitive_for_enum_with_custom_value() {
+    let v: [Option<Color>; 5] = [
+        num_renamed::FromPrimitive::from_u64(0),
+        num_renamed::FromPrimitive::from_u64(5),
+        num_renamed::FromPrimitive::from_u64(6),
+        num_renamed::FromPrimitive::from_u64(-8isize as u64),
+        num_renamed::FromPrimitive::from_u64(3),
+    ];
+
+    assert_eq!(
+        v,
+        [
+            Some(Color::Red),
+            Some(Color::Blue),
+            Some(Color::Green),
+            Some(Color::Alpha),
+            None
+        ]
+    );
+}
+
+#[test]
+fn test_to_primitive_for_enum_with_custom_value() {
+    let v: [Option<u64>; 4] = [
+        num_renamed::ToPrimitive::to_u64(&Color::Red),
+        num_renamed::ToPrimitive::to_u64(&Color::Blue),
+        num_renamed::ToPrimitive::to_u64(&Color::Green),
+        num_renamed::ToPrimitive::to_u64(&Color::Alpha),
+    ];
+
+    assert_eq!(v, [Some(0), Some(5), Some(6), Some(-8isize as u64)]);
+}
+
+#[test]
+fn test_reflexive_for_enum_with_custom_value() {
+    let before: [u64; 3] = [0, 5, 6];
+    let after: Vec<Option<u64>> = before
+        .iter()
+        .map(|&x| -> Option<Color> { num_renamed::FromPrimitive::from_u64(x) })
+        .map(|x| x.and_then(|x| num_renamed::ToPrimitive::to_u64(&x)))
+        .collect();
+    let before = before.iter().cloned().map(Some).collect::<Vec<_>>();
+
+    assert_eq!(before, after);
+}