Skip to content

grpc-protobuf: add server codegen utils - #2818

Open
arjan-bal wants to merge 10 commits into
grpc:masterfrom
arjan-bal:server-protobuf
Open

grpc-protobuf: add server codegen utils#2818
arjan-bal wants to merge 10 commits into
grpc:masterfrom
arjan-bal:server-protobuf

Conversation

@arjan-bal

@arjan-bal arjan-bal commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

This change introduces the types required for server codegen (see this branch for the full set of changes).

Additionally, this PR mvoes the ServerStatus from the grpc crate to the grpc-protobuf crate. ServerStatus wraps the standard status type to prevent users from accidentally forwarding client errors from a server handler using the ? operator.

Finally, this change re-exports the async_trait macro from the grpc crate (similar to tonic). Because async trait implementations require #[async_trait], re-exporting it avoids requiring applications to add async-trait as a direct dependency in their Cargo.toml while using the generated code.

@arjan-bal
arjan-bal force-pushed the server-protobuf branch 2 times, most recently from cfdffb8 to 4640ba4 Compare August 19, 2026 13:48
Comment on lines +244 to +245
/// Creates a new [`ServerStatusError`] from a [`StatusError`].
pub fn from_status(status: StatusError) -> Self {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should probably document this and into to explain why we didn't impl From instead.

Comment on lines +102 to +103
let mut res_view = ProtoRecvMessage::from_mut(req);
self.rx.dyn_next(&mut res_view).await

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: req_view since these are requests instead of responses? (I assume this was copied from the client recv_into which is why it's res?)

///
/// Note: success does *not* indicate successful receipt of the response by
/// the client; it only indicates that the stream has not yet terminated.
pub async fn send(&mut self, resp: &impl AsView<Proxied = M>) -> Result<(), ()> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we need to do something to silence clippy here?


/// An adapter that wraps a [`BidiStreamingMethod`] to handle incoming
/// bidirectional-streaming RPCs.
pub struct BidiStreamingAdapter<M: BidiStreamingMethod> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we're supposed to not specify the types here unless they're used here.

{
return trailers_from_status(Err(ServerStatusError::new(
StatusCodeError::Internal,
"client did not send a request message",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is the RPC error we send back to the client?

Maybe "unary call missing request message" or something?

Also should this be using an interceptor to deal with this (and also doing a second recv and expecting to get a None)?

#2602

)));
}

let mut resp = <M::Response as Default>::default();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

WDYT? Let's move this up to where req is defined and // TODO: allocate these together on an arena?

@dfawley dfawley assigned arjan-bal and unassigned dfawley Sep 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants