Skip to content

Commit 0ccbbf8

Browse files
authored
Honor parse_err_ty attribute when the enum has a default variant (#431)
* Honor parse_err_ty attribute when the enum has a default variant * fix confusing variable name
1 parent 2c9e5a9 commit 0ccbbf8

3 files changed

Lines changed: 38 additions & 9 deletions

File tree

strum_macros/src/lib.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,15 @@ fn debug_print_generated(ast: &DeriveInput, toks: &TokenStream) {
5858
/// can be very fast for enums with a surprisingly large number of enum variants.
5959
///
6060
/// The default error type is `strum::ParseError`. This can be overriden by applying both the
61-
/// `parse_err_ty` and `parse_err_fn` attributes at the type level. `parse_error_fn` should be a
62-
/// function that accepts an `&str` and returns the type `parse_error_ty`. See
63-
/// [this test case](https://github.com/Peternator7/strum/blob/9db3c4dc9b6f585aeb9f5f15f9cc18b6cf4fd780/strum_tests/tests/from_str.rs#L233)
61+
/// `parse_err_ty` and `parse_err_fn` attributes at the type level. `parse_err_fn` should be a
62+
/// function that accepts an `&str` and returns the type `parse_err_ty`. See [this test
63+
/// case](https://github.com/Peternator7/strum/blob/9db3c4dc9b6f585aeb9f5f15f9cc18b6cf4fd780/strum_tests/tests/from_str.rs#L233)
6464
/// for an example.
6565
///
66+
/// If the enum has a default variant (annotated with `#[strum(default)]`), then parsing is
67+
/// infallible. In that case, `parse_err_fn` need not exist (it will never be called) and
68+
/// `parse_err_ty` can be safely set to [`std::convert::Infallible`].
69+
///
6670
/// # Example how to use `EnumString`
6771
/// ```
6872
/// use std::str::FromStr;

strum_macros/src/macros/strings/from_string.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub fn from_string_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
1919
let strum_module_path = type_properties.crate_module_path();
2020

2121
let mut default_kw = None;
22-
let (mut default_err_ty, mut default) = match (
22+
let (default_err_ty, mut default_match_arm) = match (
2323
type_properties.parse_err_ty,
2424
type_properties.parse_err_fn,
2525
) {
@@ -54,17 +54,16 @@ pub fn from_string_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
5454
}
5555

5656
default_kw = Some(kw);
57-
default_err_ty = quote! { #strum_module_path::ParseError };
5857

5958
match &variant.fields {
6059
Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
61-
default = quote! {
60+
default_match_arm = quote! {
6261
::core::result::Result::Ok(#name::#ident(s.into()))
6362
};
6463
}
6564
Fields::Named(ref f) if f.named.len() == 1 => {
6665
let field_name = f.named.last().unwrap().ident.as_ref().unwrap();
67-
default = quote! {
66+
default_match_arm = quote! {
6867
::core::result::Result::Ok(#name::#ident { #field_name : s.into() } )
6968
};
7069
}
@@ -159,12 +158,12 @@ pub fn from_string_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
159158
};
160159

161160
let standard_match_body = if standard_match_arms.is_empty() {
162-
default
161+
default_match_arm
163162
} else {
164163
quote! {
165164
::core::result::Result::Ok(match s {
166165
#(#standard_match_arms)*
167-
_ => return #default,
166+
_ => return #default_match_arm,
168167
})
169168
}
170169
};

strum_tests/tests/from_str.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,3 +274,29 @@ fn case_custom_parse_error() {
274274
r.unwrap_err()
275275
);
276276
}
277+
278+
#[derive(Debug, EnumString, Eq, PartialEq)]
279+
#[strum(
280+
parse_err_fn = not_needed_parsing_is_infallible,
281+
parse_err_ty = std::convert::Infallible
282+
)]
283+
enum CaseCustomInfallibleParsingWithDefaultEnum {
284+
#[strum(serialize = "foo")]
285+
Foo,
286+
#[strum(serialize = "bar")]
287+
Bar,
288+
#[strum(default)]
289+
Unknown(String),
290+
}
291+
292+
#[test]
293+
fn case_custom_infallible_parsing_with_default() {
294+
let r = match "yellow".parse::<CaseCustomInfallibleParsingWithDefaultEnum>() {
295+
Ok(r) => r,
296+
Err(never) => match never {},
297+
};
298+
assert_eq!(
299+
CaseCustomInfallibleParsingWithDefaultEnum::Unknown("yellow".to_string()),
300+
r
301+
);
302+
}

0 commit comments

Comments
 (0)