Skip to content
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

[3/n] [dropshot-endpoint] factor out endpoint and parameter validation #1008

Conversation

sunshowers
Copy link
Contributor

@sunshowers sunshowers commented May 15, 2024

We're going to reuse a lot of this code for server endpoints. Refactor code to
prepare for that. I think it's overall a nice improvement :)

For successful generation, there are absolutely no changes in output. (This is
a standalone PR, so it's easy to see this.)

In error cases:

  1. Since we encapsulate the different parts of parsing into their own types, there are some minor changes to the situations where we produce errors. Among the fixtures we have, there are a few outputs that change -- I think all for the better.
  2. If the function is valid, but the metadata is not, we pass through the original function without doing any modifications to it. This leads to a much better experience for traits, and a slightly better one for functions.

Also add a little bit of error-handling infrastructure in the form of an
ErrorStore. This makes it reasonable to have this kind of nested
structure, where each component can determine whether it produced errors. We're
going to use this more extensively within the server macro, since that has
to maintain separate error contexts per endpoint.

As part of this, do_endpoint and do_channel no longer return Result types -- all errors are handled internally, and instead they return a pair of output and a list of errors. This resolves an inconsistency that I've been bothered by for a bit.

Depends on #1007.

Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1

[skip ci]
Comment on lines -21 to -40

error: `self` parameter is only allowed in associated functions
--> tests/fail/bad_endpoint2.rs:13:23
|
13 | async fn bad_endpoint(self) -> Result<HttpResponseOk<()>, HttpError> {
| ^^^^ not semantically valid as function parameter
|
= note: associated functions are those in `impl` or `trait` definitions

error[E0401]: can't use generic parameters from outer item
--> tests/fail/bad_endpoint2.rs:13:23
|
9 | #[endpoint {
| ---------- `Self` type implicitly declared here, by this `impl`
...
13 | async fn bad_endpoint(self) -> Result<HttpResponseOk<()>, HttpError> {
| ^^^^
| |
| use of generic parameter from outer item
| refer to the type directly here instead
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these errors in particular are unhelpful, and detecting them syntactically is much cleaner.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does "detecting them syntactically" mean and how does that relate to this change? Agreed that these errors are not helpful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By "syntactically" I just mean looking at the token stream and rejecting code within the proc macro, rather than "semantically", generating code that will fail to compile and relying on rustc's errors. (Is there a better term for this? I've always used syntactically/semantically for this in the context of proc macros)

Created using spr 1.3.6-beta.1
@sunshowers
Copy link
Contributor Author

(Looks like the tests aren't running because this is a dependent PR not targeting main. Yay for github's terrible support for stacks.)

Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1

[skip ci]
@sunshowers sunshowers changed the title [dropshot-endpoint] factor out endpoint and parameter validation [3/n] [dropshot-endpoint] factor out endpoint and parameter validation May 16, 2024
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1

[skip ci]
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1

[skip ci]
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
pub(crate) struct ErrorSink<'a, T> {
// It's a bit weird to use both a lifetime parameter and a RefCell, but it
// makes sense here. The lifetime parameter ensures that the error context
// doesn't outlive the collector, and the RefCell exists so we can
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's a collector?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, the collector is just the thing that collects and stores errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed this comment up.

dropshot_endpoint/src/error_store.rs Outdated Show resolved Hide resolved
@sunshowers sunshowers changed the base branch from sunshowers/spr/main.dropshot-endpoint-factor-out-endpoint-and-parameter-validation to main June 2, 2024 03:25
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Copy link
Collaborator

@ahl ahl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ship it


use std::cell::RefCell;

/// Top-level struct that holds all errors encountered during the invocation of
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is excellent

/// So the typical Rust pattern of returning on the first error isn't quite good
/// enough for us, and what we need is:
///
/// * a hierarchical way to collect errors
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not clear to my why hierarchy is important or how it manifests to users... but this is great, and no need to block on my confusion!

Copy link
Contributor Author

@sunshowers sunshowers Jun 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically the hierarchy is:

top level
|-> metadata
|-> signature
      |-> request context
      |-> each extractor
      |-> return type

and errors in some node in the tree should not stop sibling nodes from being validated.

@sunshowers sunshowers merged commit 3f435ef into main Jun 6, 2024
10 checks passed
@sunshowers sunshowers deleted the sunshowers/spr/dropshot-endpoint-factor-out-endpoint-and-parameter-validation branch June 6, 2024 23:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants