1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
//! Assorted helper functions used throughout the code. /// Interconvert between external and internal representation. /// We can freely do this within this crate, but must not allow /// our clients to do this. pub(crate) trait Protected<T> { fn build(inner: T) -> Self; fn inner(&self) -> T; } /// Enhance a nullary enum as follows: /// /// * `Display` / `to_string` /// * `FromStr` / `parse` (with just a simple `String` as error type) /// * Interconvert with another type (via `Protected`). /// * `variants` yields an array of all variants. /// /// Only works for nullary enums, i.e., ones where no variants have any arguments. /// /// # Syntax /// /// ```ignore /// enhance_nullary_enum(ThisEnum, ThatEnum, { /// (ThisVariant1, ThatVariant1, "StringName1"), /// (ThisVariant2, ThatVariant2, "StringName2"), /// ... /// }, omit { ThatVariantOmit1, ThatVariantOmit2 }); /// ``` /// where /// /// * `ThisEnum` is the name of the type being enhanced. /// * `ThatEnum` is the name of the inner type wrapped by `ThisEnum`. /// * Then all variants of `ThisEnum` are listed: /// * `ThisVariant`i is the name of the variant. /// * `ThatVariant`i is the name of the corresponding variant of `ThatEnum`. /// * `StringName`i is the desired string representation of the enum for parsing and printing. /// * The `omit` section is optional; any variants of `ThatEnum` listed here /// cause `Protected::build` to panic. /// // We attempted to use the `macro-attr` crate to achieve this more naturally, but sadly // identifier-concatenation functionality is not yet available in stable Rust // per https://github.com/rust-lang/rust/issues/29599. We really don't want to use the verbose // identifiers (e.g., `CASS_CONSISTENCY_ANY`), so without concatenation we are forced to // provide an explicit list of identifiers. However with `macro-attr` there's nowhere to // hang them; we can't add them in a custom attribute because custom attributes are unstable. // In the end the best approach is just the direct one, as exemplified here. macro_rules! enhance_nullary_enum { ( $this_name:ident, $that_name: ident, { $( ($this:ident, $that:ident, $name:expr), )* } $( , omit { $( $not_that:ident ),* } )* ) => { impl ::std::fmt::Display for $this_name { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> { write!(f, "{}", match *self { $( $this_name::$this => $name, )* }) } } impl ::std::str::FromStr for $this_name { type Err = String; fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> { match s { $( $name => Ok($this_name::$this), )* _ => Err(format!("Unrecognized {}: {}", stringify!($this_name), s)), } } } impl $crate::cassandra::util::Protected<$that_name> for $this_name { fn build(inner: $that_name) -> Self { match inner { $( $that_name::$that => $this_name::$this, )* $($( $that_name::$not_that => panic!(stringify!(Unexpected variant $that_name::$not_that)), )*)* } } fn inner(&self) -> $that_name { match *self { $( $this_name::$this => $that_name::$that ),* } } } impl $this_name { /// List all the possible values of this enumeration. pub fn variants() -> &'static [$this_name] { // Nasty trick to calculate the length of the iteration - we must mention // a variable inside the layer, even though we never actually use it. static VARIANTS: [ $this_name; 0 $( + ($this_name::$this, 1).1 )* ] = [ $( $this_name::$this ),* ]; &VARIANTS } } }; }