-
Notifications
You must be signed in to change notification settings - Fork 143
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
Conversation
0dd85d9 to
83d7694
Compare
tyranron
left a comment
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.
TryIntoderive 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. |
|
@tyranron sorry for the delay. The failed CI seems unrelated. I submitted #508 to fix. I've added to doc and adjusted the error message as suggested
I want to adjust the message for this error as well, but I can't seem to be able to trigger it. Looks like both Line 858 in e0a0713
For the surplus attribute case I changed the message to |
Maybe... it's quite entangled. Maybe an additional check is required in such a case?
"Top level" is a normal term for that. However, I think it makes sense to emit just different errors for top-level and variant-level. |
4af0ed1 to
0265139
Compare
0265139 to
82a5354
Compare
I agree, but for just adjusting the error message emitted from |
|
anw the error now reads PR's ready for review. |
tyranron
left a comment
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.
@kiendang thanks!
Resolves #396
Synopsis
Add support for specifying a custom error type for
TryIntoderive via a#[try_into(error(error_ty[, error_fn]))]attribute similarly to #494 forFromStr.However there are a couple of issues that need clarifying
TryIntoderive 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.attrsthat follow the[#try_into(errorpattern, parse them withattr::Errorfor the custom error support. These attributes are also taken out ofinput.attrsbefore theState::with_attr_paramscall, leaving the rest of theTryIntoderive 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
refandref_mut.Another thing is suppose we want to derive for all 3
owned,refandref_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