Skip to content

[9/n] [dropshot] add API traits with support for endpoints#984

Merged
sunshowers merged 67 commits into
mainfrom
sunshowers/spr/wip-prototype-for-trait-based-dropshot-servers
Jul 3, 2024
Merged

[9/n] [dropshot] add API traits with support for endpoints#984
sunshowers merged 67 commits into
mainfrom
sunshowers/spr/wip-prototype-for-trait-based-dropshot-servers

Conversation

@sunshowers

@sunshowers sunshowers commented Apr 28, 2024

Copy link
Copy Markdown
Contributor

As discussed in RFD 479 and oxidecomputer/omicron#5247.

Add support for a new way to define Dropshot APIs: via a trait. This builds on work done in the prior PRs in this series, such that it reuses as much shared logic from endpoints as possible.

I've tried to structure the PR series such that this one is almost entirely added code. It's also mostly tests, with around 1400 lines of "real" code.

See RFD 479 for more information.

TODO

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
Comment thread dropshot/src/lib.rs Outdated
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
Comment thread dropshot/src/lib.rs Outdated
//! for each type of response (which can also include documentation). This is
//! largely known statically, though generated at runtime.
//!
//! ### As a trait server

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is where the end-user documentation starts.

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
@sunshowers sunshowers changed the base branch from main to sunshowers/spr/main.wip-prototype-for-trait-based-dropshot-servers May 20, 2024 02:15
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
@sunshowers sunshowers changed the title [WIP] prototype for trait-based dropshot servers [6/n] [WIP] add trait-based dropshot servers with endpoints May 20, 2024
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Comment thread dropshot/tests/fail/bad_server_invalid_types.stderr Outdated
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

[skip ci]
@sunshowers sunshowers changed the title [6/n] [WIP] add trait-based dropshot servers with endpoints [7/n] [WIP] add trait-based dropshot servers with endpoints May 24, 2024
Created using spr 1.3.6-beta.1
@sunshowers sunshowers changed the title [8/n] add trait-based dropshot servers with endpoints [9/n] add trait-based dropshot servers with endpoints Jun 10, 2024
Created using spr 1.3.6-beta.1

[skip ci]
Created using spr 1.3.6-beta.1
Comment on lines +1 to +7
error: endpoint `bad_endpoint` has invalid attributes: missing field `path`
--> tests/fail/bad_server_endpoint26.rs:12:1
|
12 | #[dropshot::server]
| ^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the attribute macro `dropshot::server` (in Nightly builds, run with -Z macro-backtrace for more info)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is addressed by oxidecomputer/serde_tokenstream#194.

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

[skip ci]
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

[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

@ahl ahl left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'd say I looked that code "some" i.e. in the places that I felt most familiar with. I scanned through the tests to think about coverage, and I looked at the docs for end-user clarity. If you'd like me to look more thoroughly at some part(s) please let me know but my general feeling is that the mechanics don't require intense scrutiny.

Comment thread dropshot/examples/server-trait-default.rs Outdated
Comment thread dropshot/examples/server-trait-default.rs Outdated
Comment thread dropshot/examples/server-trait-default.rs Outdated
Comment on lines +13 to +17
//! implementations to override the base behavior if desired (similar to std's
//! `Read` and `Write`).
//! * The behavior lives in a base trait, and the server is an extension trait
//! on top of it, with a blanket impl prohibiting overrides (similar to
//! tokio's `AsyncReadExt` and `AsyncWriteExt`).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I didn't follow the Read or AsyncReadExt analogies

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Expanded the doc comment to explain this in more detail.

Variations

The general degrees of freedom available when dealing with traits in Rust
are almost all available here. The main bit of flexibility that isn't
available is that server traits can't be object-safe.

Same trait with default methods

For example:

#[dropshot::server]
trait CounterServer {
     type Context;
     
     fn get_counter_impl(&self) -> impl Future<Output = u64> + Send;
     fn set_counter_impl(
         &self,
         value: u64,
     ) -> impl Future<Output = Result<(), String>> + Send;
     #[endpoint { method = GET, path = "/counter" }
     async fn get_counter() {} // as below
     #[endpoint { method = PUT, path = "/counter" }
     async fn put_counter() {} // as below
}

This is similar to how [std::io::Write]'s write_all method is defined as
a default method over the required write.

Supertrait

trait CounterBase {
    fn get_counter_impl(&self) -> impl Future<Output = u64> + Send;
    fn set_counter_impl(
        &self,
        value: u64,
    ) -> impl Future<Output = Result<(), String>> + Send;
}
#[dropshot::server]
trait CounterServer: CounterBase {
    #[endpoint { method = GET, path = "/counter" }
    async fn get_counter() {} // as below
    #[endpoint { method = PUT, path = "/counter" }
    async fn put_counter() {} // as below
}
// And optionally, a blanket impl.
impl<T: CounterBase> CounterServer for T {}

With the optional blanket impl, implementations cannot override
CounterServer's behavior. This is similar to how
[tokio::io::AsyncWriteExt] has a blanket impl for
AsyncWrite.

Comment thread dropshot/examples/server-trait.rs Outdated
Comment thread dropshot_endpoint/src/server.rs Outdated
Comment thread dropshot_endpoint/src/server.rs Outdated
Comment thread dropshot_endpoint/src/server.rs Outdated
Comment thread dropshot_endpoint/src/server.rs Outdated
@@ -1,8 +1,15 @@
// Copyright 2021 Oxide Computer Company
//
// Portions of this file are adapted from syn (https://github.com/dtolnay/syn),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

what in particular?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've added "adapted from syn" comments to the relevant bits (which is most of the file).

@sunshowers sunshowers changed the base branch from sunshowers/spr/main.wip-prototype-for-trait-based-dropshot-servers to main June 12, 2024 23:56
Created using spr 1.3.6-beta.1
@sunshowers sunshowers changed the title [9/n] add trait-based dropshot servers with endpoints [9/n] [dropshot] add trait-based Dropshot servers with endpoints Jun 12, 2024
@sunshowers sunshowers changed the title [9/n] [dropshot] add trait-based Dropshot servers with endpoints [9/n] [dropshot] add trait-based Dropshot servers with support for endpoints Jun 12, 2024
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
@sunshowers sunshowers changed the title [9/n] [dropshot] add trait-based Dropshot servers with support for endpoints [9/n] [dropshot] add API traits with support for endpoints Jun 15, 2024
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
@sunshowers sunshowers merged commit 0bc8fb4 into main Jul 3, 2024
@sunshowers sunshowers deleted the sunshowers/spr/wip-prototype-for-trait-based-dropshot-servers branch July 3, 2024 01:02
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.

2 participants