diff options
Diffstat (limited to 'rust/vendor/num_enum/README.md')
-rw-r--r-- | rust/vendor/num_enum/README.md | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/rust/vendor/num_enum/README.md b/rust/vendor/num_enum/README.md new file mode 100644 index 0000000..902cee7 --- /dev/null +++ b/rust/vendor/num_enum/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. |