-
Notifications
You must be signed in to change notification settings - Fork 141
Support for custom error type in TryInto
derive
#503
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
0dd85d9
to
83d7694
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TryInto
derive supports[#try_into(owned, ref, ref_mut)]
attributes which are handled byState::with_attr_params
.
This works. However, this leads to the error message being unhelpful in cases like this
A very dirty hack could be used after parsing State::with_attr_params()
, like: checking the returned error message and putting the better one. Covering this with test will ensure no regression is happened if the error from State::with_attr_params()
is changed accidentally.
Not an optimal solution, of course, but does the job, until handling owned
/ref
/ref_mut
is refactored with the new utils::attr
machinery.
- The PR currently works if the custom error is non-generic
I think this could easily be supported like this:
struct CustomError<T>(TryIntoError<T>);
impl<T> From<TryIntoError<T>> for CustomError<T> {
fn from(value: TryIntoError<T>) -> Self {
Self(value)
}
}
impl<T> CustomError<T> {
fn new(err: TryIntoError<T>) -> Self {
Self(err)
}
}
fn into_custom_err<T>(err: TryIntoError<T>) -> CustomError<T> {
err.into()
}
#[derive(TryInto)]
#[try_into(ref)]
#[try_into(error::<T>(CustomError<T>))]
// or
#[try_into(error::<T>(CustomError<T>, CustomError<T>::new))]
// or
#[try_into(error::<T>(CustomError<T>, into_custom_err<T>))]
enum MixedInts {
SmallInt(i32),
NamedBigInt { int: i64 },
}
where T
, of course, would be substituted with the appropriate type, like it's done for derive_more::TryIntoError
in the expansion.
This requires a slight extension of the attr::Error
machinery. Note, that this behavior should be controlled, in a way that error::<T>
is not allowed for derive(FromStr)
at all. Maybe, parametrizing attr::Error
with behaviour marker will do the trick:
pub(crate) struct Error<const GENERICS: bool = false> {
// ...
}
/// [`Error`] attribute with type parameters support (e.g. `error::<T>(...)`).
pub(crate) type ErrorGeneric = Error<true>;
And so, derive(TryInto)
will use attr::ErrorGeneric
, while derive(FromStr)
will continue to use attr::Error
which disallows using error::<T>
syntax.
Thanks for the detailed response @tyranron!
Ah yes this would work.
This would work. My concern is if this syntax is too specific to this use case. I'm not sure how useful or common this use case of having a custom error parametrized on #[try_into(error::<T>(CustomError<T>, into_custom_err<T>))]
enum MixedInts {
SmallInt(i32),
NamedBigInt { int: i64 },
} it's a bit unclear what |
We don't even have to support that use case now, though. We can support only non-generic error type now. Extending the syntax to |
Well, the point is:
So, overall, you don't use weird syntax if you don't have to.
That's what documentation is for!
I'm OK with not supporting it at all! Only giving suggestions how we could solve this if we want to! |
Yup I agree. Let's support just the simple non-generic case for this PR. Still, I gave much thought to the syntax for the generic case so I'll just put it down here anw.
I agree with this. The most appropriate syntax for this case would probably look like what you proposed,
Originally, I thought of something like enum MixedInts {
SmallInt(i32),
NamedBigInt { int: i64 },
Unit
} the error type for the Maybe |
@kiendang okay, so let's roll out the solution without generics first and only support them if there will be enough demand for them. As I've mentioned above, caveats regarding generics should be mentioned in docs. |
Resolves #396
Synopsis
Add support for specifying a custom error type for
TryInto
derive via a#[try_into(error(error_ty[, error_fn]))]
attribute similarly to #494 forFromStr
.However there are a couple of issues that need clarifying
TryInto
derive supports[#try_into(owned, ref, ref_mut)]
attributes which are handled byState::with_attr_params
. To add support for the error attribute, I took the approach that requires less amount of code change: find the attributes ininput.attrs
that follow the[#try_into(error
pattern, parse them withattr::Error
for the custom error support. These attributes are also taken out ofinput.attrs
before theState::with_attr_params
call, leaving the rest of theTryInto
derive code unchanged. This works. However, this leads to the error message being unhelpful in cases like this"Only 1
[#try_into(owned, ref, ref_mut)]
and 1#[try_into(error(...))]
attribute allowed" would be more helpful.The PR currently works if the custom error is non-generic, e.g
struct CustomError(String)
(see the added test for a working example). However, in this casethere is a problem with specifying the type for
ref
andref_mut
.Another thing is suppose we want to derive for all 3
owned
,ref
andref_mut
, the custom error types might be different for each of them. The syntax can be extended to#[try_into(error(owned(...), ref(...), ref_mut(...)))]
to accommodate this, but the issue above needs solving first.Solution
Checklist