From f5712b692564f93b38c4bd8a23ad9f379338479b Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Mon, 14 Nov 2022 14:31:42 +0100 Subject: [PATCH] Create a TryIntoError type Instead of returning a string as the error, this returns a dedicated error type. This has the big benefit that in case of an error it's possible to get back the original value by using `error.input`. Previously the original value would be dropped in case of an error. Fixes #173 Fixes #130 --- impl/src/try_into.rs | 6 +- src/lib.rs | 3 + tests/try_into.rs | 176 ++++++++++++++++++++++--------------------- 3 files changed, 95 insertions(+), 90 deletions(-) diff --git a/impl/src/try_into.rs b/impl/src/try_into.rs index b571cc81..4c1f95c4 100644 --- a/impl/src/try_into.rs +++ b/impl/src/try_into.rs @@ -89,8 +89,6 @@ pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result>() .join(", "); - let message = - format!("Only {} can be converted to {}", variant_names, output_type); let generics_impl; let (_, ty_generics, where_clause) = input.generics.split_for_impl(); @@ -108,13 +106,13 @@ pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result; #[inline] fn try_from(value: #reference_with_lifetime #input_type #ty_generics) -> ::core::result::Result { match value { #(#matchers)|* => ::core::result::Result::Ok(#vars), - _ => ::core::result::Result::Err(#message), + _ => ::core::result::Result::Err(::derive_more::TryIntoError::new(value, #variant_names, #output_type)), } } } diff --git a/src/lib.rs b/src/lib.rs index 9e51ac99..3228f446 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,3 +32,6 @@ #[doc(inline)] pub use derive_more_impl::*; + +mod errors; +pub use crate::errors::TryIntoError; diff --git a/tests/try_into.rs b/tests/try_into.rs index e9354426..a4f03653 100644 --- a/tests/try_into.rs +++ b/tests/try_into.rs @@ -6,7 +6,7 @@ use derive_more::TryInto; // has been redefined. type Result = (); -#[derive(Clone, Copy, TryInto)] +#[derive(Clone, Copy, Eq, PartialEq, Debug, TryInto)] #[try_into(owned, ref, ref_mut)] enum MixedInts { SmallInt(i32), @@ -36,161 +36,165 @@ enum MixedInts { #[test] fn test_try_into() { let mut i = MixedInts::SmallInt(42); - assert_eq!(Ok(42i32), i.try_into()); - assert_eq!(Ok(&42i32), (&i).try_into()); - assert_eq!(Ok(&mut 42i32), (&mut i).try_into()); + assert_eq!(42i32, i.try_into().unwrap()); + assert_eq!(&42i32, <_ as TryInto<&i32>>::try_into(&i).unwrap()); + assert_eq!(&mut 42i32, <_ as TryInto<&mut i32>>::try_into(&mut i).unwrap()); assert_eq!( - i64::try_from(i), - Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64") + i64::try_from(i).unwrap_err().to_string(), + "Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64" ); assert_eq!( - <(i32, i32)>::try_from(i), - Err("Only TwoSmallInts can be converted to (i32, i32)") + i64::try_from(i).unwrap_err().input, + MixedInts::SmallInt(42) ); assert_eq!( - <(i64, i64)>::try_from(i), - Err("Only NamedBigInts can be converted to (i64, i64)") + <(i32, i32)>::try_from(i).unwrap_err().to_string(), + "Only TwoSmallInts can be converted to (i32, i32)" ); assert_eq!( - u32::try_from(i), - Err("Only Unsigned, NamedUnsigned can be converted to u32") + <(i64, i64)>::try_from(i).unwrap_err().to_string(), + "Only NamedBigInts can be converted to (i64, i64)" ); - assert_eq!(<()>::try_from(i), Err("Only Unit can be converted to ()")); + assert_eq!( + u32::try_from(i).unwrap_err().to_string(), + "Only Unsigned, NamedUnsigned can be converted to u32" + ); + assert_eq!(<()>::try_from(i).unwrap_err().to_string(), "Only Unit can be converted to ()"); let mut i = MixedInts::NamedBigInt { int: 42 }; assert_eq!( - i32::try_from(i), - Err("Only SmallInt can be converted to i32") + i32::try_from(i).unwrap_err().to_string(), + "Only SmallInt can be converted to i32" ); - assert_eq!(Ok(42i64), i.try_into()); - assert_eq!(Ok(&42i64), (&i).try_into()); - assert_eq!(Ok(&mut 42i64), (&mut i).try_into()); + assert_eq!(42i64, i.try_into().unwrap()); + assert_eq!(&42i64, <_ as TryInto<&i64>>::try_into(&i).unwrap()); + assert_eq!(&mut 42i64, <_ as TryInto<&mut i64>>::try_into(&mut i).unwrap()); assert_eq!( - <(i32, i32)>::try_from(i), - Err("Only TwoSmallInts can be converted to (i32, i32)") + <(i32, i32)>::try_from(i).unwrap_err().to_string(), + "Only TwoSmallInts can be converted to (i32, i32)" ); assert_eq!( - <(i64, i64)>::try_from(i), - Err("Only NamedBigInts can be converted to (i64, i64)") + <(i64, i64)>::try_from(i).unwrap_err().to_string(), + "Only NamedBigInts can be converted to (i64, i64)" ); assert_eq!( - u32::try_from(i), - Err("Only Unsigned, NamedUnsigned can be converted to u32") + u32::try_from(i).unwrap_err().to_string(), + "Only Unsigned, NamedUnsigned can be converted to u32" ); - assert_eq!(<()>::try_from(i), Err("Only Unit can be converted to ()")); + assert_eq!(<()>::try_from(i).unwrap_err().to_string(), "Only Unit can be converted to ()"); let mut i = MixedInts::TwoSmallInts(42, 64); assert_eq!( - i32::try_from(i), - Err("Only SmallInt can be converted to i32") + i32::try_from(i).unwrap_err().to_string(), + "Only SmallInt can be converted to i32" ); assert_eq!( - i64::try_from(i), - Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64") + i64::try_from(i).unwrap_err().to_string(), + "Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64" ); - assert_eq!(Ok((42i32, 64i32)), i.try_into()); - assert_eq!(Ok((&42i32, &64i32)), (&i).try_into()); - assert_eq!(Ok((&mut 42i32, &mut 64i32)), (&mut i).try_into()); + assert_eq!((42i32, 64i32), i.try_into().unwrap()); + assert_eq!((&42i32, &64i32), (&i).try_into().unwrap()); + assert_eq!((&mut 42i32, &mut 64i32), (&mut i).try_into().unwrap()); assert_eq!( - <(i64, i64)>::try_from(i), - Err("Only NamedBigInts can be converted to (i64, i64)") + <(i64, i64)>::try_from(i).unwrap_err().to_string(), + "Only NamedBigInts can be converted to (i64, i64)" ); assert_eq!( - u32::try_from(i), - Err("Only Unsigned, NamedUnsigned can be converted to u32") + u32::try_from(i).unwrap_err().to_string(), + "Only Unsigned, NamedUnsigned can be converted to u32" ); - assert_eq!(<()>::try_from(i), Err("Only Unit can be converted to ()")); + assert_eq!(<()>::try_from(i).unwrap_err().to_string(), "Only Unit can be converted to ()"); let mut i = MixedInts::NamedBigInts { x: 42, y: 64 }; assert_eq!( - i32::try_from(i), - Err("Only SmallInt can be converted to i32") + i32::try_from(i).unwrap_err().to_string(), + "Only SmallInt can be converted to i32" ); assert_eq!( - i64::try_from(i), - Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64") + i64::try_from(i).unwrap_err().to_string(), + "Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64" ); assert_eq!( - <(i32, i32)>::try_from(i), - Err("Only TwoSmallInts can be converted to (i32, i32)") + <(i32, i32)>::try_from(i).unwrap_err().to_string(), + "Only TwoSmallInts can be converted to (i32, i32)" ); - assert_eq!(Ok((42i64, 64i64)), i.try_into()); - assert_eq!(Ok((&42i64, &64i64)), (&i).try_into()); - assert_eq!(Ok((&mut 42i64, &mut 64i64)), (&mut i).try_into()); + assert_eq!((42i64, 64i64), i.try_into().unwrap()); + assert_eq!((&42i64, &64i64), (&i).try_into().unwrap()); + assert_eq!((&mut 42i64, &mut 64i64), (&mut i).try_into().unwrap()); assert_eq!( - u32::try_from(i), - Err("Only Unsigned, NamedUnsigned can be converted to u32") + u32::try_from(i).unwrap_err().to_string(), + "Only Unsigned, NamedUnsigned can be converted to u32" ); - assert_eq!(<()>::try_from(i), Err("Only Unit can be converted to ()")); + assert_eq!(<()>::try_from(i).unwrap_err().to_string(), "Only Unit can be converted to ()"); let mut i = MixedInts::Unsigned(42); assert_eq!( - i32::try_from(i), - Err("Only SmallInt can be converted to i32") + i32::try_from(i).unwrap_err().to_string(), + "Only SmallInt can be converted to i32" ); assert_eq!( - i64::try_from(i), - Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64") + i64::try_from(i).unwrap_err().to_string(), + "Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64" ); assert_eq!( - <(i32, i32)>::try_from(i), - Err("Only TwoSmallInts can be converted to (i32, i32)") + <(i32, i32)>::try_from(i).unwrap_err().to_string(), + "Only TwoSmallInts can be converted to (i32, i32)" ); assert_eq!( - <(i64, i64)>::try_from(i), - Err("Only NamedBigInts can be converted to (i64, i64)") + <(i64, i64)>::try_from(i).unwrap_err().to_string(), + "Only NamedBigInts can be converted to (i64, i64)" ); - assert_eq!(Ok(42u32), i.try_into()); - assert_eq!(Ok(&42u32), (&i).try_into()); - assert_eq!(Ok(&mut 42u32), (&mut i).try_into()); - assert_eq!(<()>::try_from(i), Err("Only Unit can be converted to ()")); + assert_eq!(42u32, i.try_into().unwrap()); + assert_eq!(&42u32, <_ as TryInto<&u32>>::try_into(&i).unwrap()); + assert_eq!(&mut 42u32, <_ as TryInto<&mut u32>>::try_into(&mut i).unwrap()); + assert_eq!(<()>::try_from(i).unwrap_err().to_string(), "Only Unit can be converted to ()"); let mut i = MixedInts::NamedUnsigned { x: 42 }; assert_eq!( - i32::try_from(i), - Err("Only SmallInt can be converted to i32") + i32::try_from(i).unwrap_err().to_string(), + "Only SmallInt can be converted to i32" ); assert_eq!( - i64::try_from(i), - Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64") + i64::try_from(i).unwrap_err().to_string(), + "Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64" ); assert_eq!( - i64::try_from(i), - Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64") + i64::try_from(i).unwrap_err().to_string(), + "Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64" ); assert_eq!( - <(i32, i32)>::try_from(i), - Err("Only TwoSmallInts can be converted to (i32, i32)") + <(i32, i32)>::try_from(i).unwrap_err().to_string(), + "Only TwoSmallInts can be converted to (i32, i32)" ); assert_eq!( - <(i64, i64)>::try_from(i), - Err("Only NamedBigInts can be converted to (i64, i64)") + <(i64, i64)>::try_from(i).unwrap_err().to_string(), + "Only NamedBigInts can be converted to (i64, i64)" ); - assert_eq!(Ok(42u32), i.try_into()); - assert_eq!(Ok(&42u32), (&i).try_into()); - assert_eq!(Ok(&mut 42u32), (&mut i).try_into()); - assert_eq!(<()>::try_from(i), Err("Only Unit can be converted to ()")); + assert_eq!(42u32, i.try_into().unwrap()); + assert_eq!(&42u32, <_ as TryInto<&u32>>::try_into(&i).unwrap()); + assert_eq!(&mut 42u32, <_ as TryInto<&mut u32>>::try_into(&mut i).unwrap()); + assert_eq!(<()>::try_from(i).unwrap_err().to_string(), "Only Unit can be converted to ()"); let i = MixedInts::Unit; assert_eq!( - i32::try_from(i), - Err("Only SmallInt can be converted to i32") + i32::try_from(i).unwrap_err().to_string(), + "Only SmallInt can be converted to i32" ); assert_eq!( - i64::try_from(i), - Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64") + i64::try_from(i).unwrap_err().to_string(), + "Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64" ); assert_eq!( - <(i32, i32)>::try_from(i), - Err("Only TwoSmallInts can be converted to (i32, i32)") + <(i32, i32)>::try_from(i).unwrap_err().to_string(), + "Only TwoSmallInts can be converted to (i32, i32)" ); assert_eq!( - <(i64, i64)>::try_from(i), - Err("Only NamedBigInts can be converted to (i64, i64)") + <(i64, i64)>::try_from(i).unwrap_err().to_string(), + "Only NamedBigInts can be converted to (i64, i64)" ); assert_eq!( - u32::try_from(i), - Err("Only Unsigned, NamedUnsigned can be converted to u32") + u32::try_from(i).unwrap_err().to_string(), + "Only Unsigned, NamedUnsigned can be converted to u32" ); - assert_eq!(Ok(()), i.try_into()); + assert_eq!((), i.try_into().unwrap()); }