aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cargo_vcs_info.json5
-rw-r--r--.gitignore2
-rw-r--r--Cargo.toml55
-rw-r--r--Cargo.toml.orig42
-rw-r--r--LICENSE-APACHE201
-rw-r--r--LICENSE-MIT25
-rw-r--r--README.md54
-rw-r--r--RELEASES.md85
-rw-r--r--src/lib.rs769
-rw-r--r--tests/empty_enum.rs23
-rw-r--r--tests/issue-6.rs17
-rw-r--r--tests/issue-9.rs18
-rw-r--r--tests/newtype-2015.rs2
-rw-r--r--tests/newtype.rs89
-rw-r--r--tests/num_derive_without_num.rs20
-rw-r--r--tests/trivial-2015.rs2
-rw-r--r--tests/trivial.rs64
-rw-r--r--tests/with_custom_values.rs70
18 files changed, 1543 insertions, 0 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..87254ec
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,5 @@
+{
+ "git": {
+ "sha1": "1b361d7af828467aa9a1d80d609793f0a312aae5"
+ }
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..fa8d85a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+Cargo.lock
+target
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..33eb0b8
--- /dev/null
+++ b/Cargo.toml
@@ -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.0"
+authors = ["The Rust Project Developers"]
+exclude = ["/ci/*", "/.travis.yml", "/bors.toml"]
+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/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.2"
+
+[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
index 0000000..7d378a7
--- /dev/null
+++ b/Cargo.toml.orig
@@ -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/Apache-2.0"
+name = "num-derive"
+repository = "https://github.com/rust-num/num-derive"
+version = "0.3.0"
+readme = "README.md"
+exclude = ["/ci/*", "/.travis.yml", "/bors.toml"]
+edition = "2018"
+
+[dependencies]
+proc-macro2 = "1"
+quote = "1"
+syn = "1"
+
+[dev-dependencies]
+num = "0.2"
+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
index 0000000..16fe87b
--- /dev/null
+++ b/LICENSE-APACHE
@@ -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
index 0000000..39d4bdb
--- /dev/null
+++ b/LICENSE-MIT
@@ -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
index 0000000..0bb70d2
--- /dev/null
+++ b/README.md
@@ -0,0 +1,54 @@
+# 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)
+[![Travis status](https://travis-ci.org/rust-num/num-derive.svg?branch=master)](https://travis-ci.org/rust-num/num-derive)
+
+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.
diff --git a/RELEASES.md b/RELEASES.md
new file mode 100644
index 0000000..371f6fb
--- /dev/null
+++ b/RELEASES.md
@@ -0,0 +1,85 @@
+# 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
index 0000000..be77fb5
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,769 @@
+// 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() {}
+//! ```
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+use proc_macro2::Span;
+use quote::quote;
+use syn::{Data, Fields, Ident};
+
+// 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<T: quote::ToTokens>(
+ trait_: &str,
+ name: &proc_macro2::Ident,
+ exp: T,
+) -> proc_macro2::TokenStream {
+ 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: &proc_macro2::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,
+ }
+}
+
+/// 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)]
+pub fn from_primitive(input: TokenStream) -> TokenStream {
+ let ast: syn::DeriveInput = syn::parse(input).unwrap();
+ let name = &ast.ident;
+
+ let impl_ = if let Some(inner_ty) = newtype_inner(&ast.data) {
+ quote! {
+ impl _num_traits::FromPrimitive for #name {
+ fn from_i64(n: i64) -> Option<Self> {
+ <#inner_ty as _num_traits::FromPrimitive>::from_i64(n).map(#name)
+ }
+ fn from_u64(n: u64) -> Option<Self> {
+ <#inner_ty as _num_traits::FromPrimitive>::from_u64(n).map(#name)
+ }
+ fn from_isize(n: isize) -> Option<Self> {
+ <#inner_ty as _num_traits::FromPrimitive>::from_isize(n).map(#name)
+ }
+ fn from_i8(n: i8) -> Option<Self> {
+ <#inner_ty as _num_traits::FromPrimitive>::from_i8(n).map(#name)
+ }
+ fn from_i16(n: i16) -> Option<Self> {
+ <#inner_ty as _num_traits::FromPrimitive>::from_i16(n).map(#name)
+ }
+ fn from_i32(n: i32) -> Option<Self> {
+ <#inner_ty as _num_traits::FromPrimitive>::from_i32(n).map(#name)
+ }
+ fn from_i128(n: i128) -> Option<Self> {
+ <#inner_ty as _num_traits::FromPrimitive>::from_i128(n).map(#name)
+ }
+ fn from_usize(n: usize) -> Option<Self> {
+ <#inner_ty as _num_traits::FromPrimitive>::from_usize(n).map(#name)
+ }
+ fn from_u8(n: u8) -> Option<Self> {
+ <#inner_ty as _num_traits::FromPrimitive>::from_u8(n).map(#name)
+ }
+ fn from_u16(n: u16) -> Option<Self> {
+ <#inner_ty as _num_traits::FromPrimitive>::from_u16(n).map(#name)
+ }
+ fn from_u32(n: u32) -> Option<Self> {
+ <#inner_ty as _num_traits::FromPrimitive>::from_u32(n).map(#name)
+ }
+ fn from_u128(n: u128) -> Option<Self> {
+ <#inner_ty as _num_traits::FromPrimitive>::from_u128(n).map(#name)
+ }
+ fn from_f32(n: f32) -> Option<Self> {
+ <#inner_ty as _num_traits::FromPrimitive>::from_f32(n).map(#name)
+ }
+ fn from_f64(n: f64) -> Option<Self> {
+ <#inner_ty as _num_traits::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 _num_traits::FromPrimitive for #name {
+ #[allow(trivial_numeric_casts)]
+ fn from_i64(#from_i64_var: i64) -> Option<Self> {
+ #(#clauses else)* {
+ None
+ }
+ }
+
+ fn from_u64(n: u64) -> Option<Self> {
+ Self::from_i64(n as i64)
+ }
+ }
+ }
+ };
+
+ dummy_const_trick("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)]
+pub fn to_primitive(input: TokenStream) -> TokenStream {
+ let ast: syn::DeriveInput = syn::parse(input).unwrap();
+ let name = &ast.ident;
+
+ let impl_ = if let Some(inner_ty) = newtype_inner(&ast.data) {
+ quote! {
+ impl _num_traits::ToPrimitive for #name {
+ fn to_i64(&self) -> Option<i64> {
+ <#inner_ty as _num_traits::ToPrimitive>::to_i64(&self.0)
+ }
+ fn to_u64(&self) -> Option<u64> {
+ <#inner_ty as _num_traits::ToPrimitive>::to_u64(&self.0)
+ }
+ fn to_isize(&self) -> Option<isize> {
+ <#inner_ty as _num_traits::ToPrimitive>::to_isize(&self.0)
+ }
+ fn to_i8(&self) -> Option<i8> {
+ <#inner_ty as _num_traits::ToPrimitive>::to_i8(&self.0)
+ }
+ fn to_i16(&self) -> Option<i16> {
+ <#inner_ty as _num_traits::ToPrimitive>::to_i16(&self.0)
+ }
+ fn to_i32(&self) -> Option<i32> {
+ <#inner_ty as _num_traits::ToPrimitive>::to_i32(&self.0)
+ }
+ fn to_i128(&self) -> Option<i128> {
+ <#inner_ty as _num_traits::ToPrimitive>::to_i128(&self.0)
+ }
+ fn to_usize(&self) -> Option<usize> {
+ <#inner_ty as _num_traits::ToPrimitive>::to_usize(&self.0)
+ }
+ fn to_u8(&self) -> Option<u8> {
+ <#inner_ty as _num_traits::ToPrimitive>::to_u8(&self.0)
+ }
+ fn to_u16(&self) -> Option<u16> {
+ <#inner_ty as _num_traits::ToPrimitive>::to_u16(&self.0)
+ }
+ fn to_u32(&self) -> Option<u32> {
+ <#inner_ty as _num_traits::ToPrimitive>::to_u32(&self.0)
+ }
+ fn to_u128(&self) -> Option<u128> {
+ <#inner_ty as _num_traits::ToPrimitive>::to_u128(&self.0)
+ }
+ fn to_f32(&self) -> Option<f32> {
+ <#inner_ty as _num_traits::ToPrimitive>::to_f32(&self.0)
+ }
+ fn to_f64(&self) -> Option<f64> {
+ <#inner_ty as _num_traits::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 _num_traits::ToPrimitive for #name {
+ #[allow(trivial_numeric_casts)]
+ fn to_i64(&self) -> Option<i64> {
+ #match_expr
+ }
+
+ fn to_u64(&self) -> Option<u64> {
+ self.to_i64().map(|x| x as u64)
+ }
+ }
+ }
+ };
+
+ dummy_const_trick("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: syn::DeriveInput = syn::parse(input).unwrap();
+ let name = &ast.ident;
+ let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+ dummy_const_trick(
+ "NumOps",
+ &name,
+ quote! {
+ impl ::std::ops::Add for #name {
+ type Output = Self;
+ fn add(self, other: Self) -> Self {
+ #name(<#inner_ty as ::std::ops::Add>::add(self.0, other.0))
+ }
+ }
+ impl ::std::ops::Sub for #name {
+ type Output = Self;
+ fn sub(self, other: Self) -> Self {
+ #name(<#inner_ty as ::std::ops::Sub>::sub(self.0, other.0))
+ }
+ }
+ impl ::std::ops::Mul for #name {
+ type Output = Self;
+ fn mul(self, other: Self) -> Self {
+ #name(<#inner_ty as ::std::ops::Mul>::mul(self.0, other.0))
+ }
+ }
+ impl ::std::ops::Div for #name {
+ type Output = Self;
+ fn div(self, other: Self) -> Self {
+ #name(<#inner_ty as ::std::ops::Div>::div(self.0, other.0))
+ }
+ }
+ impl ::std::ops::Rem for #name {
+ type Output = Self;
+ fn rem(self, other: Self) -> Self {
+ #name(<#inner_ty as ::std::ops::Rem>::rem(self.0, other.0))
+ }
+ }
+ },
+ )
+ .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)]
+pub fn num_cast(input: TokenStream) -> TokenStream {
+ let ast: syn::DeriveInput = syn::parse(input).unwrap();
+ let name = &ast.ident;
+ let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+ dummy_const_trick(
+ "NumCast",
+ &name,
+ quote! {
+ impl _num_traits::NumCast for #name {
+ fn from<T: _num_traits::ToPrimitive>(n: T) -> Option<Self> {
+ <#inner_ty as _num_traits::NumCast>::from(n).map(#name)
+ }
+ }
+ },
+ )
+ .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)]
+pub fn zero(input: TokenStream) -> TokenStream {
+ let ast: syn::DeriveInput = syn::parse(input).unwrap();
+ let name = &ast.ident;
+ let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+ dummy_const_trick(
+ "Zero",
+ &name,
+ quote! {
+ impl _num_traits::Zero for #name {
+ fn zero() -> Self {
+ #name(<#inner_ty as _num_traits::Zero>::zero())
+ }
+ fn is_zero(&self) -> bool {
+ <#inner_ty as _num_traits::Zero>::is_zero(&self.0)
+ }
+ }
+ },
+ )
+ .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)]
+pub fn one(input: TokenStream) -> TokenStream {
+ let ast: syn::DeriveInput = syn::parse(input).unwrap();
+ let name = &ast.ident;
+ let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+ dummy_const_trick(
+ "One",
+ &name,
+ quote! {
+ impl _num_traits::One for #name {
+ fn one() -> Self {
+ #name(<#inner_ty as _num_traits::One>::one())
+ }
+ fn is_one(&self) -> bool {
+ <#inner_ty as _num_traits::One>::is_one(&self.0)
+ }
+ }
+ },
+ )
+ .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)]
+pub fn num(input: TokenStream) -> TokenStream {
+ let ast: syn::DeriveInput = syn::parse(input).unwrap();
+ let name = &ast.ident;
+ let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+ dummy_const_trick(
+ "Num",
+ &name,
+ quote! {
+ impl _num_traits::Num for #name {
+ type FromStrRadixErr = <#inner_ty as _num_traits::Num>::FromStrRadixErr;
+ fn from_str_radix(s: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
+ <#inner_ty as _num_traits::Num>::from_str_radix(s, radix).map(#name)
+ }
+ }
+ },
+ )
+ .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)]
+pub fn float(input: TokenStream) -> TokenStream {
+ let ast: syn::DeriveInput = syn::parse(input).unwrap();
+ let name = &ast.ident;
+ let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+ dummy_const_trick(
+ "Float",
+ &name,
+ quote! {
+ impl _num_traits::Float for #name {
+ fn nan() -> Self {
+ #name(<#inner_ty as _num_traits::Float>::nan())
+ }
+ fn infinity() -> Self {
+ #name(<#inner_ty as _num_traits::Float>::infinity())
+ }
+ fn neg_infinity() -> Self {
+ #name(<#inner_ty as _num_traits::Float>::neg_infinity())
+ }
+ fn neg_zero() -> Self {
+ #name(<#inner_ty as _num_traits::Float>::neg_zero())
+ }
+ fn min_value() -> Self {
+ #name(<#inner_ty as _num_traits::Float>::min_value())
+ }
+ fn min_positive_value() -> Self {
+ #name(<#inner_ty as _num_traits::Float>::min_positive_value())
+ }
+ fn max_value() -> Self {
+ #name(<#inner_ty as _num_traits::Float>::max_value())
+ }
+ fn is_nan(self) -> bool {
+ <#inner_ty as _num_traits::Float>::is_nan(self.0)
+ }
+ fn is_infinite(self) -> bool {
+ <#inner_ty as _num_traits::Float>::is_infinite(self.0)
+ }
+ fn is_finite(self) -> bool {
+ <#inner_ty as _num_traits::Float>::is_finite(self.0)
+ }
+ fn is_normal(self) -> bool {
+ <#inner_ty as _num_traits::Float>::is_normal(self.0)
+ }
+ fn classify(self) -> ::std::num::FpCategory {
+ <#inner_ty as _num_traits::Float>::classify(self.0)
+ }
+ fn floor(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::floor(self.0))
+ }
+ fn ceil(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::ceil(self.0))
+ }
+ fn round(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::round(self.0))
+ }
+ fn trunc(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::trunc(self.0))
+ }
+ fn fract(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::fract(self.0))
+ }
+ fn abs(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::abs(self.0))
+ }
+ fn signum(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::signum(self.0))
+ }
+ fn is_sign_positive(self) -> bool {
+ <#inner_ty as _num_traits::Float>::is_sign_positive(self.0)
+ }
+ fn is_sign_negative(self) -> bool {
+ <#inner_ty as _num_traits::Float>::is_sign_negative(self.0)
+ }
+ fn mul_add(self, a: Self, b: Self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::mul_add(self.0, a.0, b.0))
+ }
+ fn recip(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::recip(self.0))
+ }
+ fn powi(self, n: i32) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::powi(self.0, n))
+ }
+ fn powf(self, n: Self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::powf(self.0, n.0))
+ }
+ fn sqrt(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::sqrt(self.0))
+ }
+ fn exp(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::exp(self.0))
+ }
+ fn exp2(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::exp2(self.0))
+ }
+ fn ln(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::ln(self.0))
+ }
+ fn log(self, base: Self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::log(self.0, base.0))
+ }
+ fn log2(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::log2(self.0))
+ }
+ fn log10(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::log10(self.0))
+ }
+ fn max(self, other: Self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::max(self.0, other.0))
+ }
+ fn min(self, other: Self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::min(self.0, other.0))
+ }
+ fn abs_sub(self, other: Self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::abs_sub(self.0, other.0))
+ }
+ fn cbrt(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::cbrt(self.0))
+ }
+ fn hypot(self, other: Self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::hypot(self.0, other.0))
+ }
+ fn sin(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::sin(self.0))
+ }
+ fn cos(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::cos(self.0))
+ }
+ fn tan(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::tan(self.0))
+ }
+ fn asin(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::asin(self.0))
+ }
+ fn acos(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::acos(self.0))
+ }
+ fn atan(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::atan(self.0))
+ }
+ fn atan2(self, other: Self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::atan2(self.0, other.0))
+ }
+ fn sin_cos(self) -> (Self, Self) {
+ let (x, y) = <#inner_ty as _num_traits::Float>::sin_cos(self.0);
+ (#name(x), #name(y))
+ }
+ fn exp_m1(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::exp_m1(self.0))
+ }
+ fn ln_1p(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::ln_1p(self.0))
+ }
+ fn sinh(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::sinh(self.0))
+ }
+ fn cosh(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::cosh(self.0))
+ }
+ fn tanh(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::tanh(self.0))
+ }
+ fn asinh(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::asinh(self.0))
+ }
+ fn acosh(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::acosh(self.0))
+ }
+ fn atanh(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::atanh(self.0))
+ }
+ fn integer_decode(self) -> (u64, i16, i8) {
+ <#inner_ty as _num_traits::Float>::integer_decode(self.0)
+ }
+ fn epsilon() -> Self {
+ #name(<#inner_ty as _num_traits::Float>::epsilon())
+ }
+ fn to_degrees(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::to_degrees(self.0))
+ }
+ fn to_radians(self) -> Self {
+ #name(<#inner_ty as _num_traits::Float>::to_radians(self.0))
+ }
+ }
+ },
+ )
+ .into()
+}
diff --git a/tests/empty_enum.rs b/tests/empty_enum.rs
new file mode 100644
index 0000000..173996c
--- /dev/null
+++ b/tests/empty_enum.rs
@@ -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
index 0000000..9eae7fb
--- /dev/null
+++ b/tests/issue-6.rs
@@ -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
index 0000000..30c04d2
--- /dev/null
+++ b/tests/issue-9.rs
@@ -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
index 0000000..2b58190
--- /dev/null
+++ b/tests/newtype-2015.rs
@@ -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
index 0000000..6eafd09
--- /dev/null
+++ b/tests/newtype.rs
@@ -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
index 0000000..edebbec
--- /dev/null
+++ b/tests/num_derive_without_num.rs
@@ -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
index 0000000..8309f0e
--- /dev/null
+++ b/tests/trivial-2015.rs
@@ -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
index 0000000..d3b56b6
--- /dev/null
+++ b/tests/trivial.rs
@@ -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
index 0000000..94c8445
--- /dev/null
+++ b/tests/with_custom_values.rs
@@ -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);
+}