From 94d7a45672825c916bfd5425b1703a0db1a822a5 Mon Sep 17 00:00:00 2001 From: bogay Date: Fri, 14 Oct 2022 04:31:32 +0800 Subject: [PATCH] feat(FromVariant): allow derived by uninhabitable enums --- gdnative-derive/src/variant/from.rs | 94 +++++++++++++++-------------- gdnative-derive/src/variant/mod.rs | 14 +++++ test/src/test_derive.rs | 14 +++++ 3 files changed, 76 insertions(+), 46 deletions(-) diff --git a/gdnative-derive/src/variant/from.rs b/gdnative-derive/src/variant/from.rs index a726ff737..6fc84a1b8 100644 --- a/gdnative-derive/src/variant/from.rs +++ b/gdnative-derive/src/variant/from.rs @@ -30,13 +30,6 @@ pub(crate) fn expand_from_variant(derive_data: DeriveData) -> Result { - if variants.is_empty() { - return Err(syn::Error::new( - ident.span(), - "cannot derive FromVariant for an uninhabited enum", - )); - } - let var_input_ident = Ident::new("__enum_variant", Span::call_site()); let var_ident_strings: Vec = variants @@ -61,46 +54,55 @@ pub(crate) fn expand_from_variant(derive_data: DeriveData) -> Result { - let #var_input_ident_iter = &__dict.get_or_nil(&__keys.get(0)); - (#var_from_variants).map_err(|err| FVE::InvalidEnumVariant { - variant: #ref_var_ident_string_literals, - error: std::boxed::Box::new(err), - }) - }, - )* - variant => Err(FVE::UnknownEnumVariant { - variant: variant.to_string(), - expected: &[#(#ref_var_ident_string_literals),*], - }), - } - } + let __dict = ::gdnative::core_types::Dictionary::from_variant(#input_ident) + .map_err(|__err| FVE::InvalidEnumRepr { + expected: VariantEnumRepr::ExternallyTagged, + error: std::boxed::Box::new(__err), + })?; + let __keys = __dict.keys(); + if __keys.len() != 1 { + return Err(FVE::InvalidEnumRepr { + expected: VariantEnumRepr::ExternallyTagged, + error: std::boxed::Box::new(FVE::InvalidLength { + expected: 1, + len: __keys.len() as usize, + }), + }) + } + + let __key = String::from_variant(&__keys.get(0)) + .map_err(|__err| FVE::InvalidEnumRepr { + expected: VariantEnumRepr::ExternallyTagged, + error: std::boxed::Box::new(__err), + })?; + + #early_return + + match __key.as_str() { + #( + #ref_var_ident_string_literals => { + let #var_input_ident_iter = &__dict.get_or_nil(&__keys.get(0)); + (#var_from_variants).map_err(|err| FVE::InvalidEnumVariant { + variant: #ref_var_ident_string_literals, + error: std::boxed::Box::new(err), + }) + }, + )* + variant => Err(FVE::UnknownEnumVariant { + variant: variant.to_string(), + expected: &[#(#ref_var_ident_string_literals),*], + }), } } } diff --git a/gdnative-derive/src/variant/mod.rs b/gdnative-derive/src/variant/mod.rs index d98422d38..0f56e3048 100644 --- a/gdnative-derive/src/variant/mod.rs +++ b/gdnative-derive/src/variant/mod.rs @@ -107,3 +107,17 @@ pub(crate) fn derive_from_variant(derive_input: DeriveInput) -> Result(1, 0, false)), ToVarTuple::from_variant(&variant) ); + + // Derive on uninhabitable enum results an error + #[derive(Debug, PartialEq, FromVariant)] + enum NoVariant {} + + let input = HashMap::from_iter([("foo", "bar")]).to_variant(); + assert_eq!( + NoVariant::from_variant(&input), + Err(FromVariantError::UnknownEnumVariant { + variant: "foo".into(), + expected: &[] + }) + ); }} // ----------------------------------------------------------------------------------------------------------------------------------------------