Option guards should return None only if the value is empty.
#2831
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Based on #2543
Option is usable as pretty much any kind of guard. Right now, it's always infallible, and simply ignored errors. This may be somewhat counter-intuitive for newcomers (and old hats such as myself), and may have some other negative implications. This PR changes the behavior of
Optionto match what one might expect -Nonerepresents the empty case, as it makes sense for each type of guard.The Negative Implications
There are a couple of issues I can see with the current behavior. First, and most obvious, it's likely not what a newcomer to Rocket would expect. We should avoid sweeping errors under the rug, so to speak, and instead leave that choice fully up to the user. Second, there may be a non-trivial overhead to simply discarding data in the case we fail to parse. This is generally mitigated by data limits, but I don't think they represent a full solution. Finally, the current behavior may actually impede debugging efforts. To see how, consider the following route:
Right now, a request to
/?age=awill callr(None)- with no mention (even in the logs) that the guard failed. With this PR, the above request will instead return an Error (which, with typed-catchers, could produce a nice error message for the consumer). Ifagehad a more complex parser, this would make debugging much harder, since the error is just being silently ignored.New behavior
In general, the old behavior can be emulated by using
Result, and ignoring theErrvalue. We could provide a separateOption-like enum that had the old behavior, but it might be easier to simply provide a set of type aliases that fill in the error type automatically, e.g.type DataResult<T: FromData> = Result<T, T::Error>;FromData
FromDatanow usespeekto check whether the data contains any bytes. Iff it is empty, it will succeed withNone.FromParam
This implementation has been removed. This is a more obviously breaking change, but since Rocket ignores empty segments, we can't meaningfully provide this implementation anymore.
FromSegements
This implementation now only succeeds with
Noneif theSegmentsis empty.FromForm
This one has different behavior depending on the current strictness. In strict mode, it succeeds with
Noneiff there were no values passed to theFromFormimplementation. Otherwise, it also succeeds withNoneif all theErrorKinds wereMissing.See the diff of core/lib/src/form/tests.rs for the changes to how
Optionparses.FromRequest
There isn't really an easy way to check whether a request guard failed or was simply missing, but now
Optiononly catchesForwards. In this case, the old behavior can be emulated byOption<Result>,Result<Option>, orOutcome.TODO