summaryrefslogtreecommitdiffstats
path: root/rust/vendor/num_enum_derive
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:39:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:39:49 +0000
commita0aa2307322cd47bbf416810ac0292925e03be87 (patch)
tree37076262a026c4b48c8a0e84f44ff9187556ca35 /rust/vendor/num_enum_derive
parentInitial commit. (diff)
downloadsuricata-a0aa2307322cd47bbf416810ac0292925e03be87.tar.xz
suricata-a0aa2307322cd47bbf416810ac0292925e03be87.zip
Adding upstream version 1:7.0.3.upstream/1%7.0.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'rust/vendor/num_enum_derive')
-rw-r--r--rust/vendor/num_enum_derive/.cargo-checksum.json1
-rw-r--r--rust/vendor/num_enum_derive/Cargo.toml52
-rw-r--r--rust/vendor/num_enum_derive/LICENSE-APACHE176
-rw-r--r--rust/vendor/num_enum_derive/LICENSE-BSD27
-rw-r--r--rust/vendor/num_enum_derive/LICENSE-MIT23
-rw-r--r--rust/vendor/num_enum_derive/README.md277
-rw-r--r--rust/vendor/num_enum_derive/src/lib.rs1066
7 files changed, 1622 insertions, 0 deletions
diff --git a/rust/vendor/num_enum_derive/.cargo-checksum.json b/rust/vendor/num_enum_derive/.cargo-checksum.json
new file mode 100644
index 0000000..4cd36f9
--- /dev/null
+++ b/rust/vendor/num_enum_derive/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"91ca56a63860212f0ad546a431076d9650a190a29a6fe1f42dd9624f44ee05e8","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-BSD":"0be96d891d00e0ae0df75d7f3289b12871c000a1f5ac744f3b570768d4bb277c","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"808954bb7af3a919b66c792ccef12e31b98070e78e2a83cde665d0e485cb1a11","src/lib.rs":"92a94fee79ca9c1ae4769246cd88a1f4af28d0b731d416b2643059fed00ef6da"},"package":"dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"} \ No newline at end of file
diff --git a/rust/vendor/num_enum_derive/Cargo.toml b/rust/vendor/num_enum_derive/Cargo.toml
new file mode 100644
index 0000000..4397b7d
--- /dev/null
+++ b/rust/vendor/num_enum_derive/Cargo.toml
@@ -0,0 +1,52 @@
+# 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 are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+name = "num_enum_derive"
+version = "0.5.11"
+authors = [
+ "Daniel Wagner-Hall <dawagner@gmail.com>",
+ "Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>",
+ "Vincent Esche <regexident@gmail.com>",
+]
+description = "Internal implementation details for ::num_enum (Procedural macros to make inter-operation between primitives and enums easier)"
+readme = "README.md"
+keywords = []
+categories = []
+license = "BSD-3-Clause OR MIT OR Apache-2.0"
+repository = "https://github.com/illicitonion/num_enum"
+
+[package.metadata.docs.rs]
+features = ["external_doc"]
+
+[lib]
+proc-macro = true
+
+[dependencies.proc-macro-crate]
+version = "1"
+optional = true
+
+[dependencies.proc-macro2]
+version = "1"
+
+[dependencies.quote]
+version = "1"
+
+[dependencies.syn]
+version = "1.0.15"
+features = ["parsing"]
+
+[features]
+complex-expressions = ["syn/full"]
+default = ["std"]
+external_doc = []
+std = ["proc-macro-crate"]
diff --git a/rust/vendor/num_enum_derive/LICENSE-APACHE b/rust/vendor/num_enum_derive/LICENSE-APACHE
new file mode 100644
index 0000000..1b5ec8b
--- /dev/null
+++ b/rust/vendor/num_enum_derive/LICENSE-APACHE
@@ -0,0 +1,176 @@
+ 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
diff --git a/rust/vendor/num_enum_derive/LICENSE-BSD b/rust/vendor/num_enum_derive/LICENSE-BSD
new file mode 100644
index 0000000..b742e29
--- /dev/null
+++ b/rust/vendor/num_enum_derive/LICENSE-BSD
@@ -0,0 +1,27 @@
+Copyright (c) 2018, Daniel Wagner-Hall
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of num_enum nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/rust/vendor/num_enum_derive/LICENSE-MIT b/rust/vendor/num_enum_derive/LICENSE-MIT
new file mode 100644
index 0000000..31aa793
--- /dev/null
+++ b/rust/vendor/num_enum_derive/LICENSE-MIT
@@ -0,0 +1,23 @@
+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/rust/vendor/num_enum_derive/README.md b/rust/vendor/num_enum_derive/README.md
new file mode 100644
index 0000000..902cee7
--- /dev/null
+++ b/rust/vendor/num_enum_derive/README.md
@@ -0,0 +1,277 @@
+num_enum
+========
+
+Procedural macros to make inter-operation between primitives and enums easier.
+This crate is no_std compatible.
+
+[![crates.io](https://img.shields.io/crates/v/num_enum.svg)](https://crates.io/crates/num_enum)
+[![Documentation](https://docs.rs/num_enum/badge.svg)](https://docs.rs/num_enum)
+[![Build Status](https://travis-ci.org/illicitonion/num_enum.svg?branch=master)](https://travis-ci.org/illicitonion/num_enum)
+
+Turning an enum into a primitive
+--------------------------------
+
+```rust
+use num_enum::IntoPrimitive;
+
+#[derive(IntoPrimitive)]
+#[repr(u8)]
+enum Number {
+ Zero,
+ One,
+}
+
+fn main() {
+ let zero: u8 = Number::Zero.into();
+ assert_eq!(zero, 0u8);
+}
+```
+
+`num_enum`'s `IntoPrimitive` is more type-safe than using `as`, because `as` will silently truncate - `num_enum` only derives `From` for exactly the discriminant type of the enum.
+
+Attempting to turn a primitive into an enum with try_from
+----------------------------------------------
+
+```rust
+use num_enum::TryFromPrimitive;
+use std::convert::TryFrom;
+
+#[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
+#[repr(u8)]
+enum Number {
+ Zero,
+ One,
+}
+
+fn main() {
+ let zero = Number::try_from(0u8);
+ assert_eq!(zero, Ok(Number::Zero));
+
+ let three = Number::try_from(3u8);
+ assert_eq!(
+ three.unwrap_err().to_string(),
+ "No discriminant in enum `Number` matches the value `3`",
+ );
+}
+```
+
+Variant alternatives
+---------------
+
+Sometimes a single enum variant might be representable by multiple numeric values.
+
+The `#[num_enum(alternatives = [..])]` attribute allows you to define additional value alternatives for individual variants.
+
+(The behavior of `IntoPrimitive` is unaffected by this attribute, it will always return the canonical value.)
+
+```rust
+use num_enum::TryFromPrimitive;
+use std::convert::TryFrom;
+
+#[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
+#[repr(u8)]
+enum Number {
+ Zero = 0,
+ #[num_enum(alternatives = [2])]
+ OneOrTwo = 1,
+}
+
+fn main() {
+ let zero = Number::try_from(0u8);
+ assert_eq!(zero, Ok(Number::Zero));
+
+ let one = Number::try_from(1u8);
+ assert_eq!(one, Ok(Number::OneOrTwo));
+
+ let two = Number::try_from(2u8);
+ assert_eq!(two, Ok(Number::OneOrTwo));
+
+ let three = Number::try_from(3u8);
+ assert_eq!(
+ three.unwrap_err().to_string(),
+ "No discriminant in enum `Number` matches the value `3`",
+ );
+}
+```
+
+Range expressions are also supported for alternatives, but this requires enabling the `complex-expressions` feature:
+
+```rust
+use num_enum::TryFromPrimitive;
+use std::convert::TryFrom;
+
+#[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
+#[repr(u8)]
+enum Number {
+ Zero = 0,
+ #[num_enum(alternatives = [2..16])]
+ Some = 1,
+ #[num_enum(alternatives = [17, 18..=255])]
+ Many = 16,
+}
+
+fn main() {
+ let zero = Number::try_from(0u8);
+ assert_eq!(zero, Ok(Number::Zero));
+
+ let some = Number::try_from(15u8);
+ assert_eq!(some, Ok(Number::Some));
+
+ let many = Number::try_from(255u8);
+ assert_eq!(many, Ok(Number::Many));
+}
+```
+
+Default variant
+---------------
+
+Sometimes it is desirable to have an `Other` variant in an enum that acts as a kind of a wildcard matching all the value not yet covered by other variants.
+
+The `#[num_enum(default)]` attribute allows you to mark variant as the default.
+
+(The behavior of `IntoPrimitive` is unaffected by this attribute, it will always return the canonical value.)
+
+```rust
+use num_enum::TryFromPrimitive;
+use std::convert::TryFrom;
+
+#[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
+#[repr(u8)]
+enum Number {
+ Zero = 0,
+ #[num_enum(default)]
+ NonZero = 1,
+}
+
+fn main() {
+ let zero = Number::try_from(0u8);
+ assert_eq!(zero, Ok(Number::Zero));
+
+ let one = Number::try_from(1u8);
+ assert_eq!(one, Ok(Number::NonZero));
+
+ let two = Number::try_from(2u8);
+ assert_eq!(two, Ok(Number::NonZero));
+}
+```
+
+Safely turning a primitive into an exhaustive enum with from_primitive
+-------------------------------------------------------------
+
+If your enum has all possible primitive values covered, you can derive `FromPrimitive` for it (which auto-implement stdlib's `From`):
+
+You can cover all possible values by:
+* Having variants for every possible value
+* Having a variant marked `#[num_enum(default)]`
+* Having a variant marked `#[num_enum(catch_all)]`
+* Having `#[num_enum(alternatives = [...])`s covering values not covered by a variant.
+
+```rust
+use num_enum::FromPrimitive;
+
+#[derive(Debug, Eq, PartialEq, FromPrimitive)]
+#[repr(u8)]
+enum Number {
+ Zero,
+ #[num_enum(default)]
+ NonZero,
+}
+
+fn main() {
+ assert_eq!(
+ Number::Zero,
+ Number::from(0_u8),
+ );
+ assert_eq!(
+ Number::NonZero,
+ Number::from(1_u8),
+ );
+}
+```
+
+Catch-all variant
+-----------------
+
+Sometimes it is desirable to have an `Other` variant which holds the otherwise un-matched value as a field.
+
+The `#[num_enum(catch_all)]` attribute allows you to mark at most one variant for this purpose. The variant it's applied to must be a tuple variant with exactly one field matching the `repr` type.
+
+```rust
+use num_enum::FromPrimitive;
+use std::convert::TryFrom;
+
+#[derive(Debug, Eq, PartialEq, FromPrimitive)]
+#[repr(u8)]
+enum Number {
+ Zero = 0,
+ #[num_enum(catch_all)]
+ NonZero(u8),
+}
+
+fn main() {
+ let zero = Number::from(0u8);
+ assert_eq!(zero, Number::Zero);
+
+ let one = Number::from(1u8);
+ assert_eq!(one, Number::NonZero(1_u8));
+
+ let two = Number::from(2u8);
+ assert_eq!(two, Number::NonZero(2_u8));
+}
+```
+
+As this is naturally exhaustive, this is only supported for `FromPrimitive`, not also `TryFromPrimitive`.
+
+Unsafely turning a primitive into an enum with from_unchecked
+-------------------------------------------------------------
+
+If you're really certain a conversion will succeed (and have not made use of `#[num_enum(default)]` or `#[num_enum(alternatives = [..])]`
+for any of its variants), and want to avoid a small amount of overhead, you can use unsafe code to do this conversion.
+Unless you have data showing that the match statement generated in the `try_from` above is a bottleneck for you,
+you should avoid doing this, as the unsafe code has potential to cause serious memory issues in your program.
+
+```rust
+use num_enum::UnsafeFromPrimitive;
+
+#[derive(Debug, Eq, PartialEq, UnsafeFromPrimitive)]
+#[repr(u8)]
+enum Number {
+ Zero,
+ One,
+}
+
+fn main() {
+ assert_eq!(
+ unsafe { Number::from_unchecked(0_u8) },
+ Number::Zero,
+ );
+ assert_eq!(
+ unsafe { Number::from_unchecked(1_u8) },
+ Number::One,
+ );
+}
+
+unsafe fn undefined_behavior() {
+ let _ = Number::from_unchecked(2); // 2 is not a valid discriminant!
+}
+```
+
+Optional features
+-----------------
+
+Some enum values may be composed of complex expressions, for example:
+
+```rust
+enum Number {
+ Zero = (0, 1).0,
+ One = (0, 1).1,
+}
+```
+
+To cut down on compile time, these are not supported by default, but if you enable the `complex-expressions`
+feature of your dependency on `num_enum`, these should start working.
+
+License
+-------
+
+num_enum may be used under your choice of the BSD 3-clause, Apache 2, or MIT license.
diff --git a/rust/vendor/num_enum_derive/src/lib.rs b/rust/vendor/num_enum_derive/src/lib.rs
new file mode 100644
index 0000000..600730f
--- /dev/null
+++ b/rust/vendor/num_enum_derive/src/lib.rs
@@ -0,0 +1,1066 @@
+// Not supported by MSRV
+#![allow(clippy::uninlined_format_args)]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+use proc_macro2::Span;
+use quote::{format_ident, quote};
+use std::collections::BTreeSet;
+use syn::{
+ parse::{Parse, ParseStream},
+ parse_macro_input, parse_quote,
+ spanned::Spanned,
+ Attribute, Data, DeriveInput, Error, Expr, ExprLit, ExprUnary, Fields, Ident, Lit, LitInt,
+ LitStr, Meta, Result, UnOp,
+};
+
+macro_rules! die {
+ ($spanned:expr=>
+ $msg:expr
+ ) => {
+ return Err(Error::new_spanned($spanned, $msg))
+ };
+
+ (
+ $msg:expr
+ ) => {
+ return Err(Error::new(Span::call_site(), $msg))
+ };
+}
+
+fn literal(i: i128) -> Expr {
+ Expr::Lit(ExprLit {
+ lit: Lit::Int(LitInt::new(&i.to_string(), Span::call_site())),
+ attrs: vec![],
+ })
+}
+
+enum DiscriminantValue {
+ Literal(i128),
+ Expr(Expr),
+}
+
+fn parse_discriminant(val_exp: &Expr) -> Result<DiscriminantValue> {
+ let mut sign = 1;
+ let mut unsigned_expr = val_exp;
+ if let Expr::Unary(ExprUnary {
+ op: UnOp::Neg(..),
+ expr,
+ ..
+ }) = val_exp
+ {
+ unsigned_expr = expr;
+ sign = -1;
+ }
+ if let Expr::Lit(ExprLit {
+ lit: Lit::Int(ref lit_int),
+ ..
+ }) = unsigned_expr
+ {
+ Ok(DiscriminantValue::Literal(
+ sign * lit_int.base10_parse::<i128>()?,
+ ))
+ } else {
+ Ok(DiscriminantValue::Expr(val_exp.clone()))
+ }
+}
+
+#[cfg(feature = "complex-expressions")]
+fn parse_alternative_values(val_expr: &Expr) -> Result<Vec<DiscriminantValue>> {
+ fn range_expr_value_to_number(
+ parent_range_expr: &Expr,
+ range_bound_value: &Option<Box<Expr>>,
+ ) -> Result<i128> {
+ // Avoid needing to calculate what the lower and upper bound would be - these are type dependent,
+ // and also may not be obvious in context (e.g. an omitted bound could reasonably mean "from the last discriminant" or "from the lower bound of the type").
+ if let Some(range_bound_value) = range_bound_value {
+ let range_bound_value = parse_discriminant(range_bound_value.as_ref())?;
+ // If non-literals are used, we can't expand to the mapped values, so can't write a nice match statement or do exhaustiveness checking.
+ // Require literals instead.
+ if let DiscriminantValue::Literal(value) = range_bound_value {
+ return Ok(value);
+ }
+ }
+ die!(parent_range_expr => "When ranges are used for alternate values, both bounds most be explicitly specified numeric literals")
+ }
+
+ if let Expr::Range(syn::ExprRange {
+ from, to, limits, ..
+ }) = val_expr
+ {
+ let lower = range_expr_value_to_number(val_expr, from)?;
+ let upper = range_expr_value_to_number(val_expr, to)?;
+ // While this is technically allowed in Rust, and results in an empty range, it's almost certainly a mistake in this context.
+ if lower > upper {
+ die!(val_expr => "When using ranges for alternate values, upper bound must not be less than lower bound");
+ }
+ let mut values = Vec::with_capacity((upper - lower) as usize);
+ let mut next = lower;
+ loop {
+ match limits {
+ syn::RangeLimits::HalfOpen(..) => {
+ if next == upper {
+ break;
+ }
+ }
+ syn::RangeLimits::Closed(..) => {
+ if next > upper {
+ break;
+ }
+ }
+ }
+ values.push(DiscriminantValue::Literal(next));
+ next += 1;
+ }
+ return Ok(values);
+ }
+ parse_discriminant(val_expr).map(|v| vec![v])
+}
+
+#[cfg(not(feature = "complex-expressions"))]
+fn parse_alternative_values(val_expr: &Expr) -> Result<Vec<DiscriminantValue>> {
+ parse_discriminant(val_expr).map(|v| vec![v])
+}
+
+mod kw {
+ syn::custom_keyword!(default);
+ syn::custom_keyword!(catch_all);
+ syn::custom_keyword!(alternatives);
+}
+
+struct NumEnumVariantAttributes {
+ items: syn::punctuated::Punctuated<NumEnumVariantAttributeItem, syn::Token![,]>,
+}
+
+impl Parse for NumEnumVariantAttributes {
+ fn parse(input: ParseStream<'_>) -> Result<Self> {
+ Ok(Self {
+ items: input.parse_terminated(NumEnumVariantAttributeItem::parse)?,
+ })
+ }
+}
+
+enum NumEnumVariantAttributeItem {
+ Default(VariantDefaultAttribute),
+ CatchAll(VariantCatchAllAttribute),
+ Alternatives(VariantAlternativesAttribute),
+}
+
+impl Parse for NumEnumVariantAttributeItem {
+ fn parse(input: ParseStream<'_>) -> Result<Self> {
+ let lookahead = input.lookahead1();
+ if lookahead.peek(kw::default) {
+ input.parse().map(Self::Default)
+ } else if lookahead.peek(kw::catch_all) {
+ input.parse().map(Self::CatchAll)
+ } else if lookahead.peek(kw::alternatives) {
+ input.parse().map(Self::Alternatives)
+ } else {
+ Err(lookahead.error())
+ }
+ }
+}
+
+struct VariantDefaultAttribute {
+ keyword: kw::default,
+}
+
+impl Parse for VariantDefaultAttribute {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(Self {
+ keyword: input.parse()?,
+ })
+ }
+}
+
+impl Spanned for VariantDefaultAttribute {
+ fn span(&self) -> Span {
+ self.keyword.span()
+ }
+}
+
+struct VariantCatchAllAttribute {
+ keyword: kw::catch_all,
+}
+
+impl Parse for VariantCatchAllAttribute {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(Self {
+ keyword: input.parse()?,
+ })
+ }
+}
+
+impl Spanned for VariantCatchAllAttribute {
+ fn span(&self) -> Span {
+ self.keyword.span()
+ }
+}
+
+struct VariantAlternativesAttribute {
+ keyword: kw::alternatives,
+ _eq_token: syn::Token![=],
+ _bracket_token: syn::token::Bracket,
+ expressions: syn::punctuated::Punctuated<Expr, syn::Token![,]>,
+}
+
+impl Parse for VariantAlternativesAttribute {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let content;
+ let keyword = input.parse()?;
+ let _eq_token = input.parse()?;
+ let _bracket_token = syn::bracketed!(content in input);
+ let expressions = content.parse_terminated(Expr::parse)?;
+ Ok(Self {
+ keyword,
+ _eq_token,
+ _bracket_token,
+ expressions,
+ })
+ }
+}
+
+impl Spanned for VariantAlternativesAttribute {
+ fn span(&self) -> Span {
+ self.keyword.span()
+ }
+}
+
+#[derive(::core::default::Default)]
+struct AttributeSpans {
+ default: Vec<Span>,
+ catch_all: Vec<Span>,
+ alternatives: Vec<Span>,
+}
+
+struct VariantInfo {
+ ident: Ident,
+ attr_spans: AttributeSpans,
+ is_default: bool,
+ is_catch_all: bool,
+ canonical_value: Expr,
+ alternative_values: Vec<Expr>,
+}
+
+impl VariantInfo {
+ fn all_values(&self) -> impl Iterator<Item = &Expr> {
+ ::core::iter::once(&self.canonical_value).chain(self.alternative_values.iter())
+ }
+
+ fn is_complex(&self) -> bool {
+ !self.alternative_values.is_empty()
+ }
+}
+
+struct EnumInfo {
+ name: Ident,
+ repr: Ident,
+ variants: Vec<VariantInfo>,
+}
+
+impl EnumInfo {
+ /// Returns whether the number of variants (ignoring defaults, catch-alls, etc) is the same as
+ /// the capacity of the repr.
+ fn is_naturally_exhaustive(&self) -> Result<bool> {
+ let repr_str = self.repr.to_string();
+ if !repr_str.is_empty() {
+ let suffix = repr_str
+ .strip_prefix('i')
+ .or_else(|| repr_str.strip_prefix('u'));
+ if let Some(suffix) = suffix {
+ if let Ok(bits) = suffix.parse::<u32>() {
+ let variants = 1usize.checked_shl(bits);
+ return Ok(variants.map_or(false, |v| {
+ v == self
+ .variants
+ .iter()
+ .map(|v| v.alternative_values.len() + 1)
+ .sum()
+ }));
+ }
+ }
+ }
+ die!(self.repr.clone() => "Failed to parse repr into bit size");
+ }
+
+ fn has_default_variant(&self) -> bool {
+ self.default().is_some()
+ }
+
+ fn has_complex_variant(&self) -> bool {
+ self.variants.iter().any(|info| info.is_complex())
+ }
+
+ fn default(&self) -> Option<&Ident> {
+ self.variants
+ .iter()
+ .find(|info| info.is_default)
+ .map(|info| &info.ident)
+ }
+
+ fn catch_all(&self) -> Option<&Ident> {
+ self.variants
+ .iter()
+ .find(|info| info.is_catch_all)
+ .map(|info| &info.ident)
+ }
+
+ fn first_default_attr_span(&self) -> Option<&Span> {
+ self.variants
+ .iter()
+ .find_map(|info| info.attr_spans.default.first())
+ }
+
+ fn first_alternatives_attr_span(&self) -> Option<&Span> {
+ self.variants
+ .iter()
+ .find_map(|info| info.attr_spans.alternatives.first())
+ }
+
+ fn variant_idents(&self) -> Vec<Ident> {
+ self.variants
+ .iter()
+ .map(|variant| variant.ident.clone())
+ .collect()
+ }
+
+ fn expression_idents(&self) -> Vec<Vec<Ident>> {
+ self.variants
+ .iter()
+ .filter(|variant| !variant.is_catch_all)
+ .map(|info| {
+ let indices = 0..(info.alternative_values.len() + 1);
+ indices
+ .map(|index| format_ident!("{}__num_enum_{}__", info.ident, index))
+ .collect()
+ })
+ .collect()
+ }
+
+ fn variant_expressions(&self) -> Vec<Vec<Expr>> {
+ self.variants
+ .iter()
+ .map(|variant| variant.all_values().cloned().collect())
+ .collect()
+ }
+}
+
+impl Parse for EnumInfo {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok({
+ let input: DeriveInput = input.parse()?;
+ let name = input.ident;
+ let data = match input.data {
+ Data::Enum(data) => data,
+ Data::Union(data) => die!(data.union_token => "Expected enum but found union"),
+ Data::Struct(data) => die!(data.struct_token => "Expected enum but found struct"),
+ };
+
+ let repr: Ident = {
+ let mut attrs = input.attrs.into_iter();
+ loop {
+ if let Some(attr) = attrs.next() {
+ if let Ok(Meta::List(meta_list)) = attr.parse_meta() {
+ if let Some(ident) = meta_list.path.get_ident() {
+ if ident == "repr" {
+ let mut nested = meta_list.nested.iter();
+ if nested.len() != 1 {
+ die!(attr =>
+ "Expected exactly one `repr` argument"
+ );
+ }
+ let repr = nested.next().unwrap();
+ let repr: Ident = parse_quote! {
+ #repr
+ };
+ if repr == "C" {
+ die!(repr =>
+ "repr(C) doesn't have a well defined size"
+ );
+ } else {
+ break repr;
+ }
+ }
+ }
+ }
+ } else {
+ die!("Missing `#[repr({Integer})]` attribute");
+ }
+ }
+ };
+
+ let mut variants: Vec<VariantInfo> = vec![];
+ let mut has_default_variant: bool = false;
+ let mut has_catch_all_variant: bool = false;
+
+ // Vec to keep track of the used discriminants and alt values.
+ let mut discriminant_int_val_set = BTreeSet::new();
+
+ let mut next_discriminant = literal(0);
+ for variant in data.variants.into_iter() {
+ let ident = variant.ident.clone();
+
+ let discriminant = match &variant.discriminant {
+ Some(d) => d.1.clone(),
+ None => next_discriminant.clone(),
+ };
+
+ let mut attr_spans: AttributeSpans = Default::default();
+ let mut raw_alternative_values: Vec<Expr> = vec![];
+ // Keep the attribute around for better error reporting.
+ let mut alt_attr_ref: Vec<&Attribute> = vec![];
+
+ // `#[num_enum(default)]` is required by `#[derive(FromPrimitive)]`
+ // and forbidden by `#[derive(UnsafeFromPrimitive)]`, so we need to
+ // keep track of whether we encountered such an attribute:
+ let mut is_default: bool = false;
+ let mut is_catch_all: bool = false;
+
+ for attribute in &variant.attrs {
+ if attribute.path.is_ident("default") {
+ if has_default_variant {
+ die!(attribute =>
+ "Multiple variants marked `#[default]` or `#[num_enum(default)]` found"
+ );
+ } else if has_catch_all_variant {
+ die!(attribute =>
+ "Attribute `default` is mutually exclusive with `catch_all`"
+ );
+ }
+ attr_spans.default.push(attribute.span());
+ is_default = true;
+ has_default_variant = true;
+ }
+
+ if attribute.path.is_ident("num_enum") {
+ match attribute.parse_args_with(NumEnumVariantAttributes::parse) {
+ Ok(variant_attributes) => {
+ for variant_attribute in variant_attributes.items {
+ match variant_attribute {
+ NumEnumVariantAttributeItem::Default(default) => {
+ if has_default_variant {
+ die!(default.keyword =>
+ "Multiple variants marked `#[default]` or `#[num_enum(default)]` found"
+ );
+ } else if has_catch_all_variant {
+ die!(default.keyword =>
+ "Attribute `default` is mutually exclusive with `catch_all`"
+ );
+ }
+ attr_spans.default.push(default.span());
+ is_default = true;
+ has_default_variant = true;
+ }
+ NumEnumVariantAttributeItem::CatchAll(catch_all) => {
+ if has_catch_all_variant {
+ die!(catch_all.keyword =>
+ "Multiple variants marked with `#[num_enum(catch_all)]`"
+ );
+ } else if has_default_variant {
+ die!(catch_all.keyword =>
+ "Attribute `catch_all` is mutually exclusive with `default`"
+ );
+ }
+
+ match variant
+ .fields
+ .iter()
+ .collect::<Vec<_>>()
+ .as_slice()
+ {
+ [syn::Field {
+ ty: syn::Type::Path(syn::TypePath { path, .. }),
+ ..
+ }] if path.is_ident(&repr) => {
+ attr_spans.catch_all.push(catch_all.span());
+ is_catch_all = true;
+ has_catch_all_variant = true;
+ }
+ _ => {
+ die!(catch_all.keyword =>
+ "Variant with `catch_all` must be a tuple with exactly 1 field matching the repr type"
+ );
+ }
+ }
+ }
+ NumEnumVariantAttributeItem::Alternatives(alternatives) => {
+ attr_spans.alternatives.push(alternatives.span());
+ raw_alternative_values.extend(alternatives.expressions);
+ alt_attr_ref.push(attribute);
+ }
+ }
+ }
+ }
+ Err(err) => {
+ if cfg!(not(feature = "complex-expressions")) {
+ let attribute_str = format!("{}", attribute.tokens);
+ if attribute_str.contains("alternatives")
+ && attribute_str.contains("..")
+ {
+ // Give a nice error message suggesting how to fix the problem.
+ die!(attribute => "Ranges are only supported as num_enum alternate values if the `complex-expressions` feature of the crate `num_enum` is enabled".to_string())
+ }
+ }
+ die!(attribute =>
+ format!("Invalid attribute: {}", err)
+ );
+ }
+ }
+ }
+ }
+
+ if !is_catch_all {
+ match &variant.fields {
+ Fields::Named(_) | Fields::Unnamed(_) => {
+ die!(variant => format!("`{}` only supports unit variants (with no associated data), but `{}::{}` was not a unit variant.", get_crate_name(), name, ident));
+ }
+ Fields::Unit => {}
+ }
+ }
+
+ let discriminant_value = parse_discriminant(&discriminant)?;
+
+ // Check for collision.
+ // We can't do const evaluation, or even compare arbitrary Exprs,
+ // so unfortunately we can't check for duplicates.
+ // That's not the end of the world, just we'll end up with compile errors for
+ // matches with duplicate branches in generated code instead of nice friendly error messages.
+ if let DiscriminantValue::Literal(canonical_value_int) = discriminant_value {
+ if discriminant_int_val_set.contains(&canonical_value_int) {
+ die!(ident => format!("The discriminant '{}' collides with a value attributed to a previous variant", canonical_value_int))
+ }
+ }
+
+ // Deal with the alternative values.
+ let mut flattened_alternative_values = Vec::new();
+ let mut flattened_raw_alternative_values = Vec::new();
+ for raw_alternative_value in raw_alternative_values {
+ let expanded_values = parse_alternative_values(&raw_alternative_value)?;
+ for expanded_value in expanded_values {
+ flattened_alternative_values.push(expanded_value);
+ flattened_raw_alternative_values.push(raw_alternative_value.clone())
+ }
+ }
+
+ if !flattened_alternative_values.is_empty() {
+ let alternate_int_values = flattened_alternative_values
+ .into_iter()
+ .map(|v| {
+ match v {
+ DiscriminantValue::Literal(value) => Ok(value),
+ DiscriminantValue::Expr(expr) => {
+ if let Expr::Range(_) = expr {
+ if cfg!(not(feature = "complex-expressions")) {
+ // Give a nice error message suggesting how to fix the problem.
+ die!(expr => "Ranges are only supported as num_enum alternate values if the `complex-expressions` feature of the crate `num_enum` is enabled".to_string())
+ }
+ }
+ // We can't do uniqueness checking on non-literals, so we don't allow them as alternate values.
+ // We could probably allow them, but there doesn't seem to be much of a use-case,
+ // and it's easier to give good error messages about duplicate values this way,
+ // rather than rustc errors on conflicting match branches.
+ die!(expr => "Only literals are allowed as num_enum alternate values".to_string())
+ },
+ }
+ })
+ .collect::<Result<Vec<i128>>>()?;
+ let mut sorted_alternate_int_values = alternate_int_values.clone();
+ sorted_alternate_int_values.sort_unstable();
+ let sorted_alternate_int_values = sorted_alternate_int_values;
+
+ // Check if the current discriminant is not in the alternative values.
+ if let DiscriminantValue::Literal(canonical_value_int) = discriminant_value {
+ if let Some(index) = alternate_int_values
+ .iter()
+ .position(|&x| x == canonical_value_int)
+ {
+ die!(&flattened_raw_alternative_values[index] => format!("'{}' in the alternative values is already attributed as the discriminant of this variant", canonical_value_int));
+ }
+ }
+
+ // Search for duplicates, the vec is sorted. Warn about them.
+ if (1..sorted_alternate_int_values.len()).any(|i| {
+ sorted_alternate_int_values[i] == sorted_alternate_int_values[i - 1]
+ }) {
+ let attr = *alt_attr_ref.last().unwrap();
+ die!(attr => "There is duplication in the alternative values");
+ }
+ // Search if those discriminant_int_val_set where already attributed.
+ // (discriminant_int_val_set is BTreeSet, and iter().next_back() is the is the maximum in the set.)
+ if let Some(last_upper_val) = discriminant_int_val_set.iter().next_back() {
+ if sorted_alternate_int_values.first().unwrap() <= last_upper_val {
+ for (index, val) in alternate_int_values.iter().enumerate() {
+ if discriminant_int_val_set.contains(val) {
+ die!(&flattened_raw_alternative_values[index] => format!("'{}' in the alternative values is already attributed to a previous variant", val));
+ }
+ }
+ }
+ }
+
+ // Reconstruct the alternative_values vec of Expr but sorted.
+ flattened_raw_alternative_values = sorted_alternate_int_values
+ .iter()
+ .map(|val| literal(val.to_owned()))
+ .collect();
+
+ // Add the alternative values to the the set to keep track.
+ discriminant_int_val_set.extend(sorted_alternate_int_values);
+ }
+
+ // Add the current discriminant to the the set to keep track.
+ if let DiscriminantValue::Literal(canonical_value_int) = discriminant_value {
+ discriminant_int_val_set.insert(canonical_value_int);
+ }
+
+ variants.push(VariantInfo {
+ ident,
+ attr_spans,
+ is_default,
+ is_catch_all,
+ canonical_value: discriminant,
+ alternative_values: flattened_raw_alternative_values,
+ });
+
+ // Get the next value for the discriminant.
+ next_discriminant = match discriminant_value {
+ DiscriminantValue::Literal(int_value) => literal(int_value.wrapping_add(1)),
+ DiscriminantValue::Expr(expr) => {
+ parse_quote! {
+ #repr::wrapping_add(#expr, 1)
+ }
+ }
+ }
+ }
+
+ EnumInfo {
+ name,
+ repr,
+ variants,
+ }
+ })
+ }
+}
+
+/// Implements `Into<Primitive>` for a `#[repr(Primitive)] enum`.
+///
+/// (It actually implements `From<Enum> for Primitive`)
+///
+/// ## Allows turning an enum into a primitive.
+///
+/// ```rust
+/// use num_enum::IntoPrimitive;
+///
+/// #[derive(IntoPrimitive)]
+/// #[repr(u8)]
+/// enum Number {
+/// Zero,
+/// One,
+/// }
+///
+/// let zero: u8 = Number::Zero.into();
+/// assert_eq!(zero, 0u8);
+/// ```
+#[proc_macro_derive(IntoPrimitive, attributes(num_enum, catch_all))]
+pub fn derive_into_primitive(input: TokenStream) -> TokenStream {
+ let enum_info = parse_macro_input!(input as EnumInfo);
+ let catch_all = enum_info.catch_all();
+ let name = &enum_info.name;
+ let repr = &enum_info.repr;
+
+ let body = if let Some(catch_all_ident) = catch_all {
+ quote! {
+ match enum_value {
+ #name::#catch_all_ident(raw) => raw,
+ rest => unsafe { *(&rest as *const #name as *const Self) }
+ }
+ }
+ } else {
+ quote! { enum_value as Self }
+ };
+
+ TokenStream::from(quote! {
+ impl From<#name> for #repr {
+ #[inline]
+ fn from (enum_value: #name) -> Self
+ {
+ #body
+ }
+ }
+ })
+}
+
+/// Implements `From<Primitive>` for a `#[repr(Primitive)] enum`.
+///
+/// Turning a primitive into an enum with `from`.
+/// ----------------------------------------------
+///
+/// ```rust
+/// use num_enum::FromPrimitive;
+///
+/// #[derive(Debug, Eq, PartialEq, FromPrimitive)]
+/// #[repr(u8)]
+/// enum Number {
+/// Zero,
+/// #[num_enum(default)]
+/// NonZero,
+/// }
+///
+/// let zero = Number::from(0u8);
+/// assert_eq!(zero, Number::Zero);
+///
+/// let one = Number::from(1u8);
+/// assert_eq!(one, Number::NonZero);
+///
+/// let two = Number::from(2u8);
+/// assert_eq!(two, Number::NonZero);
+/// ```
+#[proc_macro_derive(FromPrimitive, attributes(num_enum, default, catch_all))]
+pub fn derive_from_primitive(input: TokenStream) -> TokenStream {
+ let enum_info: EnumInfo = parse_macro_input!(input);
+ let krate = Ident::new(&get_crate_name(), Span::call_site());
+
+ let is_naturally_exhaustive = enum_info.is_naturally_exhaustive();
+ let catch_all_body = match is_naturally_exhaustive {
+ Ok(is_naturally_exhaustive) => {
+ if is_naturally_exhaustive {
+ quote! { unreachable!("exhaustive enum") }
+ } else if let Some(default_ident) = enum_info.default() {
+ quote! { Self::#default_ident }
+ } else if let Some(catch_all_ident) = enum_info.catch_all() {
+ quote! { Self::#catch_all_ident(number) }
+ } else {
+ let span = Span::call_site();
+ let message =
+ "#[derive(num_enum::FromPrimitive)] requires enum to be exhaustive, or a variant marked with `#[default]`, `#[num_enum(default)]`, or `#[num_enum(catch_all)`";
+ return syn::Error::new(span, message).to_compile_error().into();
+ }
+ }
+ Err(err) => {
+ return err.to_compile_error().into();
+ }
+ };
+
+ let EnumInfo {
+ ref name, ref repr, ..
+ } = enum_info;
+
+ let variant_idents: Vec<Ident> = enum_info.variant_idents();
+ let expression_idents: Vec<Vec<Ident>> = enum_info.expression_idents();
+ let variant_expressions: Vec<Vec<Expr>> = enum_info.variant_expressions();
+
+ debug_assert_eq!(variant_idents.len(), variant_expressions.len());
+
+ TokenStream::from(quote! {
+ impl ::#krate::FromPrimitive for #name {
+ type Primitive = #repr;
+
+ fn from_primitive(number: Self::Primitive) -> Self {
+ // Use intermediate const(s) so that enums defined like
+ // `Two = ONE + 1u8` work properly.
+ #![allow(non_upper_case_globals)]
+ #(
+ #(
+ const #expression_idents: #repr = #variant_expressions;
+ )*
+ )*
+ #[deny(unreachable_patterns)]
+ match number {
+ #(
+ #( #expression_idents )|*
+ => Self::#variant_idents,
+ )*
+ #[allow(unreachable_patterns)]
+ _ => #catch_all_body,
+ }
+ }
+ }
+
+ impl ::core::convert::From<#repr> for #name {
+ #[inline]
+ fn from (
+ number: #repr,
+ ) -> Self {
+ ::#krate::FromPrimitive::from_primitive(number)
+ }
+ }
+
+ // The Rust stdlib will implement `#name: From<#repr>` for us for free!
+
+ impl ::#krate::TryFromPrimitive for #name {
+ type Primitive = #repr;
+
+ const NAME: &'static str = stringify!(#name);
+
+ #[inline]
+ fn try_from_primitive (
+ number: Self::Primitive,
+ ) -> ::core::result::Result<
+ Self,
+ ::#krate::TryFromPrimitiveError<Self>,
+ >
+ {
+ Ok(::#krate::FromPrimitive::from_primitive(number))
+ }
+ }
+ })
+}
+
+/// Implements `TryFrom<Primitive>` for a `#[repr(Primitive)] enum`.
+///
+/// Attempting to turn a primitive into an enum with `try_from`.
+/// ----------------------------------------------
+///
+/// ```rust
+/// use num_enum::TryFromPrimitive;
+/// use std::convert::TryFrom;
+///
+/// #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
+/// #[repr(u8)]
+/// enum Number {
+/// Zero,
+/// One,
+/// }
+///
+/// let zero = Number::try_from(0u8);
+/// assert_eq!(zero, Ok(Number::Zero));
+///
+/// let three = Number::try_from(3u8);
+/// assert_eq!(
+/// three.unwrap_err().to_string(),
+/// "No discriminant in enum `Number` matches the value `3`",
+/// );
+/// ```
+#[proc_macro_derive(TryFromPrimitive, attributes(num_enum))]
+pub fn derive_try_from_primitive(input: TokenStream) -> TokenStream {
+ let enum_info: EnumInfo = parse_macro_input!(input);
+ let krate = Ident::new(&get_crate_name(), Span::call_site());
+
+ let EnumInfo {
+ ref name, ref repr, ..
+ } = enum_info;
+
+ let variant_idents: Vec<Ident> = enum_info.variant_idents();
+ let expression_idents: Vec<Vec<Ident>> = enum_info.expression_idents();
+ let variant_expressions: Vec<Vec<Expr>> = enum_info.variant_expressions();
+
+ debug_assert_eq!(variant_idents.len(), variant_expressions.len());
+
+ let default_arm = match enum_info.default() {
+ Some(ident) => {
+ quote! {
+ _ => ::core::result::Result::Ok(
+ #name::#ident
+ )
+ }
+ }
+ None => {
+ quote! {
+ _ => ::core::result::Result::Err(
+ ::#krate::TryFromPrimitiveError { number }
+ )
+ }
+ }
+ };
+
+ TokenStream::from(quote! {
+ impl ::#krate::TryFromPrimitive for #name {
+ type Primitive = #repr;
+
+ const NAME: &'static str = stringify!(#name);
+
+ fn try_from_primitive (
+ number: Self::Primitive,
+ ) -> ::core::result::Result<
+ Self,
+ ::#krate::TryFromPrimitiveError<Self>
+ > {
+ // Use intermediate const(s) so that enums defined like
+ // `Two = ONE + 1u8` work properly.
+ #![allow(non_upper_case_globals)]
+ #(
+ #(
+ const #expression_idents: #repr = #variant_expressions;
+ )*
+ )*
+ #[deny(unreachable_patterns)]
+ match number {
+ #(
+ #( #expression_idents )|*
+ => ::core::result::Result::Ok(Self::#variant_idents),
+ )*
+ #[allow(unreachable_patterns)]
+ #default_arm,
+ }
+ }
+ }
+
+ impl ::core::convert::TryFrom<#repr> for #name {
+ type Error = ::#krate::TryFromPrimitiveError<Self>;
+
+ #[inline]
+ fn try_from (
+ number: #repr,
+ ) -> ::core::result::Result<Self, ::#krate::TryFromPrimitiveError<Self>>
+ {
+ ::#krate::TryFromPrimitive::try_from_primitive(number)
+ }
+ }
+ })
+}
+
+#[cfg(feature = "proc-macro-crate")]
+fn get_crate_name() -> String {
+ let found_crate = proc_macro_crate::crate_name("num_enum").unwrap_or_else(|err| {
+ eprintln!("Warning: {}\n => defaulting to `num_enum`", err,);
+ proc_macro_crate::FoundCrate::Itself
+ });
+
+ match found_crate {
+ proc_macro_crate::FoundCrate::Itself => String::from("num_enum"),
+ proc_macro_crate::FoundCrate::Name(name) => name,
+ }
+}
+
+// Don't depend on proc-macro-crate in no_std environments because it causes an awkward dependency
+// on serde with std.
+//
+// no_std dependees on num_enum cannot rename the num_enum crate when they depend on it. Sorry.
+//
+// See https://github.com/illicitonion/num_enum/issues/18
+#[cfg(not(feature = "proc-macro-crate"))]
+fn get_crate_name() -> String {
+ String::from("num_enum")
+}
+
+/// Generates a `unsafe fn from_unchecked (number: Primitive) -> Self`
+/// associated function.
+///
+/// Allows unsafely turning a primitive into an enum with from_unchecked.
+/// -------------------------------------------------------------
+///
+/// If you're really certain a conversion will succeed, and want to avoid a small amount of overhead, you can use unsafe
+/// code to do this conversion. Unless you have data showing that the match statement generated in the `try_from` above is a
+/// bottleneck for you, you should avoid doing this, as the unsafe code has potential to cause serious memory issues in
+/// your program.
+///
+/// ```rust
+/// use num_enum::UnsafeFromPrimitive;
+///
+/// #[derive(Debug, Eq, PartialEq, UnsafeFromPrimitive)]
+/// #[repr(u8)]
+/// enum Number {
+/// Zero,
+/// One,
+/// }
+///
+/// fn main() {
+/// assert_eq!(
+/// Number::Zero,
+/// unsafe { Number::from_unchecked(0_u8) },
+/// );
+/// assert_eq!(
+/// Number::One,
+/// unsafe { Number::from_unchecked(1_u8) },
+/// );
+/// }
+///
+/// unsafe fn undefined_behavior() {
+/// let _ = Number::from_unchecked(2); // 2 is not a valid discriminant!
+/// }
+/// ```
+#[proc_macro_derive(UnsafeFromPrimitive, attributes(num_enum))]
+pub fn derive_unsafe_from_primitive(stream: TokenStream) -> TokenStream {
+ let enum_info = parse_macro_input!(stream as EnumInfo);
+
+ if enum_info.has_default_variant() {
+ let span = enum_info
+ .first_default_attr_span()
+ .cloned()
+ .expect("Expected span");
+ let message = "#[derive(UnsafeFromPrimitive)] does not support `#[num_enum(default)]`";
+ return syn::Error::new(span, message).to_compile_error().into();
+ }
+
+ if enum_info.has_complex_variant() {
+ let span = enum_info
+ .first_alternatives_attr_span()
+ .cloned()
+ .expect("Expected span");
+ let message =
+ "#[derive(UnsafeFromPrimitive)] does not support `#[num_enum(alternatives = [..])]`";
+ return syn::Error::new(span, message).to_compile_error().into();
+ }
+
+ let EnumInfo {
+ ref name, ref repr, ..
+ } = enum_info;
+
+ let doc_string = LitStr::new(
+ &format!(
+ r#"
+Transmutes `number: {repr}` into a [`{name}`].
+
+# Safety
+
+ - `number` must represent a valid discriminant of [`{name}`]
+"#,
+ repr = repr,
+ name = name,
+ ),
+ Span::call_site(),
+ );
+
+ TokenStream::from(quote! {
+ impl #name {
+ #[doc = #doc_string]
+ #[inline]
+ pub unsafe fn from_unchecked(number: #repr) -> Self {
+ ::core::mem::transmute(number)
+ }
+ }
+ })
+}
+
+/// Implements `core::default::Default` for a `#[repr(Primitive)] enum`.
+///
+/// Whichever variant has the `#[default]` or `#[num_enum(default)]` attribute will be returned.
+/// ----------------------------------------------
+///
+/// ```rust
+/// #[derive(Debug, Eq, PartialEq, num_enum::Default)]
+/// #[repr(u8)]
+/// enum Number {
+/// Zero,
+/// #[default]
+/// One,
+/// }
+///
+/// assert_eq!(Number::One, Number::default());
+/// assert_eq!(Number::One, <Number as ::core::default::Default>::default());
+/// ```
+#[proc_macro_derive(Default, attributes(num_enum, default))]
+pub fn derive_default(stream: TokenStream) -> TokenStream {
+ let enum_info = parse_macro_input!(stream as EnumInfo);
+
+ let default_ident = match enum_info.default() {
+ Some(ident) => ident,
+ None => {
+ let span = Span::call_site();
+ let message =
+ "#[derive(num_enum::Default)] requires enum to be exhaustive, or a variant marked with `#[default]` or `#[num_enum(default)]`";
+ return syn::Error::new(span, message).to_compile_error().into();
+ }
+ };
+
+ let EnumInfo { ref name, .. } = enum_info;
+
+ TokenStream::from(quote! {
+ impl ::core::default::Default for #name {
+ #[inline]
+ fn default() -> Self {
+ Self::#default_ident
+ }
+ }
+ })
+}