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
Option
to match what one might expect -None
represents 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=a
will 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). Ifage
had 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 theErr
value. 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
FromData
now usespeek
to 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
None
if theSegments
is empty.FromForm
This one has different behavior depending on the current strictness. In strict mode, it succeeds with
None
iff there were no values passed to theFromForm
implementation. Otherwise, it also succeeds withNone
if all theErrorKind
s wereMissing
.See the diff of core/lib/src/form/tests.rs for the changes to how
Option
parses.FromRequest
There isn't really an easy way to check whether a request guard failed or was simply missing, but now
Option
only catchesForwards
. In this case, the old behavior can be emulated byOption<Result>
,Result<Option>
, orOutcome
.TODO