summaryrefslogtreecommitdiffstats
path: root/vendor/strum_macros/src
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/strum_macros/src')
-rw-r--r--vendor/strum_macros/src/helpers/case_style.rs117
-rw-r--r--vendor/strum_macros/src/helpers/metadata.rs309
-rw-r--r--vendor/strum_macros/src/helpers/mod.rs32
-rw-r--r--vendor/strum_macros/src/helpers/type_props.rs116
-rw-r--r--vendor/strum_macros/src/helpers/variant_props.rs133
-rw-r--r--vendor/strum_macros/src/lib.rs755
-rw-r--r--vendor/strum_macros/src/macros/enum_count.rs27
-rw-r--r--vendor/strum_macros/src/macros/enum_discriminants.rs162
-rw-r--r--vendor/strum_macros/src/macros/enum_iter.rs158
-rw-r--r--vendor/strum_macros/src/macros/enum_messages.rs138
-rw-r--r--vendor/strum_macros/src/macros/enum_properties.rs65
-rw-r--r--vendor/strum_macros/src/macros/enum_variant_names.rs34
-rw-r--r--vendor/strum_macros/src/macros/from_repr.rs139
-rw-r--r--vendor/strum_macros/src/macros/mod.rs14
-rw-r--r--vendor/strum_macros/src/macros/strings/as_ref_str.rs117
-rw-r--r--vendor/strum_macros/src/macros/strings/display.rs51
-rw-r--r--vendor/strum_macros/src/macros/strings/from_string.rs180
-rw-r--r--vendor/strum_macros/src/macros/strings/mod.rs4
-rw-r--r--vendor/strum_macros/src/macros/strings/to_string.rs51
19 files changed, 2602 insertions, 0 deletions
diff --git a/vendor/strum_macros/src/helpers/case_style.rs b/vendor/strum_macros/src/helpers/case_style.rs
new file mode 100644
index 000000000..425382606
--- /dev/null
+++ b/vendor/strum_macros/src/helpers/case_style.rs
@@ -0,0 +1,117 @@
+use heck::{
+ ToKebabCase, ToLowerCamelCase, ToShoutySnakeCase, ToSnakeCase, ToTitleCase, ToUpperCamelCase,
+};
+use std::str::FromStr;
+use syn::{
+ parse::{Parse, ParseStream},
+ Ident, LitStr,
+};
+
+#[allow(clippy::enum_variant_names)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum CaseStyle {
+ CamelCase,
+ KebabCase,
+ MixedCase,
+ ShoutySnakeCase,
+ SnakeCase,
+ TitleCase,
+ UpperCase,
+ LowerCase,
+ ScreamingKebabCase,
+ PascalCase,
+}
+
+const VALID_CASE_STYLES: &[&str] = &[
+ "camelCase",
+ "PascalCase",
+ "kebab-case",
+ "snake_case",
+ "SCREAMING_SNAKE_CASE",
+ "SCREAMING-KEBAB-CASE",
+ "lowercase",
+ "UPPERCASE",
+ "title_case",
+ "mixed_case",
+];
+
+impl Parse for CaseStyle {
+ fn parse(input: ParseStream) -> syn::Result<Self> {
+ let text = input.parse::<LitStr>()?;
+ let val = text.value();
+
+ val.as_str().parse().map_err(|_| {
+ syn::Error::new_spanned(
+ &text,
+ format!(
+ "Unexpected case style for serialize_all: `{}`. Valid values are: `{:?}`",
+ val, VALID_CASE_STYLES
+ ),
+ )
+ })
+ }
+}
+
+impl FromStr for CaseStyle {
+ type Err = ();
+
+ fn from_str(text: &str) -> Result<Self, ()> {
+ Ok(match text {
+ "camel_case" | "PascalCase" => CaseStyle::PascalCase,
+ "camelCase" => CaseStyle::CamelCase,
+ "snake_case" | "snek_case" => CaseStyle::SnakeCase,
+ "kebab_case" | "kebab-case" => CaseStyle::KebabCase,
+ "SCREAMING-KEBAB-CASE" => CaseStyle::ScreamingKebabCase,
+ "shouty_snake_case" | "shouty_snek_case" | "SCREAMING_SNAKE_CASE" => {
+ CaseStyle::ShoutySnakeCase
+ }
+ "title_case" => CaseStyle::TitleCase,
+ "mixed_case" => CaseStyle::MixedCase,
+ "lowercase" => CaseStyle::LowerCase,
+ "UPPERCASE" => CaseStyle::UpperCase,
+ _ => return Err(()),
+ })
+ }
+}
+
+pub trait CaseStyleHelpers {
+ fn convert_case(&self, case_style: Option<CaseStyle>) -> String;
+}
+
+impl CaseStyleHelpers for Ident {
+ fn convert_case(&self, case_style: Option<CaseStyle>) -> String {
+ let ident_string = self.to_string();
+ if let Some(case_style) = case_style {
+ match case_style {
+ CaseStyle::PascalCase => ident_string.to_upper_camel_case(),
+ CaseStyle::KebabCase => ident_string.to_kebab_case(),
+ CaseStyle::MixedCase => ident_string.to_lower_camel_case(),
+ CaseStyle::ShoutySnakeCase => ident_string.to_shouty_snake_case(),
+ CaseStyle::SnakeCase => ident_string.to_snake_case(),
+ CaseStyle::TitleCase => ident_string.to_title_case(),
+ CaseStyle::UpperCase => ident_string.to_uppercase(),
+ CaseStyle::LowerCase => ident_string.to_lowercase(),
+ CaseStyle::ScreamingKebabCase => ident_string.to_kebab_case().to_uppercase(),
+ CaseStyle::CamelCase => {
+ let camel_case = ident_string.to_upper_camel_case();
+ let mut pascal = String::with_capacity(camel_case.len());
+ let mut it = camel_case.chars();
+ if let Some(ch) = it.next() {
+ pascal.extend(ch.to_lowercase());
+ }
+ pascal.extend(it);
+ pascal
+ }
+ }
+ } else {
+ ident_string
+ }
+ }
+}
+
+#[test]
+fn test_convert_case() {
+ let id = Ident::new("test_me", proc_macro2::Span::call_site());
+ assert_eq!("testMe", id.convert_case(Some(CaseStyle::CamelCase)));
+ assert_eq!("TestMe", id.convert_case(Some(CaseStyle::PascalCase)));
+}
diff --git a/vendor/strum_macros/src/helpers/metadata.rs b/vendor/strum_macros/src/helpers/metadata.rs
new file mode 100644
index 000000000..56e4c78bd
--- /dev/null
+++ b/vendor/strum_macros/src/helpers/metadata.rs
@@ -0,0 +1,309 @@
+use proc_macro2::{Span, TokenStream};
+use syn::{
+ parenthesized,
+ parse::{Parse, ParseStream},
+ parse2, parse_str,
+ punctuated::Punctuated,
+ spanned::Spanned,
+ Attribute, DeriveInput, Ident, Lit, LitBool, LitStr, Meta, MetaNameValue, Path, Token, Variant,
+ Visibility,
+};
+
+use super::case_style::CaseStyle;
+
+pub mod kw {
+ use syn::custom_keyword;
+ pub use syn::token::Crate;
+
+ // enum metadata
+ custom_keyword!(serialize_all);
+ custom_keyword!(use_phf);
+
+ // enum discriminant metadata
+ custom_keyword!(derive);
+ custom_keyword!(name);
+ custom_keyword!(vis);
+
+ // variant metadata
+ custom_keyword!(message);
+ custom_keyword!(detailed_message);
+ custom_keyword!(serialize);
+ custom_keyword!(to_string);
+ custom_keyword!(disabled);
+ custom_keyword!(default);
+ custom_keyword!(props);
+ custom_keyword!(ascii_case_insensitive);
+}
+
+pub enum EnumMeta {
+ SerializeAll {
+ kw: kw::serialize_all,
+ case_style: CaseStyle,
+ },
+ AsciiCaseInsensitive(kw::ascii_case_insensitive),
+ Crate {
+ kw: kw::Crate,
+ crate_module_path: Path,
+ },
+ UsePhf(kw::use_phf),
+}
+
+impl Parse for EnumMeta {
+ fn parse(input: ParseStream) -> syn::Result<Self> {
+ let lookahead = input.lookahead1();
+ if lookahead.peek(kw::serialize_all) {
+ let kw = input.parse::<kw::serialize_all>()?;
+ input.parse::<Token![=]>()?;
+ let case_style = input.parse()?;
+ Ok(EnumMeta::SerializeAll { kw, case_style })
+ } else if lookahead.peek(kw::Crate) {
+ let kw = input.parse::<kw::Crate>()?;
+ input.parse::<Token![=]>()?;
+ let path_str: LitStr = input.parse()?;
+ let path_tokens = parse_str(&path_str.value())?;
+ let crate_module_path = parse2(path_tokens)?;
+ Ok(EnumMeta::Crate {
+ kw,
+ crate_module_path,
+ })
+ } else if lookahead.peek(kw::ascii_case_insensitive) {
+ Ok(EnumMeta::AsciiCaseInsensitive(input.parse()?))
+ } else if lookahead.peek(kw::use_phf) {
+ Ok(EnumMeta::UsePhf(input.parse()?))
+ } else {
+ Err(lookahead.error())
+ }
+ }
+}
+
+impl Spanned for EnumMeta {
+ fn span(&self) -> Span {
+ match self {
+ EnumMeta::SerializeAll { kw, .. } => kw.span(),
+ EnumMeta::AsciiCaseInsensitive(kw) => kw.span(),
+ EnumMeta::Crate { kw, .. } => kw.span(),
+ EnumMeta::UsePhf(use_phf) => use_phf.span(),
+ }
+ }
+}
+
+pub enum EnumDiscriminantsMeta {
+ Derive { kw: kw::derive, paths: Vec<Path> },
+ Name { kw: kw::name, name: Ident },
+ Vis { kw: kw::vis, vis: Visibility },
+ Other { path: Path, nested: TokenStream },
+}
+
+impl Parse for EnumDiscriminantsMeta {
+ fn parse(input: ParseStream) -> syn::Result<Self> {
+ if input.peek(kw::derive) {
+ let kw = input.parse()?;
+ let content;
+ parenthesized!(content in input);
+ let paths = content.parse_terminated::<_, Token![,]>(Path::parse)?;
+ Ok(EnumDiscriminantsMeta::Derive {
+ kw,
+ paths: paths.into_iter().collect(),
+ })
+ } else if input.peek(kw::name) {
+ let kw = input.parse()?;
+ let content;
+ parenthesized!(content in input);
+ let name = content.parse()?;
+ Ok(EnumDiscriminantsMeta::Name { kw, name })
+ } else if input.peek(kw::vis) {
+ let kw = input.parse()?;
+ let content;
+ parenthesized!(content in input);
+ let vis = content.parse()?;
+ Ok(EnumDiscriminantsMeta::Vis { kw, vis })
+ } else {
+ let path = input.parse()?;
+ let content;
+ parenthesized!(content in input);
+ let nested = content.parse()?;
+ Ok(EnumDiscriminantsMeta::Other { path, nested })
+ }
+ }
+}
+
+impl Spanned for EnumDiscriminantsMeta {
+ fn span(&self) -> Span {
+ match self {
+ EnumDiscriminantsMeta::Derive { kw, .. } => kw.span,
+ EnumDiscriminantsMeta::Name { kw, .. } => kw.span,
+ EnumDiscriminantsMeta::Vis { kw, .. } => kw.span,
+ EnumDiscriminantsMeta::Other { path, .. } => path.span(),
+ }
+ }
+}
+
+pub trait DeriveInputExt {
+ /// Get all the strum metadata associated with an enum.
+ fn get_metadata(&self) -> syn::Result<Vec<EnumMeta>>;
+
+ /// Get all the `strum_discriminants` metadata associated with an enum.
+ fn get_discriminants_metadata(&self) -> syn::Result<Vec<EnumDiscriminantsMeta>>;
+}
+
+impl DeriveInputExt for DeriveInput {
+ fn get_metadata(&self) -> syn::Result<Vec<EnumMeta>> {
+ get_metadata_inner("strum", &self.attrs)
+ }
+
+ fn get_discriminants_metadata(&self) -> syn::Result<Vec<EnumDiscriminantsMeta>> {
+ get_metadata_inner("strum_discriminants", &self.attrs)
+ }
+}
+
+pub enum VariantMeta {
+ Message {
+ kw: kw::message,
+ value: LitStr,
+ },
+ DetailedMessage {
+ kw: kw::detailed_message,
+ value: LitStr,
+ },
+ Serialize {
+ kw: kw::serialize,
+ value: LitStr,
+ },
+ Documentation {
+ value: LitStr,
+ },
+ ToString {
+ kw: kw::to_string,
+ value: LitStr,
+ },
+ Disabled(kw::disabled),
+ Default(kw::default),
+ AsciiCaseInsensitive {
+ kw: kw::ascii_case_insensitive,
+ value: bool,
+ },
+ Props {
+ kw: kw::props,
+ props: Vec<(LitStr, LitStr)>,
+ },
+}
+
+impl Parse for VariantMeta {
+ fn parse(input: ParseStream) -> syn::Result<Self> {
+ let lookahead = input.lookahead1();
+ if lookahead.peek(kw::message) {
+ let kw = input.parse()?;
+ let _: Token![=] = input.parse()?;
+ let value = input.parse()?;
+ Ok(VariantMeta::Message { kw, value })
+ } else if lookahead.peek(kw::detailed_message) {
+ let kw = input.parse()?;
+ let _: Token![=] = input.parse()?;
+ let value = input.parse()?;
+ Ok(VariantMeta::DetailedMessage { kw, value })
+ } else if lookahead.peek(kw::serialize) {
+ let kw = input.parse()?;
+ let _: Token![=] = input.parse()?;
+ let value = input.parse()?;
+ Ok(VariantMeta::Serialize { kw, value })
+ } else if lookahead.peek(kw::to_string) {
+ let kw = input.parse()?;
+ let _: Token![=] = input.parse()?;
+ let value = input.parse()?;
+ Ok(VariantMeta::ToString { kw, value })
+ } else if lookahead.peek(kw::disabled) {
+ Ok(VariantMeta::Disabled(input.parse()?))
+ } else if lookahead.peek(kw::default) {
+ Ok(VariantMeta::Default(input.parse()?))
+ } else if lookahead.peek(kw::ascii_case_insensitive) {
+ let kw = input.parse()?;
+ let value = if input.peek(Token![=]) {
+ let _: Token![=] = input.parse()?;
+ input.parse::<LitBool>()?.value
+ } else {
+ true
+ };
+ Ok(VariantMeta::AsciiCaseInsensitive { kw, value })
+ } else if lookahead.peek(kw::props) {
+ let kw = input.parse()?;
+ let content;
+ parenthesized!(content in input);
+ let props = content.parse_terminated::<_, Token![,]>(Prop::parse)?;
+ Ok(VariantMeta::Props {
+ kw,
+ props: props
+ .into_iter()
+ .map(|Prop(k, v)| (LitStr::new(&k.to_string(), k.span()), v))
+ .collect(),
+ })
+ } else {
+ Err(lookahead.error())
+ }
+ }
+}
+
+struct Prop(Ident, LitStr);
+
+impl Parse for Prop {
+ fn parse(input: ParseStream) -> syn::Result<Self> {
+ use syn::ext::IdentExt;
+
+ let k = Ident::parse_any(input)?;
+ let _: Token![=] = input.parse()?;
+ let v = input.parse()?;
+
+ Ok(Prop(k, v))
+ }
+}
+
+impl Spanned for VariantMeta {
+ fn span(&self) -> Span {
+ match self {
+ VariantMeta::Message { kw, .. } => kw.span,
+ VariantMeta::DetailedMessage { kw, .. } => kw.span,
+ VariantMeta::Documentation { value } => value.span(),
+ VariantMeta::Serialize { kw, .. } => kw.span,
+ VariantMeta::ToString { kw, .. } => kw.span,
+ VariantMeta::Disabled(kw) => kw.span,
+ VariantMeta::Default(kw) => kw.span,
+ VariantMeta::AsciiCaseInsensitive { kw, .. } => kw.span,
+ VariantMeta::Props { kw, .. } => kw.span,
+ }
+ }
+}
+
+pub trait VariantExt {
+ /// Get all the metadata associated with an enum variant.
+ fn get_metadata(&self) -> syn::Result<Vec<VariantMeta>>;
+}
+
+impl VariantExt for Variant {
+ fn get_metadata(&self) -> syn::Result<Vec<VariantMeta>> {
+ let result = get_metadata_inner("strum", &self.attrs)?;
+ self.attrs
+ .iter()
+ .filter(|attr| attr.path.is_ident("doc"))
+ .try_fold(result, |mut vec, attr| {
+ if let Meta::NameValue(MetaNameValue {
+ lit: Lit::Str(value),
+ ..
+ }) = attr.parse_meta()?
+ {
+ vec.push(VariantMeta::Documentation { value })
+ }
+ Ok(vec)
+ })
+ }
+}
+
+fn get_metadata_inner<'a, T: Parse + Spanned>(
+ ident: &str,
+ it: impl IntoIterator<Item = &'a Attribute>,
+) -> syn::Result<Vec<T>> {
+ it.into_iter()
+ .filter(|attr| attr.path.is_ident(ident))
+ .try_fold(Vec::new(), |mut vec, attr| {
+ vec.extend(attr.parse_args_with(Punctuated::<T, Token![,]>::parse_terminated)?);
+ Ok(vec)
+ })
+}
diff --git a/vendor/strum_macros/src/helpers/mod.rs b/vendor/strum_macros/src/helpers/mod.rs
new file mode 100644
index 000000000..11aebc835
--- /dev/null
+++ b/vendor/strum_macros/src/helpers/mod.rs
@@ -0,0 +1,32 @@
+pub use self::case_style::CaseStyleHelpers;
+pub use self::type_props::HasTypeProperties;
+pub use self::variant_props::HasStrumVariantProperties;
+
+pub mod case_style;
+mod metadata;
+pub mod type_props;
+pub mod variant_props;
+
+use proc_macro2::Span;
+use quote::ToTokens;
+use syn::spanned::Spanned;
+
+pub fn non_enum_error() -> syn::Error {
+ syn::Error::new(Span::call_site(), "This macro only supports enums.")
+}
+
+pub fn strum_discriminants_passthrough_error(span: &impl Spanned) -> syn::Error {
+ syn::Error::new(
+ span.span(),
+ "expected a pass-through attribute, e.g. #[strum_discriminants(serde(rename = \"var0\"))]",
+ )
+}
+
+pub fn occurrence_error<T: ToTokens>(fst: T, snd: T, attr: &str) -> syn::Error {
+ let mut e = syn::Error::new_spanned(
+ snd,
+ format!("Found multiple occurrences of strum({})", attr),
+ );
+ e.combine(syn::Error::new_spanned(fst, "first one here"));
+ e
+}
diff --git a/vendor/strum_macros/src/helpers/type_props.rs b/vendor/strum_macros/src/helpers/type_props.rs
new file mode 100644
index 000000000..0d49e04eb
--- /dev/null
+++ b/vendor/strum_macros/src/helpers/type_props.rs
@@ -0,0 +1,116 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+use std::default::Default;
+use syn::{parse_quote, DeriveInput, Ident, Path, Visibility};
+
+use super::case_style::CaseStyle;
+use super::metadata::{DeriveInputExt, EnumDiscriminantsMeta, EnumMeta};
+use super::occurrence_error;
+
+pub trait HasTypeProperties {
+ fn get_type_properties(&self) -> syn::Result<StrumTypeProperties>;
+}
+
+#[derive(Debug, Clone, Default)]
+pub struct StrumTypeProperties {
+ pub case_style: Option<CaseStyle>,
+ pub ascii_case_insensitive: bool,
+ pub crate_module_path: Option<Path>,
+ pub discriminant_derives: Vec<Path>,
+ pub discriminant_name: Option<Ident>,
+ pub discriminant_others: Vec<TokenStream>,
+ pub discriminant_vis: Option<Visibility>,
+ pub use_phf: bool,
+}
+
+impl HasTypeProperties for DeriveInput {
+ fn get_type_properties(&self) -> syn::Result<StrumTypeProperties> {
+ let mut output = StrumTypeProperties::default();
+
+ let strum_meta = self.get_metadata()?;
+ let discriminants_meta = self.get_discriminants_metadata()?;
+
+ let mut serialize_all_kw = None;
+ let mut ascii_case_insensitive_kw = None;
+ let mut use_phf_kw = None;
+ let mut crate_module_path_kw = None;
+ for meta in strum_meta {
+ match meta {
+ EnumMeta::SerializeAll { case_style, kw } => {
+ if let Some(fst_kw) = serialize_all_kw {
+ return Err(occurrence_error(fst_kw, kw, "serialize_all"));
+ }
+
+ serialize_all_kw = Some(kw);
+ output.case_style = Some(case_style);
+ }
+ EnumMeta::AsciiCaseInsensitive(kw) => {
+ if let Some(fst_kw) = ascii_case_insensitive_kw {
+ return Err(occurrence_error(fst_kw, kw, "ascii_case_insensitive"));
+ }
+
+ ascii_case_insensitive_kw = Some(kw);
+ output.ascii_case_insensitive = true;
+ }
+ EnumMeta::UsePhf(kw) => {
+ if let Some(fst_kw) = use_phf_kw {
+ return Err(occurrence_error(fst_kw, kw, "use_phf"));
+ }
+
+ use_phf_kw = Some(kw);
+ output.use_phf = true;
+ }
+ EnumMeta::Crate {
+ crate_module_path,
+ kw,
+ } => {
+ if let Some(fst_kw) = crate_module_path_kw {
+ return Err(occurrence_error(fst_kw, kw, "Crate"));
+ }
+
+ crate_module_path_kw = Some(kw);
+ output.crate_module_path = Some(crate_module_path);
+ }
+ }
+ }
+
+ let mut name_kw = None;
+ let mut vis_kw = None;
+ for meta in discriminants_meta {
+ match meta {
+ EnumDiscriminantsMeta::Derive { paths, .. } => {
+ output.discriminant_derives.extend(paths);
+ }
+ EnumDiscriminantsMeta::Name { name, kw } => {
+ if let Some(fst_kw) = name_kw {
+ return Err(occurrence_error(fst_kw, kw, "name"));
+ }
+
+ name_kw = Some(kw);
+ output.discriminant_name = Some(name);
+ }
+ EnumDiscriminantsMeta::Vis { vis, kw } => {
+ if let Some(fst_kw) = vis_kw {
+ return Err(occurrence_error(fst_kw, kw, "vis"));
+ }
+
+ vis_kw = Some(kw);
+ output.discriminant_vis = Some(vis);
+ }
+ EnumDiscriminantsMeta::Other { path, nested } => {
+ output.discriminant_others.push(quote! { #path(#nested) });
+ }
+ }
+ }
+
+ Ok(output)
+ }
+}
+
+impl StrumTypeProperties {
+ pub fn crate_module_path(&self) -> Path {
+ self.crate_module_path
+ .as_ref()
+ .map_or_else(|| parse_quote!(::strum), |path| parse_quote!(#path))
+ }
+}
diff --git a/vendor/strum_macros/src/helpers/variant_props.rs b/vendor/strum_macros/src/helpers/variant_props.rs
new file mode 100644
index 000000000..a39d3ea17
--- /dev/null
+++ b/vendor/strum_macros/src/helpers/variant_props.rs
@@ -0,0 +1,133 @@
+use std::default::Default;
+use syn::{Ident, LitStr, Variant};
+
+use super::case_style::{CaseStyle, CaseStyleHelpers};
+use super::metadata::{kw, VariantExt, VariantMeta};
+use super::occurrence_error;
+
+pub trait HasStrumVariantProperties {
+ fn get_variant_properties(&self) -> syn::Result<StrumVariantProperties>;
+}
+
+#[derive(Clone, Eq, PartialEq, Debug, Default)]
+pub struct StrumVariantProperties {
+ pub disabled: Option<kw::disabled>,
+ pub default: Option<kw::default>,
+ pub ascii_case_insensitive: Option<bool>,
+ pub message: Option<LitStr>,
+ pub detailed_message: Option<LitStr>,
+ pub documentation: Vec<LitStr>,
+ pub string_props: Vec<(LitStr, LitStr)>,
+ serialize: Vec<LitStr>,
+ to_string: Option<LitStr>,
+ ident: Option<Ident>,
+}
+
+impl StrumVariantProperties {
+ fn ident_as_str(&self, case_style: Option<CaseStyle>) -> LitStr {
+ let ident = self.ident.as_ref().expect("identifier");
+ LitStr::new(&ident.convert_case(case_style), ident.span())
+ }
+
+ pub fn get_preferred_name(&self, case_style: Option<CaseStyle>) -> LitStr {
+ self.to_string.as_ref().cloned().unwrap_or_else(|| {
+ self.serialize
+ .iter()
+ .max_by_key(|s| s.value().len())
+ .cloned()
+ .unwrap_or_else(|| self.ident_as_str(case_style))
+ })
+ }
+
+ pub fn get_serializations(&self, case_style: Option<CaseStyle>) -> Vec<LitStr> {
+ let mut attrs = self.serialize.clone();
+ if let Some(to_string) = &self.to_string {
+ attrs.push(to_string.clone());
+ }
+
+ if attrs.is_empty() {
+ attrs.push(self.ident_as_str(case_style));
+ }
+
+ attrs
+ }
+}
+
+impl HasStrumVariantProperties for Variant {
+ fn get_variant_properties(&self) -> syn::Result<StrumVariantProperties> {
+ let mut output = StrumVariantProperties {
+ ident: Some(self.ident.clone()),
+ ..Default::default()
+ };
+
+ let mut message_kw = None;
+ let mut detailed_message_kw = None;
+ let mut to_string_kw = None;
+ let mut disabled_kw = None;
+ let mut default_kw = None;
+ let mut ascii_case_insensitive_kw = None;
+ for meta in self.get_metadata()? {
+ match meta {
+ VariantMeta::Message { value, kw } => {
+ if let Some(fst_kw) = message_kw {
+ return Err(occurrence_error(fst_kw, kw, "message"));
+ }
+
+ message_kw = Some(kw);
+ output.message = Some(value);
+ }
+ VariantMeta::DetailedMessage { value, kw } => {
+ if let Some(fst_kw) = detailed_message_kw {
+ return Err(occurrence_error(fst_kw, kw, "detailed_message"));
+ }
+
+ detailed_message_kw = Some(kw);
+ output.detailed_message = Some(value);
+ }
+ VariantMeta::Documentation { value } => {
+ output.documentation.push(value);
+ }
+ VariantMeta::Serialize { value, .. } => {
+ output.serialize.push(value);
+ }
+ VariantMeta::ToString { value, kw } => {
+ if let Some(fst_kw) = to_string_kw {
+ return Err(occurrence_error(fst_kw, kw, "to_string"));
+ }
+
+ to_string_kw = Some(kw);
+ output.to_string = Some(value);
+ }
+ VariantMeta::Disabled(kw) => {
+ if let Some(fst_kw) = disabled_kw {
+ return Err(occurrence_error(fst_kw, kw, "disabled"));
+ }
+
+ disabled_kw = Some(kw);
+ output.disabled = Some(kw);
+ }
+ VariantMeta::Default(kw) => {
+ if let Some(fst_kw) = default_kw {
+ return Err(occurrence_error(fst_kw, kw, "default"));
+ }
+
+ default_kw = Some(kw);
+ output.default = Some(kw);
+ }
+ VariantMeta::AsciiCaseInsensitive { kw, value } => {
+ if let Some(fst_kw) = ascii_case_insensitive_kw {
+ return Err(occurrence_error(fst_kw, kw, "ascii_case_insensitive"));
+ }
+
+ ascii_case_insensitive_kw = Some(kw);
+ output.ascii_case_insensitive = Some(value);
+ }
+ VariantMeta::Props { props, .. } => {
+ output.string_props.extend(props);
+ }
+ }
+ }
+
+ Ok(output)
+ }
+}
diff --git a/vendor/strum_macros/src/lib.rs b/vendor/strum_macros/src/lib.rs
new file mode 100644
index 000000000..de16c9c25
--- /dev/null
+++ b/vendor/strum_macros/src/lib.rs
@@ -0,0 +1,755 @@
+//! # Strum
+//!
+//! Strum is a set of macros and traits for working with
+//! enums and strings easier in Rust.
+//!
+
+#![recursion_limit = "128"]
+
+extern crate proc_macro;
+
+mod helpers;
+mod macros;
+
+use proc_macro2::TokenStream;
+use std::env;
+use syn::DeriveInput;
+
+fn debug_print_generated(ast: &DeriveInput, toks: &TokenStream) {
+ let debug = env::var("STRUM_DEBUG");
+ if let Ok(s) = debug {
+ if s == "1" {
+ println!("{}", toks);
+ }
+
+ if ast.ident == s {
+ println!("{}", toks);
+ }
+ }
+}
+
+/// Converts strings to enum variants based on their name.
+///
+/// auto-derives `std::str::FromStr` on the enum (for Rust 1.34 and above, `std::convert::TryFrom<&str>`
+/// will be derived as well). Each variant of the enum will match on it's own name.
+/// This can be overridden using `serialize="DifferentName"` or `to_string="DifferentName"`
+/// on the attribute as shown below.
+/// Multiple deserializations can be added to the same variant. If the variant contains additional data,
+/// they will be set to their default values upon deserialization.
+///
+/// The `default` attribute can be applied to a tuple variant with a single data parameter. When a match isn't
+/// found, the given variant will be returned and the input string will be captured in the parameter.
+///
+/// Note that the implementation of `FromStr` by default only matches on the name of the
+/// variant. There is an option to match on different case conversions through the
+/// `#[strum(serialize_all = "snake_case")]` type attribute.
+///
+/// See the [Additional Attributes](https://docs.rs/strum/0.22/strum/additional_attributes/index.html)
+/// Section for more information on using this feature.
+///
+/// If you have a large enum, you may want to consider using the `use_phf` attribute here. It leverages
+/// perfect hash functions to parse much quicker than a standard `match`. (MSRV 1.46)
+///
+/// # Example howto use `EnumString`
+/// ```
+/// use std::str::FromStr;
+/// use strum_macros::EnumString;
+///
+/// #[derive(Debug, PartialEq, EnumString)]
+/// enum Color {
+/// Red,
+/// // The Default value will be inserted into range if we match "Green".
+/// Green {
+/// range: usize,
+/// },
+///
+/// // We can match on multiple different patterns.
+/// #[strum(serialize = "blue", serialize = "b")]
+/// Blue(usize),
+///
+/// // Notice that we can disable certain variants from being found
+/// #[strum(disabled)]
+/// Yellow,
+///
+/// // We can make the comparison case insensitive (however Unicode is not supported at the moment)
+/// #[strum(ascii_case_insensitive)]
+/// Black,
+/// }
+///
+/// /*
+/// //The generated code will look like:
+/// impl std::str::FromStr for Color {
+/// type Err = ::strum::ParseError;
+///
+/// fn from_str(s: &str) -> ::core::result::Result<Color, Self::Err> {
+/// match s {
+/// "Red" => ::core::result::Result::Ok(Color::Red),
+/// "Green" => ::core::result::Result::Ok(Color::Green { range:Default::default() }),
+/// "blue" => ::core::result::Result::Ok(Color::Blue(Default::default())),
+/// "b" => ::core::result::Result::Ok(Color::Blue(Default::default())),
+/// s if s.eq_ignore_ascii_case("Black") => ::core::result::Result::Ok(Color::Black),
+/// _ => ::core::result::Result::Err(::strum::ParseError::VariantNotFound),
+/// }
+/// }
+/// }
+/// */
+///
+/// // simple from string
+/// let color_variant = Color::from_str("Red").unwrap();
+/// assert_eq!(Color::Red, color_variant);
+/// // short version works too
+/// let color_variant = Color::from_str("b").unwrap();
+/// assert_eq!(Color::Blue(0), color_variant);
+/// // was disabled for parsing = returns parse-error
+/// let color_variant = Color::from_str("Yellow");
+/// assert!(color_variant.is_err());
+/// // however the variant is still normally usable
+/// println!("{:?}", Color::Yellow);
+/// let color_variant = Color::from_str("bLACk").unwrap();
+/// assert_eq!(Color::Black, color_variant);
+/// ```
+#[proc_macro_derive(EnumString, attributes(strum))]
+pub fn from_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let ast = syn::parse_macro_input!(input as DeriveInput);
+
+ let toks =
+ macros::from_string::from_string_inner(&ast).unwrap_or_else(|err| err.to_compile_error());
+ debug_print_generated(&ast, &toks);
+ toks.into()
+}
+
+/// Converts enum variants to `&'static str`.
+///
+/// Implements `AsRef<str>` on your enum using the same rules as
+/// `Display` for determining what string is returned. The difference is that `as_ref()` returns
+/// a `&str` instead of a `String` so you don't allocate any additional memory with each call.
+///
+/// ```
+/// // You need to bring the AsRef trait into scope to use it
+/// use std::convert::AsRef;
+/// use strum_macros::AsRefStr;
+///
+/// #[derive(AsRefStr, Debug)]
+/// enum Color {
+/// #[strum(serialize = "redred")]
+/// Red,
+/// Green {
+/// range: usize,
+/// },
+/// Blue(usize),
+/// Yellow,
+/// }
+///
+/// // uses the serialize string for Display
+/// let red = Color::Red;
+/// assert_eq!("redred", red.as_ref());
+/// // by default the variants Name
+/// let yellow = Color::Yellow;
+/// assert_eq!("Yellow", yellow.as_ref());
+/// // or for string formatting
+/// println!(
+/// "blue: {} green: {}",
+/// Color::Blue(10).as_ref(),
+/// Color::Green { range: 42 }.as_ref()
+/// );
+/// ```
+#[proc_macro_derive(AsRefStr, attributes(strum))]
+pub fn as_ref_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let ast = syn::parse_macro_input!(input as DeriveInput);
+
+ let toks =
+ macros::as_ref_str::as_ref_str_inner(&ast).unwrap_or_else(|err| err.to_compile_error());
+ debug_print_generated(&ast, &toks);
+ toks.into()
+}
+
+/// Implements `Strum::VariantNames` which adds an associated constant `VARIANTS` which is an array of discriminant names.
+///
+/// Adds an `impl` block for the `enum` that adds a static `VARIANTS` array of `&'static str` that are the discriminant names.
+/// This will respect the `serialize_all` attribute on the `enum` (like `#[strum(serialize_all = "snake_case")]`.
+///
+/// ```
+/// // import the macros needed
+/// use strum_macros::{EnumString, EnumVariantNames};
+/// // You need to import the trait, to have access to VARIANTS
+/// use strum::VariantNames;
+///
+/// #[derive(Debug, EnumString, EnumVariantNames)]
+/// #[strum(serialize_all = "kebab_case")]
+/// enum Color {
+/// Red,
+/// Blue,
+/// Yellow,
+/// RebeccaPurple,
+/// }
+/// assert_eq!(["red", "blue", "yellow", "rebecca-purple"], Color::VARIANTS);
+/// ```
+#[proc_macro_derive(EnumVariantNames, attributes(strum))]
+pub fn variant_names(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let ast = syn::parse_macro_input!(input as DeriveInput);
+
+ let toks = macros::enum_variant_names::enum_variant_names_inner(&ast)
+ .unwrap_or_else(|err| err.to_compile_error());
+ debug_print_generated(&ast, &toks);
+ toks.into()
+}
+
+#[proc_macro_derive(AsStaticStr, attributes(strum))]
+#[deprecated(
+ since = "0.22.0",
+ note = "please use `#[derive(IntoStaticStr)]` instead"
+)]
+pub fn as_static_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let ast = syn::parse_macro_input!(input as DeriveInput);
+
+ let toks = macros::as_ref_str::as_static_str_inner(
+ &ast,
+ &macros::as_ref_str::GenerateTraitVariant::AsStaticStr,
+ )
+ .unwrap_or_else(|err| err.to_compile_error());
+ debug_print_generated(&ast, &toks);
+ toks.into()
+}
+
+/// Implements `From<MyEnum> for &'static str` on an enum.
+///
+/// Implements `From<YourEnum>` and `From<&'a YourEnum>` for `&'static str`. This is
+/// useful for turning an enum variant into a static string.
+/// The Rust `std` provides a blanket impl of the reverse direction - i.e. `impl Into<&'static str> for YourEnum`.
+///
+/// ```
+/// use strum_macros::IntoStaticStr;
+///
+/// #[derive(IntoStaticStr)]
+/// enum State<'a> {
+/// Initial(&'a str),
+/// Finished,
+/// }
+///
+/// fn verify_state<'a>(s: &'a str) {
+/// let mut state = State::Initial(s);
+/// // The following won't work because the lifetime is incorrect:
+/// // let wrong: &'static str = state.as_ref();
+/// // using the trait implemented by the derive works however:
+/// let right: &'static str = state.into();
+/// assert_eq!("Initial", right);
+/// state = State::Finished;
+/// let done: &'static str = state.into();
+/// assert_eq!("Finished", done);
+/// }
+///
+/// verify_state(&"hello world".to_string());
+/// ```
+#[proc_macro_derive(IntoStaticStr, attributes(strum))]
+pub fn into_static_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let ast = syn::parse_macro_input!(input as DeriveInput);
+
+ let toks = macros::as_ref_str::as_static_str_inner(
+ &ast,
+ &macros::as_ref_str::GenerateTraitVariant::From,
+ )
+ .unwrap_or_else(|err| err.to_compile_error());
+ debug_print_generated(&ast, &toks);
+ toks.into()
+}
+
+/// implements `std::string::ToString` on en enum
+///
+/// ```
+/// // You need to bring the ToString trait into scope to use it
+/// use std::string::ToString;
+/// use strum_macros;
+///
+/// #[derive(strum_macros::ToString, Debug)]
+/// enum Color {
+/// #[strum(serialize = "redred")]
+/// Red,
+/// Green {
+/// range: usize,
+/// },
+/// Blue(usize),
+/// Yellow,
+/// }
+///
+/// // uses the serialize string for Display
+/// let red = Color::Red;
+/// assert_eq!(String::from("redred"), red.to_string());
+/// // by default the variants Name
+/// let yellow = Color::Yellow;
+/// assert_eq!(String::from("Yellow"), yellow.to_string());
+/// ```
+#[deprecated(
+ since = "0.22.0",
+ note = "please use `#[derive(Display)]` instead. See issue https://github.com/Peternator7/strum/issues/132"
+)]
+#[proc_macro_derive(ToString, attributes(strum))]
+pub fn to_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let ast = syn::parse_macro_input!(input as DeriveInput);
+
+ let toks =
+ macros::to_string::to_string_inner(&ast).unwrap_or_else(|err| err.to_compile_error());
+ debug_print_generated(&ast, &toks);
+ toks.into()
+}
+
+/// Converts enum variants to strings.
+///
+/// Deriving `Display` on an enum prints out the given enum. This enables you to perform round
+/// trip style conversions from enum into string and back again for unit style variants. `Display`
+/// choose which serialization to used based on the following criteria:
+///
+/// 1. If there is a `to_string` property, this value will be used. There can only be one per variant.
+/// 1. Of the various `serialize` properties, the value with the longest length is chosen. If that
+/// behavior isn't desired, you should use `to_string`.
+/// 1. The name of the variant will be used if there are no `serialize` or `to_string` attributes.
+///
+/// ```
+/// // You need to bring the ToString trait into scope to use it
+/// use std::string::ToString;
+/// use strum_macros::Display;
+///
+/// #[derive(Display, Debug)]
+/// enum Color {
+/// #[strum(serialize = "redred")]
+/// Red,
+/// Green {
+/// range: usize,
+/// },
+/// Blue(usize),
+/// Yellow,
+/// }
+///
+/// // uses the serialize string for Display
+/// let red = Color::Red;
+/// assert_eq!(String::from("redred"), format!("{}", red));
+/// // by default the variants Name
+/// let yellow = Color::Yellow;
+/// assert_eq!(String::from("Yellow"), yellow.to_string());
+/// // or for string formatting
+/// println!(
+/// "blue: {} green: {}",
+/// Color::Blue(10),
+/// Color::Green { range: 42 }
+/// );
+/// ```
+#[proc_macro_derive(Display, attributes(strum))]
+pub fn display(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let ast = syn::parse_macro_input!(input as DeriveInput);
+
+ let toks = macros::display::display_inner(&ast).unwrap_or_else(|err| err.to_compile_error());
+ debug_print_generated(&ast, &toks);
+ toks.into()
+}
+
+/// Creates a new type that iterates of the variants of an enum.
+///
+/// Iterate over the variants of an Enum. Any additional data on your variants will be set to `Default::default()`.
+/// The macro implements `strum::IntoEnumIter` on your enum and creates a new type called `YourEnumIter` that is the iterator object.
+/// You cannot derive `EnumIter` on any type with a lifetime bound (`<'a>`) because the iterator would surely
+/// create [unbounded lifetimes](https://doc.rust-lang.org/nightly/nomicon/unbounded-lifetimes.html).
+///
+/// ```
+///
+/// // You need to bring the trait into scope to use it!
+/// use strum::IntoEnumIterator;
+/// use strum_macros::EnumIter;
+///
+/// #[derive(EnumIter, Debug, PartialEq)]
+/// enum Color {
+/// Red,
+/// Green { range: usize },
+/// Blue(usize),
+/// Yellow,
+/// }
+///
+/// // It's simple to iterate over the variants of an enum.
+/// for color in Color::iter() {
+/// println!("My favorite color is {:?}", color);
+/// }
+///
+/// let mut ci = Color::iter();
+/// assert_eq!(Some(Color::Red), ci.next());
+/// assert_eq!(Some(Color::Green {range: 0}), ci.next());
+/// assert_eq!(Some(Color::Blue(0)), ci.next());
+/// assert_eq!(Some(Color::Yellow), ci.next());
+/// assert_eq!(None, ci.next());
+/// ```
+#[proc_macro_derive(EnumIter, attributes(strum))]
+pub fn enum_iter(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let ast = syn::parse_macro_input!(input as DeriveInput);
+
+ let toks =
+ macros::enum_iter::enum_iter_inner(&ast).unwrap_or_else(|err| err.to_compile_error());
+ debug_print_generated(&ast, &toks);
+ toks.into()
+}
+
+/// Add a function to enum that allows accessing variants by its discriminant
+///
+/// This macro adds a standalone function to obtain an enum variant by its discriminant. The macro adds
+/// `from_repr(discriminant: usize) -> Option<YourEnum>` as a standalone function on the enum. For
+/// variants with additional data, the returned variant will use the `Default` trait to fill the
+/// data. The discriminant follows the same rules as `rustc`. The first discriminant is zero and each
+/// successive variant has a discriminant of one greater than the previous variant, expect where an
+/// explicit discriminant is specified. The type of the discriminant will match the `repr` type if
+/// it is specifed.
+///
+/// When the macro is applied using rustc >= 1.46 and when there is no additional data on any of
+/// the variants, the `from_repr` function is marked `const`. rustc >= 1.46 is required
+/// to allow `match` statements in `const fn`. The no additional data requirement is due to the
+/// inability to use `Default::default()` in a `const fn`.
+///
+/// You cannot derive `FromRepr` on any type with a lifetime bound (`<'a>`) because the function would surely
+/// create [unbounded lifetimes](https://doc.rust-lang.org/nightly/nomicon/unbounded-lifetimes.html).
+///
+/// ```
+///
+/// use strum_macros::FromRepr;
+///
+/// #[derive(FromRepr, Debug, PartialEq)]
+/// enum Color {
+/// Red,
+/// Green { range: usize },
+/// Blue(usize),
+/// Yellow,
+/// }
+///
+/// assert_eq!(Some(Color::Red), Color::from_repr(0));
+/// assert_eq!(Some(Color::Green {range: 0}), Color::from_repr(1));
+/// assert_eq!(Some(Color::Blue(0)), Color::from_repr(2));
+/// assert_eq!(Some(Color::Yellow), Color::from_repr(3));
+/// assert_eq!(None, Color::from_repr(4));
+///
+/// // Custom discriminant tests
+/// #[derive(FromRepr, Debug, PartialEq)]
+/// #[repr(u8)]
+/// enum Vehicle {
+/// Car = 1,
+/// Truck = 3,
+/// }
+///
+/// assert_eq!(None, Vehicle::from_repr(0));
+/// ```
+///
+/// On versions of rust >= 1.46, the `from_repr` function is marked `const`.
+///
+/// ```rust
+/// use strum_macros::FromRepr;
+///
+/// #[derive(FromRepr, Debug, PartialEq)]
+/// #[repr(u8)]
+/// enum Number {
+/// One = 1,
+/// Three = 3,
+/// }
+///
+/// # #[rustversion::since(1.46)]
+/// const fn number_from_repr(d: u8) -> Option<Number> {
+/// Number::from_repr(d)
+/// }
+///
+/// # #[rustversion::before(1.46)]
+/// # fn number_from_repr(d: u8) -> Option<Number> {
+/// # Number::from_repr(d)
+/// # }
+/// assert_eq!(None, number_from_repr(0));
+/// assert_eq!(Some(Number::One), number_from_repr(1));
+/// assert_eq!(None, number_from_repr(2));
+/// assert_eq!(Some(Number::Three), number_from_repr(3));
+/// assert_eq!(None, number_from_repr(4));
+/// ```
+
+#[proc_macro_derive(FromRepr, attributes(strum))]
+pub fn from_repr(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let ast = syn::parse_macro_input!(input as DeriveInput);
+
+ let toks =
+ macros::from_repr::from_repr_inner(&ast).unwrap_or_else(|err| err.to_compile_error());
+ debug_print_generated(&ast, &toks);
+ toks.into()
+}
+
+/// Add a verbose message to an enum variant.
+///
+/// Encode strings into the enum itself. The `strum_macros::EmumMessage` macro implements the `strum::EnumMessage` trait.
+/// `EnumMessage` looks for `#[strum(message="...")]` attributes on your variants.
+/// You can also provided a `detailed_message="..."` attribute to create a seperate more detailed message than the first.
+///
+/// `EnumMessage` also exposes the variants doc comments through `get_documentation()`. This is useful in some scenarios,
+/// but `get_message` should generally be preferred. Rust doc comments are intended for developer facing documentation,
+/// not end user messaging.
+///
+/// ```
+/// // You need to bring the trait into scope to use it
+/// use strum::EnumMessage;
+/// use strum_macros;
+///
+/// #[derive(strum_macros::EnumMessage, Debug)]
+/// #[allow(dead_code)]
+/// enum Color {
+/// /// Danger color.
+/// #[strum(message = "Red", detailed_message = "This is very red")]
+/// Red,
+/// #[strum(message = "Simply Green")]
+/// Green { range: usize },
+/// #[strum(serialize = "b", serialize = "blue")]
+/// Blue(usize),
+/// }
+///
+/// // Generated code looks like more or less like this:
+/// /*
+/// impl ::strum::EnumMessage for Color {
+/// fn get_message(&self) -> ::core::option::Option<&'static str> {
+/// match self {
+/// &Color::Red => ::core::option::Option::Some("Red"),
+/// &Color::Green {..} => ::core::option::Option::Some("Simply Green"),
+/// _ => None
+/// }
+/// }
+///
+/// fn get_detailed_message(&self) -> ::core::option::Option<&'static str> {
+/// match self {
+/// &Color::Red => ::core::option::Option::Some("This is very red"),
+/// &Color::Green {..}=> ::core::option::Option::Some("Simply Green"),
+/// _ => None
+/// }
+/// }
+///
+/// fn get_documentation(&self) -> ::std::option::Option<&'static str> {
+/// match self {
+/// &Color::Red => ::std::option::Option::Some("Danger color."),
+/// _ => None
+/// }
+/// }
+///
+/// fn get_serializations(&self) -> &'static [&'static str] {
+/// match self {
+/// &Color::Red => {
+/// static ARR: [&'static str; 1] = ["Red"];
+/// &ARR
+/// },
+/// &Color::Green {..}=> {
+/// static ARR: [&'static str; 1] = ["Green"];
+/// &ARR
+/// },
+/// &Color::Blue (..) => {
+/// static ARR: [&'static str; 2] = ["b", "blue"];
+/// &ARR
+/// },
+/// }
+/// }
+/// }
+/// */
+///
+/// let c = Color::Red;
+/// assert_eq!("Red", c.get_message().unwrap());
+/// assert_eq!("This is very red", c.get_detailed_message().unwrap());
+/// assert_eq!("Danger color.", c.get_documentation().unwrap());
+/// assert_eq!(["Red"], c.get_serializations());
+/// ```
+#[proc_macro_derive(EnumMessage, attributes(strum))]
+pub fn enum_messages(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let ast = syn::parse_macro_input!(input as DeriveInput);
+
+ let toks = macros::enum_messages::enum_message_inner(&ast)
+ .unwrap_or_else(|err| err.to_compile_error());
+ debug_print_generated(&ast, &toks);
+ toks.into()
+}
+
+/// Add custom properties to enum variants.
+///
+/// Enables the encoding of arbitary constants into enum variants. This method
+/// currently only supports adding additional string values. Other types of literals are still
+/// experimental in the rustc compiler. The generated code works by nesting match statements.
+/// The first match statement matches on the type of the enum, and the inner match statement
+/// matches on the name of the property requested. This design works well for enums with a small
+/// number of variants and properties, but scales linearly with the number of variants so may not
+/// be the best choice in all situations.
+///
+/// ```
+///
+/// use strum_macros;
+/// // bring the trait into scope
+/// use strum::EnumProperty;
+///
+/// #[derive(strum_macros::EnumProperty, Debug)]
+/// #[allow(dead_code)]
+/// enum Color {
+/// #[strum(props(Red = "255", Blue = "255", Green = "255"))]
+/// White,
+/// #[strum(props(Red = "0", Blue = "0", Green = "0"))]
+/// Black,
+/// #[strum(props(Red = "0", Blue = "255", Green = "0"))]
+/// Blue,
+/// #[strum(props(Red = "255", Blue = "0", Green = "0"))]
+/// Red,
+/// #[strum(props(Red = "0", Blue = "0", Green = "255"))]
+/// Green,
+/// }
+///
+/// let my_color = Color::Red;
+/// let display = format!(
+/// "My color is {:?}. It's RGB is {},{},{}",
+/// my_color,
+/// my_color.get_str("Red").unwrap(),
+/// my_color.get_str("Green").unwrap(),
+/// my_color.get_str("Blue").unwrap()
+/// );
+/// assert_eq!("My color is Red. It\'s RGB is 255,0,0", &display);
+/// ```
+
+#[proc_macro_derive(EnumProperty, attributes(strum))]
+pub fn enum_properties(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let ast = syn::parse_macro_input!(input as DeriveInput);
+
+ let toks = macros::enum_properties::enum_properties_inner(&ast)
+ .unwrap_or_else(|err| err.to_compile_error());
+ debug_print_generated(&ast, &toks);
+ toks.into()
+}
+
+/// Generate a new type with only the discriminant names.
+///
+/// Given an enum named `MyEnum`, generates another enum called `MyEnumDiscriminants` with the same
+/// variants but without any data fields. This is useful when you wish to determine the variant of
+/// an `enum` but one or more of the variants contains a non-`Default` field. `From`
+/// implementations are generated so that you can easily convert from `MyEnum` to
+/// `MyEnumDiscriminants`.
+///
+/// By default, the generated enum has the following derives: `Clone, Copy, Debug, PartialEq, Eq`.
+/// You can add additional derives using the `#[strum_discriminants(derive(AdditionalDerive))]`
+/// attribute.
+///
+/// Note, the variant attributes passed to the discriminant enum are filtered to avoid compilation
+/// errors due to the derives mismatches, thus only `#[doc]`, `#[cfg]`, `#[allow]`, and `#[deny]`
+/// are passed through by default. If you want to specify a custom attribute on the discriminant
+/// variant, wrap it with `#[strum_discriminants(...)]` attribute.
+///
+/// ```
+/// // Bring trait into scope
+/// use std::str::FromStr;
+/// use strum::{IntoEnumIterator, EnumMessage};
+/// use strum_macros::{EnumDiscriminants, EnumIter, EnumString, EnumMessage};
+///
+/// #[derive(Debug)]
+/// struct NonDefault;
+///
+/// // simple example
+/// # #[allow(dead_code)]
+/// #[derive(Debug, EnumDiscriminants)]
+/// #[strum_discriminants(derive(EnumString, EnumMessage))]
+/// enum MyEnum {
+/// #[strum_discriminants(strum(message = "Variant zero"))]
+/// Variant0(NonDefault),
+/// Variant1 { a: NonDefault },
+/// }
+///
+/// // You can rename the generated enum using the `#[strum_discriminants(name(OtherName))]` attribute:
+/// # #[allow(dead_code)]
+/// #[derive(Debug, EnumDiscriminants)]
+/// #[strum_discriminants(derive(EnumIter))]
+/// #[strum_discriminants(name(MyVariants))]
+/// enum MyEnumR {
+/// Variant0(bool),
+/// Variant1 { a: bool },
+/// }
+///
+/// // test simple example
+/// assert_eq!(
+/// MyEnumDiscriminants::Variant0,
+/// MyEnumDiscriminants::from_str("Variant0").unwrap()
+/// );
+/// // test rename example combined with EnumIter
+/// assert_eq!(
+/// vec![MyVariants::Variant0, MyVariants::Variant1],
+/// MyVariants::iter().collect::<Vec<_>>()
+/// );
+///
+/// // Make use of the auto-From conversion to check whether an instance of `MyEnum` matches a
+/// // `MyEnumDiscriminants` discriminant.
+/// assert_eq!(
+/// MyEnumDiscriminants::Variant0,
+/// MyEnum::Variant0(NonDefault).into()
+/// );
+/// assert_eq!(
+/// MyEnumDiscriminants::Variant0,
+/// MyEnumDiscriminants::from(MyEnum::Variant0(NonDefault))
+/// );
+///
+/// // Make use of the EnumMessage on the `MyEnumDiscriminants` discriminant.
+/// assert_eq!(
+/// MyEnumDiscriminants::Variant0.get_message(),
+/// Some("Variant zero")
+/// );
+/// ```
+///
+/// It is also possible to specify the visibility (e.g. `pub`/`pub(crate)`/etc.)
+/// of the generated enum. By default, the generated enum inherits the
+/// visibility of the parent enum it was generated from.
+///
+/// ```nocompile
+/// use strum_macros::EnumDiscriminants;
+///
+/// // You can set the visibility of the generated enum using the `#[strum_discriminants(vis(..))]` attribute:
+/// mod inner {
+/// use strum_macros::EnumDiscriminants;
+///
+/// # #[allow(dead_code)]
+/// #[derive(Debug, EnumDiscriminants)]
+/// #[strum_discriminants(vis(pub))]
+/// #[strum_discriminants(name(PubDiscriminants))]
+/// enum PrivateEnum {
+/// Variant0(bool),
+/// Variant1 { a: bool },
+/// }
+/// }
+///
+/// // test visibility example, `PrivateEnum` should not be accessible here
+/// assert_ne!(
+/// inner::PubDiscriminants::Variant0,
+/// inner::PubDiscriminants::Variant1,
+/// );
+/// ```
+#[proc_macro_derive(EnumDiscriminants, attributes(strum, strum_discriminants))]
+pub fn enum_discriminants(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let ast = syn::parse_macro_input!(input as DeriveInput);
+
+ let toks = macros::enum_discriminants::enum_discriminants_inner(&ast)
+ .unwrap_or_else(|err| err.to_compile_error());
+ debug_print_generated(&ast, &toks);
+ toks.into()
+}
+
+/// Add a constant `usize` equal to the number of variants.
+///
+/// For a given enum generates implementation of `strum::EnumCount`,
+/// which adds a static property `COUNT` of type usize that holds the number of variants.
+///
+/// ```
+/// use strum::{EnumCount, IntoEnumIterator};
+/// use strum_macros::{EnumCount as EnumCountMacro, EnumIter};
+///
+/// #[derive(Debug, EnumCountMacro, EnumIter)]
+/// enum Week {
+/// Sunday,
+/// Monday,
+/// Tuesday,
+/// Wednesday,
+/// Thursday,
+/// Friday,
+/// Saturday,
+/// }
+///
+/// assert_eq!(7, Week::COUNT);
+/// assert_eq!(Week::iter().count(), Week::COUNT);
+///
+/// ```
+#[proc_macro_derive(EnumCount, attributes(strum))]
+pub fn enum_count(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let ast = syn::parse_macro_input!(input as DeriveInput);
+ let toks =
+ macros::enum_count::enum_count_inner(&ast).unwrap_or_else(|err| err.to_compile_error());
+ debug_print_generated(&ast, &toks);
+ toks.into()
+}
diff --git a/vendor/strum_macros/src/macros/enum_count.rs b/vendor/strum_macros/src/macros/enum_count.rs
new file mode 100644
index 000000000..44c7f2e57
--- /dev/null
+++ b/vendor/strum_macros/src/macros/enum_count.rs
@@ -0,0 +1,27 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{Data, DeriveInput};
+
+use crate::helpers::{non_enum_error, HasTypeProperties};
+
+pub(crate) fn enum_count_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
+ let n = match &ast.data {
+ Data::Enum(v) => v.variants.len(),
+ _ => return Err(non_enum_error()),
+ };
+ let type_properties = ast.get_type_properties()?;
+ let strum_module_path = type_properties.crate_module_path();
+
+ // Used in the quasi-quotation below as `#name`
+ let name = &ast.ident;
+
+ // Helper is provided for handling complex generic types correctly and effortlessly
+ let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
+
+ Ok(quote! {
+ // Implementation
+ impl #impl_generics #strum_module_path::EnumCount for #name #ty_generics #where_clause {
+ const COUNT: usize = #n;
+ }
+ })
+}
diff --git a/vendor/strum_macros/src/macros/enum_discriminants.rs b/vendor/strum_macros/src/macros/enum_discriminants.rs
new file mode 100644
index 000000000..66eee46b4
--- /dev/null
+++ b/vendor/strum_macros/src/macros/enum_discriminants.rs
@@ -0,0 +1,162 @@
+use proc_macro2::{Span, TokenStream, TokenTree};
+use quote::{quote, ToTokens};
+use syn::parse_quote;
+use syn::{Data, DeriveInput, Fields};
+
+use crate::helpers::{non_enum_error, strum_discriminants_passthrough_error, HasTypeProperties};
+
+/// Attributes to copy from the main enum's variants to the discriminant enum's variants.
+///
+/// Attributes not in this list may be for other `proc_macro`s on the main enum, and may cause
+/// compilation problems when copied across.
+const ATTRIBUTES_TO_COPY: &[&str] = &["doc", "cfg", "allow", "deny", "strum_discriminants"];
+
+pub fn enum_discriminants_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
+ let name = &ast.ident;
+ let vis = &ast.vis;
+
+ let variants = match &ast.data {
+ Data::Enum(v) => &v.variants,
+ _ => return Err(non_enum_error()),
+ };
+
+ // Derives for the generated enum
+ let type_properties = ast.get_type_properties()?;
+
+ let derives = type_properties.discriminant_derives;
+
+ let derives = quote! {
+ #[derive(Clone, Copy, Debug, PartialEq, Eq, #(#derives),*)]
+ };
+
+ // Work out the name
+ let default_name = syn::Ident::new(&format!("{}Discriminants", name), Span::call_site());
+
+ let discriminants_name = type_properties.discriminant_name.unwrap_or(default_name);
+ let discriminants_vis = type_properties
+ .discriminant_vis
+ .unwrap_or_else(|| vis.clone());
+
+ // Pass through all other attributes
+ let pass_though_attributes = type_properties.discriminant_others;
+
+ // Add the variants without fields, but exclude the `strum` meta item
+ let mut discriminants = Vec::new();
+ for variant in variants {
+ let ident = &variant.ident;
+
+ // Don't copy across the "strum" meta attribute. Only passthrough the whitelisted
+ // attributes and proxy `#[strum_discriminants(...)]` attributes
+ let attrs = variant
+ .attrs
+ .iter()
+ .filter(|attr| {
+ ATTRIBUTES_TO_COPY
+ .iter()
+ .any(|attr_whitelisted| attr.path.is_ident(attr_whitelisted))
+ })
+ .map(|attr| {
+ if attr.path.is_ident("strum_discriminants") {
+ let passthrough_group = attr
+ .tokens
+ .clone()
+ .into_iter()
+ .next()
+ .ok_or_else(|| strum_discriminants_passthrough_error(attr))?;
+ let passthrough_attribute = match passthrough_group {
+ TokenTree::Group(ref group) => group.stream(),
+ _ => {
+ return Err(strum_discriminants_passthrough_error(&passthrough_group));
+ }
+ };
+ if passthrough_attribute.is_empty() {
+ return Err(strum_discriminants_passthrough_error(&passthrough_group));
+ }
+ Ok(quote! { #[#passthrough_attribute] })
+ } else {
+ Ok(attr.to_token_stream())
+ }
+ })
+ .collect::<Result<Vec<_>, _>>()?;
+
+ discriminants.push(quote! { #(#attrs)* #ident });
+ }
+
+ // Ideally:
+ //
+ // * For `Copy` types, we `impl From<TheEnum> for TheEnumDiscriminants`
+ // * For `!Copy` types, we `impl<'enum> From<&'enum TheEnum> for TheEnumDiscriminants`
+ //
+ // That way we ensure users are not able to pass a `Copy` type by reference. However, the
+ // `#[derive(..)]` attributes are not in the parsed tokens, so we are not able to check if a
+ // type is `Copy`, so we just implement both.
+ //
+ // See <https://github.com/dtolnay/syn/issues/433>
+ // ---
+ // let is_copy = unique_meta_list(type_meta.iter(), "derive")
+ // .map(extract_list_metas)
+ // .map(|metas| {
+ // metas
+ // .filter_map(get_meta_ident)
+ // .any(|derive| derive.to_string() == "Copy")
+ // }).unwrap_or(false);
+
+ let arms = variants
+ .iter()
+ .map(|variant| {
+ let ident = &variant.ident;
+ let params = match &variant.fields {
+ Fields::Unit => quote! {},
+ Fields::Unnamed(_fields) => {
+ quote! { (..) }
+ }
+ Fields::Named(_fields) => {
+ quote! { { .. } }
+ }
+ };
+
+ quote! { #name::#ident #params => #discriminants_name::#ident }
+ })
+ .collect::<Vec<_>>();
+
+ let from_fn_body = quote! { match val { #(#arms),* } };
+
+ let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
+ let impl_from = quote! {
+ impl #impl_generics ::core::convert::From< #name #ty_generics > for #discriminants_name #where_clause {
+ fn from(val: #name #ty_generics) -> #discriminants_name {
+ #from_fn_body
+ }
+ }
+ };
+ let impl_from_ref = {
+ let mut generics = ast.generics.clone();
+
+ let lifetime = parse_quote!('_enum);
+ let enum_life = quote! { & #lifetime };
+ generics.params.push(lifetime);
+
+ // Shadows the earlier `impl_generics`
+ let (impl_generics, _, _) = generics.split_for_impl();
+
+ quote! {
+ impl #impl_generics ::core::convert::From< #enum_life #name #ty_generics > for #discriminants_name #where_clause {
+ fn from(val: #enum_life #name #ty_generics) -> #discriminants_name {
+ #from_fn_body
+ }
+ }
+ }
+ };
+
+ Ok(quote! {
+ /// Auto-generated discriminant enum variants
+ #derives
+ #(#[ #pass_though_attributes ])*
+ #discriminants_vis enum #discriminants_name {
+ #(#discriminants),*
+ }
+
+ #impl_from
+ #impl_from_ref
+ })
+}
diff --git a/vendor/strum_macros/src/macros/enum_iter.rs b/vendor/strum_macros/src/macros/enum_iter.rs
new file mode 100644
index 000000000..9c7017c00
--- /dev/null
+++ b/vendor/strum_macros/src/macros/enum_iter.rs
@@ -0,0 +1,158 @@
+use proc_macro2::{Span, TokenStream};
+use quote::quote;
+use syn::{Data, DeriveInput, Fields, Ident};
+
+use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties};
+
+pub fn enum_iter_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
+ let name = &ast.ident;
+ let gen = &ast.generics;
+ let (impl_generics, ty_generics, where_clause) = gen.split_for_impl();
+ let vis = &ast.vis;
+ let type_properties = ast.get_type_properties()?;
+ let strum_module_path = type_properties.crate_module_path();
+
+ if gen.lifetimes().count() > 0 {
+ return Err(syn::Error::new(
+ Span::call_site(),
+ "This macro doesn't support enums with lifetimes. \
+ The resulting enums would be unbounded.",
+ ));
+ }
+
+ let phantom_data = if gen.type_params().count() > 0 {
+ let g = gen.type_params().map(|param| &param.ident);
+ quote! { < ( #(#g),* ) > }
+ } else {
+ quote! { < () > }
+ };
+
+ let variants = match &ast.data {
+ Data::Enum(v) => &v.variants,
+ _ => return Err(non_enum_error()),
+ };
+
+ let mut arms = Vec::new();
+ let mut idx = 0usize;
+ for variant in variants {
+ if variant.get_variant_properties()?.disabled.is_some() {
+ continue;
+ }
+
+ let ident = &variant.ident;
+ let params = match &variant.fields {
+ Fields::Unit => quote! {},
+ Fields::Unnamed(fields) => {
+ let defaults = ::core::iter::repeat(quote!(::core::default::Default::default()))
+ .take(fields.unnamed.len());
+ quote! { (#(#defaults),*) }
+ }
+ Fields::Named(fields) => {
+ let fields = fields
+ .named
+ .iter()
+ .map(|field| field.ident.as_ref().unwrap());
+ quote! { {#(#fields: ::core::default::Default::default()),*} }
+ }
+ };
+
+ arms.push(quote! {#idx => ::core::option::Option::Some(#name::#ident #params)});
+ idx += 1;
+ }
+
+ let variant_count = arms.len();
+ arms.push(quote! { _ => ::core::option::Option::None });
+ let iter_name = syn::parse_str::<Ident>(&format!("{}Iter", name)).unwrap();
+
+ Ok(quote! {
+ #[doc = "An iterator over the variants of [Self]"]
+ #[allow(
+ missing_copy_implementations,
+ missing_debug_implementations,
+ )]
+ #vis struct #iter_name #ty_generics {
+ idx: usize,
+ back_idx: usize,
+ marker: ::core::marker::PhantomData #phantom_data,
+ }
+
+ impl #impl_generics #iter_name #ty_generics #where_clause {
+ fn get(&self, idx: usize) -> Option<#name #ty_generics> {
+ match idx {
+ #(#arms),*
+ }
+ }
+ }
+
+ impl #impl_generics #strum_module_path::IntoEnumIterator for #name #ty_generics #where_clause {
+ type Iterator = #iter_name #ty_generics;
+ fn iter() -> #iter_name #ty_generics {
+ #iter_name {
+ idx: 0,
+ back_idx: 0,
+ marker: ::core::marker::PhantomData,
+ }
+ }
+ }
+
+ impl #impl_generics Iterator for #iter_name #ty_generics #where_clause {
+ type Item = #name #ty_generics;
+
+ fn next(&mut self) -> Option<<Self as Iterator>::Item> {
+ self.nth(0)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let t = if self.idx + self.back_idx >= #variant_count { 0 } else { #variant_count - self.idx - self.back_idx };
+ (t, Some(t))
+ }
+
+ fn nth(&mut self, n: usize) -> Option<<Self as Iterator>::Item> {
+ let idx = self.idx + n + 1;
+ if idx + self.back_idx > #variant_count {
+ // We went past the end of the iterator. Freeze idx at #variant_count
+ // so that it doesn't overflow if the user calls this repeatedly.
+ // See PR #76 for context.
+ self.idx = #variant_count;
+ ::core::option::Option::None
+ } else {
+ self.idx = idx;
+ self.get(idx - 1)
+ }
+ }
+ }
+
+ impl #impl_generics ExactSizeIterator for #iter_name #ty_generics #where_clause {
+ fn len(&self) -> usize {
+ self.size_hint().0
+ }
+ }
+
+ impl #impl_generics DoubleEndedIterator for #iter_name #ty_generics #where_clause {
+ fn next_back(&mut self) -> Option<<Self as Iterator>::Item> {
+ let back_idx = self.back_idx + 1;
+
+ if self.idx + back_idx > #variant_count {
+ // We went past the end of the iterator. Freeze back_idx at #variant_count
+ // so that it doesn't overflow if the user calls this repeatedly.
+ // See PR #76 for context.
+ self.back_idx = #variant_count;
+ ::core::option::Option::None
+ } else {
+ self.back_idx = back_idx;
+ self.get(#variant_count - self.back_idx)
+ }
+ }
+ }
+
+ impl #impl_generics Clone for #iter_name #ty_generics #where_clause {
+ fn clone(&self) -> #iter_name #ty_generics {
+ #iter_name {
+ idx: self.idx,
+ back_idx: self.back_idx,
+ marker: self.marker.clone(),
+ }
+ }
+ }
+ })
+}
diff --git a/vendor/strum_macros/src/macros/enum_messages.rs b/vendor/strum_macros/src/macros/enum_messages.rs
new file mode 100644
index 000000000..c05610851
--- /dev/null
+++ b/vendor/strum_macros/src/macros/enum_messages.rs
@@ -0,0 +1,138 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{Data, DeriveInput, Fields, LitStr};
+
+use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties};
+
+pub fn enum_message_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
+ let name = &ast.ident;
+ let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
+ let variants = match &ast.data {
+ Data::Enum(v) => &v.variants,
+ _ => return Err(non_enum_error()),
+ };
+
+ let type_properties = ast.get_type_properties()?;
+ let strum_module_path = type_properties.crate_module_path();
+
+ let mut arms = Vec::new();
+ let mut detailed_arms = Vec::new();
+ let mut documentation_arms = Vec::new();
+ let mut serializations = Vec::new();
+
+ for variant in variants {
+ let variant_properties = variant.get_variant_properties()?;
+ let messages = variant_properties.message.as_ref();
+ let detailed_messages = variant_properties.detailed_message.as_ref();
+ let documentation = &variant_properties.documentation;
+ let ident = &variant.ident;
+
+ let params = match variant.fields {
+ Fields::Unit => quote! {},
+ Fields::Unnamed(..) => quote! { (..) },
+ Fields::Named(..) => quote! { {..} },
+ };
+
+ // You can't disable getting the serializations.
+ {
+ let serialization_variants =
+ variant_properties.get_serializations(type_properties.case_style);
+
+ let count = serialization_variants.len();
+ serializations.push(quote! {
+ &#name::#ident #params => {
+ static ARR: [&'static str; #count] = [#(#serialization_variants),*];
+ &ARR
+ }
+ });
+ }
+
+ // But you can disable the messages.
+ if variant_properties.disabled.is_some() {
+ continue;
+ }
+
+ if let Some(msg) = messages {
+ let params = params.clone();
+
+ // Push the simple message.
+ let tokens = quote! { &#name::#ident #params => ::core::option::Option::Some(#msg) };
+ arms.push(tokens.clone());
+
+ if detailed_messages.is_none() {
+ detailed_arms.push(tokens);
+ }
+ }
+
+ if let Some(msg) = detailed_messages {
+ let params = params.clone();
+ // Push the detailed message.
+ detailed_arms
+ .push(quote! { &#name::#ident #params => ::core::option::Option::Some(#msg) });
+ }
+
+ if !documentation.is_empty() {
+ let params = params.clone();
+ // Strip a single leading space from each documentation line.
+ let documentation: Vec<LitStr> = documentation.iter().map(|lit_str| {
+ let line = lit_str.value();
+ if line.starts_with(' ') {
+ LitStr::new(&line.as_str()[1..], lit_str.span())
+ } else {
+ lit_str.clone()
+ }
+ }).collect();
+ if documentation.len() == 1 {
+ let text = &documentation[0];
+ documentation_arms
+ .push(quote! { &#name::#ident #params => ::core::option::Option::Some(#text) });
+ } else {
+ // Push the documentation.
+ documentation_arms
+ .push(quote! {
+ &#name::#ident #params => ::core::option::Option::Some(concat!(#(concat!(#documentation, "\n")),*))
+ });
+ }
+ }
+ }
+
+ if arms.len() < variants.len() {
+ arms.push(quote! { _ => ::core::option::Option::None });
+ }
+
+ if detailed_arms.len() < variants.len() {
+ detailed_arms.push(quote! { _ => ::core::option::Option::None });
+ }
+
+ if documentation_arms.len() < variants.len() {
+ documentation_arms.push(quote! { _ => ::core::option::Option::None });
+ }
+
+ Ok(quote! {
+ impl #impl_generics #strum_module_path::EnumMessage for #name #ty_generics #where_clause {
+ fn get_message(&self) -> ::core::option::Option<&'static str> {
+ match self {
+ #(#arms),*
+ }
+ }
+
+ fn get_detailed_message(&self) -> ::core::option::Option<&'static str> {
+ match self {
+ #(#detailed_arms),*
+ }
+ }
+
+ fn get_documentation(&self) -> ::core::option::Option<&'static str> {
+ match self {
+ #(#documentation_arms),*
+ }
+ }
+
+ fn get_serializations(&self) -> &'static [&'static str] {
+ match self {
+ #(#serializations),*
+ }
+ }
+ }
+ })
+}
diff --git a/vendor/strum_macros/src/macros/enum_properties.rs b/vendor/strum_macros/src/macros/enum_properties.rs
new file mode 100644
index 000000000..0fe389eff
--- /dev/null
+++ b/vendor/strum_macros/src/macros/enum_properties.rs
@@ -0,0 +1,65 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{Data, DeriveInput, Fields};
+
+use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties};
+
+pub fn enum_properties_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
+ let name = &ast.ident;
+ let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
+ let variants = match &ast.data {
+ Data::Enum(v) => &v.variants,
+ _ => return Err(non_enum_error()),
+ };
+ let type_properties = ast.get_type_properties()?;
+ let strum_module_path = type_properties.crate_module_path();
+
+ let mut arms = Vec::new();
+ for variant in variants {
+ let ident = &variant.ident;
+ let variant_properties = variant.get_variant_properties()?;
+ let mut string_arms = Vec::new();
+ let mut bool_arms = Vec::new();
+ let mut num_arms = Vec::new();
+ // But you can disable the messages.
+ if variant_properties.disabled.is_some() {
+ continue;
+ }
+
+ let params = match variant.fields {
+ Fields::Unit => quote! {},
+ Fields::Unnamed(..) => quote! { (..) },
+ Fields::Named(..) => quote! { {..} },
+ };
+
+ for (key, value) in variant_properties.string_props {
+ string_arms.push(quote! { #key => ::core::option::Option::Some( #value )});
+ }
+
+ string_arms.push(quote! { _ => ::core::option::Option::None });
+ bool_arms.push(quote! { _ => ::core::option::Option::None });
+ num_arms.push(quote! { _ => ::core::option::Option::None });
+
+ arms.push(quote! {
+ &#name::#ident #params => {
+ match prop {
+ #(#string_arms),*
+ }
+ }
+ });
+ }
+
+ if arms.len() < variants.len() {
+ arms.push(quote! { _ => ::core::option::Option::None });
+ }
+
+ Ok(quote! {
+ impl #impl_generics #strum_module_path::EnumProperty for #name #ty_generics #where_clause {
+ fn get_str(&self, prop: &str) -> ::core::option::Option<&'static str> {
+ match self {
+ #(#arms),*
+ }
+ }
+ }
+ })
+}
diff --git a/vendor/strum_macros/src/macros/enum_variant_names.rs b/vendor/strum_macros/src/macros/enum_variant_names.rs
new file mode 100644
index 000000000..c54d45dc0
--- /dev/null
+++ b/vendor/strum_macros/src/macros/enum_variant_names.rs
@@ -0,0 +1,34 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{Data, DeriveInput};
+
+use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties};
+
+pub fn enum_variant_names_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
+ let name = &ast.ident;
+ let gen = &ast.generics;
+ let (impl_generics, ty_generics, where_clause) = gen.split_for_impl();
+
+ let variants = match &ast.data {
+ Data::Enum(v) => &v.variants,
+ _ => return Err(non_enum_error()),
+ };
+
+ // Derives for the generated enum
+ let type_properties = ast.get_type_properties()?;
+ let strum_module_path = type_properties.crate_module_path();
+
+ let names = variants
+ .iter()
+ .map(|v| {
+ let props = v.get_variant_properties()?;
+ Ok(props.get_preferred_name(type_properties.case_style))
+ })
+ .collect::<syn::Result<Vec<_>>>()?;
+
+ Ok(quote! {
+ impl #impl_generics #strum_module_path::VariantNames for #name #ty_generics #where_clause {
+ const VARIANTS: &'static [&'static str] = &[ #(#names),* ];
+ }
+ })
+}
diff --git a/vendor/strum_macros/src/macros/from_repr.rs b/vendor/strum_macros/src/macros/from_repr.rs
new file mode 100644
index 000000000..ec9f55779
--- /dev/null
+++ b/vendor/strum_macros/src/macros/from_repr.rs
@@ -0,0 +1,139 @@
+use heck::ToShoutySnakeCase;
+use proc_macro2::{Span, TokenStream};
+use quote::{format_ident, quote};
+use syn::{Data, DeriveInput, Fields, PathArguments, Type, TypeParen};
+
+use crate::helpers::{non_enum_error, HasStrumVariantProperties};
+
+pub fn from_repr_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
+ let name = &ast.ident;
+ let gen = &ast.generics;
+ let (impl_generics, ty_generics, where_clause) = gen.split_for_impl();
+ let vis = &ast.vis;
+ let attrs = &ast.attrs;
+
+ let mut discriminant_type: Type = syn::parse("usize".parse().unwrap()).unwrap();
+ for attr in attrs {
+ let path = &attr.path;
+ let tokens = &attr.tokens;
+ if path.leading_colon.is_some() {
+ continue;
+ }
+ if path.segments.len() != 1 {
+ continue;
+ }
+ let segment = path.segments.first().unwrap();
+ if segment.ident != "repr" {
+ continue;
+ }
+ if segment.arguments != PathArguments::None {
+ continue;
+ }
+ let typ_paren = match syn::parse2::<Type>(tokens.clone()) {
+ Ok(Type::Paren(TypeParen { elem, .. })) => *elem,
+ _ => continue,
+ };
+ let inner_path = match &typ_paren {
+ Type::Path(t) => t,
+ _ => continue,
+ };
+ if let Some(seg) = inner_path.path.segments.last() {
+ for t in &[
+ "u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "isize",
+ ] {
+ if seg.ident == t {
+ discriminant_type = typ_paren;
+ break;
+ }
+ }
+ }
+ }
+
+ if gen.lifetimes().count() > 0 {
+ return Err(syn::Error::new(
+ Span::call_site(),
+ "This macro doesn't support enums with lifetimes. \
+ The resulting enums would be unbounded.",
+ ));
+ }
+
+ let variants = match &ast.data {
+ Data::Enum(v) => &v.variants,
+ _ => return Err(non_enum_error()),
+ };
+
+ let mut arms = Vec::new();
+ let mut constant_defs = Vec::new();
+ let mut has_additional_data = false;
+ let mut prev_const_var_ident = None;
+ for variant in variants {
+ if variant.get_variant_properties()?.disabled.is_some() {
+ continue;
+ }
+
+ let ident = &variant.ident;
+ let params = match &variant.fields {
+ Fields::Unit => quote! {},
+ Fields::Unnamed(fields) => {
+ has_additional_data = true;
+ let defaults = ::core::iter::repeat(quote!(::core::default::Default::default()))
+ .take(fields.unnamed.len());
+ quote! { (#(#defaults),*) }
+ }
+ Fields::Named(fields) => {
+ has_additional_data = true;
+ let fields = fields
+ .named
+ .iter()
+ .map(|field| field.ident.as_ref().unwrap());
+ quote! { {#(#fields: ::core::default::Default::default()),*} }
+ }
+ };
+
+ let const_var_str = format!("{}_DISCRIMINANT", variant.ident).to_shouty_snake_case();
+ let const_var_ident = format_ident!("{}", const_var_str);
+
+ let const_val_expr = match &variant.discriminant {
+ Some((_, expr)) => quote! { #expr },
+ None => match &prev_const_var_ident {
+ Some(prev) => quote! { #prev + 1 },
+ None => quote! { 0 },
+ },
+ };
+
+ constant_defs.push(quote! {const #const_var_ident: #discriminant_type = #const_val_expr;});
+ arms.push(quote! {v if v == #const_var_ident => ::core::option::Option::Some(#name::#ident #params)});
+
+ prev_const_var_ident = Some(const_var_ident);
+ }
+
+ arms.push(quote! { _ => ::core::option::Option::None });
+
+ let const_if_possible = if has_additional_data {
+ quote! {}
+ } else {
+ #[rustversion::before(1.46)]
+ fn filter_by_rust_version(_: TokenStream) -> TokenStream {
+ quote! {}
+ }
+
+ #[rustversion::since(1.46)]
+ fn filter_by_rust_version(s: TokenStream) -> TokenStream {
+ s
+ }
+ filter_by_rust_version(quote! { const })
+ };
+
+ Ok(quote! {
+ #[allow(clippy::use_self)]
+ impl #impl_generics #name #ty_generics #where_clause {
+ #[doc = "Try to create [Self] from the raw representation"]
+ #vis #const_if_possible fn from_repr(discriminant: #discriminant_type) -> Option<#name #ty_generics> {
+ #(#constant_defs)*
+ match discriminant {
+ #(#arms),*
+ }
+ }
+ }
+ })
+}
diff --git a/vendor/strum_macros/src/macros/mod.rs b/vendor/strum_macros/src/macros/mod.rs
new file mode 100644
index 000000000..b4129697d
--- /dev/null
+++ b/vendor/strum_macros/src/macros/mod.rs
@@ -0,0 +1,14 @@
+pub mod enum_count;
+pub mod enum_discriminants;
+pub mod enum_iter;
+pub mod enum_messages;
+pub mod enum_properties;
+pub mod enum_variant_names;
+pub mod from_repr;
+
+mod strings;
+
+pub use self::strings::as_ref_str;
+pub use self::strings::display;
+pub use self::strings::from_string;
+pub use self::strings::to_string;
diff --git a/vendor/strum_macros/src/macros/strings/as_ref_str.rs b/vendor/strum_macros/src/macros/strings/as_ref_str.rs
new file mode 100644
index 000000000..4dfdc4b80
--- /dev/null
+++ b/vendor/strum_macros/src/macros/strings/as_ref_str.rs
@@ -0,0 +1,117 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{parse_quote, Data, DeriveInput, Fields};
+
+use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties};
+
+fn get_arms(ast: &DeriveInput) -> syn::Result<Vec<TokenStream>> {
+ let name = &ast.ident;
+ let mut arms = Vec::new();
+ let variants = match &ast.data {
+ Data::Enum(v) => &v.variants,
+ _ => return Err(non_enum_error()),
+ };
+
+ let type_properties = ast.get_type_properties()?;
+
+ for variant in variants {
+ let ident = &variant.ident;
+ let variant_properties = variant.get_variant_properties()?;
+
+ if variant_properties.disabled.is_some() {
+ continue;
+ }
+
+ // Look at all the serialize attributes.
+ // Use `to_string` attribute (not `as_ref_str` or something) to keep things consistent
+ // (i.e. always `enum.as_ref().to_string() == enum.to_string()`).
+ let output = variant_properties.get_preferred_name(type_properties.case_style);
+ let params = match variant.fields {
+ Fields::Unit => quote! {},
+ Fields::Unnamed(..) => quote! { (..) },
+ Fields::Named(..) => quote! { {..} },
+ };
+
+ arms.push(quote! { #name::#ident #params => #output });
+ }
+
+ if arms.len() < variants.len() {
+ arms.push(quote! {
+ _ => panic!(
+ "AsRef::<str>::as_ref() or AsStaticRef::<str>::as_static() \
+ called on disabled variant.",
+ )
+ });
+ }
+
+ Ok(arms)
+}
+
+pub fn as_ref_str_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
+ let name = &ast.ident;
+ let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
+ let arms = get_arms(ast)?;
+ Ok(quote! {
+ impl #impl_generics ::core::convert::AsRef<str> for #name #ty_generics #where_clause {
+ fn as_ref(&self) -> &str {
+ match *self {
+ #(#arms),*
+ }
+ }
+ }
+ })
+}
+
+pub enum GenerateTraitVariant {
+ AsStaticStr,
+ From,
+}
+
+pub fn as_static_str_inner(
+ ast: &DeriveInput,
+ trait_variant: &GenerateTraitVariant,
+) -> syn::Result<TokenStream> {
+ let name = &ast.ident;
+ let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
+ let arms = get_arms(ast)?;
+ let type_properties = ast.get_type_properties()?;
+ let strum_module_path = type_properties.crate_module_path();
+
+ let mut generics = ast.generics.clone();
+ generics
+ .params
+ .push(syn::GenericParam::Lifetime(syn::LifetimeDef::new(
+ parse_quote!('_derivative_strum),
+ )));
+ let (impl_generics2, _, _) = generics.split_for_impl();
+ let arms2 = arms.clone();
+ let arms3 = arms.clone();
+
+ Ok(match trait_variant {
+ GenerateTraitVariant::AsStaticStr => quote! {
+ impl #impl_generics #strum_module_path::AsStaticRef<str> for #name #ty_generics #where_clause {
+ fn as_static(&self) -> &'static str {
+ match *self {
+ #(#arms),*
+ }
+ }
+ }
+ },
+ GenerateTraitVariant::From => quote! {
+ impl #impl_generics ::core::convert::From<#name #ty_generics> for &'static str #where_clause {
+ fn from(x: #name #ty_generics) -> &'static str {
+ match x {
+ #(#arms2),*
+ }
+ }
+ }
+ impl #impl_generics2 ::core::convert::From<&'_derivative_strum #name #ty_generics> for &'static str #where_clause {
+ fn from(x: &'_derivative_strum #name #ty_generics) -> &'static str {
+ match *x {
+ #(#arms3),*
+ }
+ }
+ }
+ },
+ })
+}
diff --git a/vendor/strum_macros/src/macros/strings/display.rs b/vendor/strum_macros/src/macros/strings/display.rs
new file mode 100644
index 000000000..82a34b0df
--- /dev/null
+++ b/vendor/strum_macros/src/macros/strings/display.rs
@@ -0,0 +1,51 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{Data, DeriveInput, Fields};
+
+use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties};
+
+pub fn display_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
+ let name = &ast.ident;
+ let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
+ let variants = match &ast.data {
+ Data::Enum(v) => &v.variants,
+ _ => return Err(non_enum_error()),
+ };
+
+ let type_properties = ast.get_type_properties()?;
+
+ let mut arms = Vec::new();
+ for variant in variants {
+ let ident = &variant.ident;
+ let variant_properties = variant.get_variant_properties()?;
+
+ if variant_properties.disabled.is_some() {
+ continue;
+ }
+
+ // Look at all the serialize attributes.
+ let output = variant_properties.get_preferred_name(type_properties.case_style);
+
+ let params = match variant.fields {
+ Fields::Unit => quote! {},
+ Fields::Unnamed(..) => quote! { (..) },
+ Fields::Named(..) => quote! { {..} },
+ };
+
+ arms.push(quote! { #name::#ident #params => f.pad(#output) });
+ }
+
+ if arms.len() < variants.len() {
+ arms.push(quote! { _ => panic!("fmt() called on disabled variant.") });
+ }
+
+ Ok(quote! {
+ impl #impl_generics ::core::fmt::Display for #name #ty_generics #where_clause {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::result::Result<(), ::core::fmt::Error> {
+ match *self {
+ #(#arms),*
+ }
+ }
+ }
+ })
+}
diff --git a/vendor/strum_macros/src/macros/strings/from_string.rs b/vendor/strum_macros/src/macros/strings/from_string.rs
new file mode 100644
index 000000000..2d2559174
--- /dev/null
+++ b/vendor/strum_macros/src/macros/strings/from_string.rs
@@ -0,0 +1,180 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{Data, DeriveInput, Fields};
+
+use crate::helpers::{
+ non_enum_error, occurrence_error, HasStrumVariantProperties, HasTypeProperties,
+};
+
+pub fn from_string_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
+ let name = &ast.ident;
+ let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
+ let variants = match &ast.data {
+ Data::Enum(v) => &v.variants,
+ _ => return Err(non_enum_error()),
+ };
+
+ let type_properties = ast.get_type_properties()?;
+ let strum_module_path = type_properties.crate_module_path();
+
+ let mut default_kw = None;
+ let mut default =
+ quote! { ::core::result::Result::Err(#strum_module_path::ParseError::VariantNotFound) };
+
+ let mut phf_exact_match_arms = Vec::new();
+ let mut standard_match_arms = Vec::new();
+ for variant in variants {
+ let ident = &variant.ident;
+ let variant_properties = variant.get_variant_properties()?;
+
+ if variant_properties.disabled.is_some() {
+ continue;
+ }
+
+ if let Some(kw) = variant_properties.default {
+ if let Some(fst_kw) = default_kw {
+ return Err(occurrence_error(fst_kw, kw, "default"));
+ }
+
+ match &variant.fields {
+ Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {}
+ _ => {
+ return Err(syn::Error::new_spanned(
+ variant,
+ "Default only works on newtype structs with a single String field",
+ ))
+ }
+ }
+
+ default_kw = Some(kw);
+ default = quote! {
+ ::core::result::Result::Ok(#name::#ident(s.into()))
+ };
+ continue;
+ }
+
+ let params = match &variant.fields {
+ Fields::Unit => quote! {},
+ Fields::Unnamed(fields) => {
+ let defaults =
+ ::core::iter::repeat(quote!(Default::default())).take(fields.unnamed.len());
+ quote! { (#(#defaults),*) }
+ }
+ Fields::Named(fields) => {
+ let fields = fields
+ .named
+ .iter()
+ .map(|field| field.ident.as_ref().unwrap());
+ quote! { {#(#fields: Default::default()),*} }
+ }
+ };
+
+ let is_ascii_case_insensitive = variant_properties
+ .ascii_case_insensitive
+ .unwrap_or(type_properties.ascii_case_insensitive);
+
+ // If we don't have any custom variants, add the default serialized name.
+ for serialization in variant_properties.get_serializations(type_properties.case_style) {
+ if type_properties.use_phf {
+ phf_exact_match_arms.push(quote! { #serialization => #name::#ident #params, });
+
+ if is_ascii_case_insensitive {
+ // Store the lowercase and UPPERCASE variants in the phf map to capture
+ let ser_string = serialization.value();
+
+ let lower =
+ syn::LitStr::new(&ser_string.to_ascii_lowercase(), serialization.span());
+ let upper =
+ syn::LitStr::new(&ser_string.to_ascii_uppercase(), serialization.span());
+ phf_exact_match_arms.push(quote! { #lower => #name::#ident #params, });
+ phf_exact_match_arms.push(quote! { #upper => #name::#ident #params, });
+ standard_match_arms.push(quote! { s if s.eq_ignore_ascii_case(#serialization) => #name::#ident #params, });
+ }
+ } else {
+ standard_match_arms.push(if !is_ascii_case_insensitive {
+ quote! { #serialization => #name::#ident #params, }
+ } else {
+ quote! { s if s.eq_ignore_ascii_case(#serialization) => #name::#ident #params, }
+ });
+ }
+ }
+ }
+
+ let phf_body = if phf_exact_match_arms.is_empty() {
+ quote!()
+ } else {
+ quote! {
+ use #strum_module_path::_private_phf_reexport_for_macro_if_phf_feature as phf;
+ static PHF: phf::Map<&'static str, #name> = phf::phf_map! {
+ #(#phf_exact_match_arms)*
+ };
+ if let Some(value) = PHF.get(s).cloned() {
+ return ::core::result::Result::Ok(value);
+ }
+ }
+ };
+ let standard_match_body = if standard_match_arms.is_empty() {
+ default
+ } else {
+ quote! {
+ ::core::result::Result::Ok(match s {
+ #(#standard_match_arms)*
+ _ => return #default,
+ })
+ }
+ };
+
+ let from_str = quote! {
+ #[allow(clippy::use_self)]
+ impl #impl_generics ::core::str::FromStr for #name #ty_generics #where_clause {
+ type Err = #strum_module_path::ParseError;
+ fn from_str(s: &str) -> ::core::result::Result< #name #ty_generics , <Self as ::core::str::FromStr>::Err> {
+ #phf_body
+ #standard_match_body
+ }
+ }
+ };
+
+ let try_from_str = try_from_str(
+ name,
+ &impl_generics,
+ &ty_generics,
+ where_clause,
+ &strum_module_path,
+ );
+
+ Ok(quote! {
+ #from_str
+ #try_from_str
+ })
+}
+
+#[rustversion::before(1.34)]
+fn try_from_str(
+ _name: &proc_macro2::Ident,
+ _impl_generics: &syn::ImplGenerics,
+ _ty_generics: &syn::TypeGenerics,
+ _where_clause: Option<&syn::WhereClause>,
+ _strum_module_path: &syn::Path,
+) -> TokenStream {
+ Default::default()
+}
+
+#[rustversion::since(1.34)]
+fn try_from_str(
+ name: &proc_macro2::Ident,
+ impl_generics: &syn::ImplGenerics,
+ ty_generics: &syn::TypeGenerics,
+ where_clause: Option<&syn::WhereClause>,
+ strum_module_path: &syn::Path,
+) -> TokenStream {
+ quote! {
+ #[allow(clippy::use_self)]
+ impl #impl_generics ::core::convert::TryFrom<&str> for #name #ty_generics #where_clause {
+ type Error = #strum_module_path::ParseError;
+ fn try_from(s: &str) -> ::core::result::Result< #name #ty_generics , <Self as ::core::convert::TryFrom<&str>>::Error> {
+ ::core::str::FromStr::from_str(s)
+ }
+ }
+ }
+}
diff --git a/vendor/strum_macros/src/macros/strings/mod.rs b/vendor/strum_macros/src/macros/strings/mod.rs
new file mode 100644
index 000000000..e416f4b3b
--- /dev/null
+++ b/vendor/strum_macros/src/macros/strings/mod.rs
@@ -0,0 +1,4 @@
+pub mod as_ref_str;
+pub mod display;
+pub mod from_string;
+pub mod to_string;
diff --git a/vendor/strum_macros/src/macros/strings/to_string.rs b/vendor/strum_macros/src/macros/strings/to_string.rs
new file mode 100644
index 000000000..7e4c48380
--- /dev/null
+++ b/vendor/strum_macros/src/macros/strings/to_string.rs
@@ -0,0 +1,51 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{Data, DeriveInput, Fields};
+
+use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties};
+
+pub fn to_string_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
+ let name = &ast.ident;
+ let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
+ let variants = match &ast.data {
+ Data::Enum(v) => &v.variants,
+ _ => return Err(non_enum_error()),
+ };
+
+ let type_properties = ast.get_type_properties()?;
+ let mut arms = Vec::new();
+ for variant in variants {
+ let ident = &variant.ident;
+ let variant_properties = variant.get_variant_properties()?;
+
+ if variant_properties.disabled.is_some() {
+ continue;
+ }
+
+ // Look at all the serialize attributes.
+ let output = variant_properties.get_preferred_name(type_properties.case_style);
+
+ let params = match variant.fields {
+ Fields::Unit => quote! {},
+ Fields::Unnamed(..) => quote! { (..) },
+ Fields::Named(..) => quote! { {..} },
+ };
+
+ arms.push(quote! { #name::#ident #params => ::std::string::String::from(#output) });
+ }
+
+ if arms.len() < variants.len() {
+ arms.push(quote! { _ => panic!("to_string() called on disabled variant.") });
+ }
+
+ Ok(quote! {
+ #[allow(clippy::use_self)]
+ impl #impl_generics ::std::string::ToString for #name #ty_generics #where_clause {
+ fn to_string(&self) -> ::std::string::String {
+ match *self {
+ #(#arms),*
+ }
+ }
+ }
+ })
+}