Skip to content

Borrowed request views: ServiceRequest and StreamMessage on buffa 0.7.0#143

Draft
iainmcgin wants to merge 3 commits into
mainfrom
prototype/borrowed-unary-views
Draft

Borrowed request views: ServiceRequest and StreamMessage on buffa 0.7.0#143
iainmcgin wants to merge 3 commits into
mainfrom
prototype/borrowed-unary-views

Conversation

@iainmcgin
Copy link
Copy Markdown
Collaborator

@iainmcgin iainmcgin commented May 29, 2026

Summary

Reworks the server-side request surface around buffa 0.7.0, which removes the OwnedView Deref impl (which let safe code hold view fields past the backing buffer's lifetime) and introduces HasMessageView plus generated FooOwnedView accessor wrappers. Rather than just absorbing the ergonomic loss, handlers move to a new request/stream-item API:

  • ServiceRequest<'a, Req> — unary and server-streaming handlers now take a borrowed request (req: ServiceRequest<'_, GreetRequest>). It Derefs to the request view for field access, and offers to_owned_message() (zero-copy via the retained body bytes), bytes(), and view(). Borrowing across .await works; moving into tokio::spawn requires to_owned_message() (enforced by the compiler).
  • StreamMessage<M> — client-streaming and bidi inbound items. Derefs to the buffa-generated FooOwnedView wrapper for per-field accessors, and re-encodes from the retained wire bytes when forwarded.
  • Client: UnaryResponse::view() returns the reborrowed view; raw_bytes() is renamed to bytes().
  • Codegen: generated service traits/dispatchers use the new signatures; the view-family impls come from buffa 0.7.0's generated code rather than connect-codegen.
  • Workspace now requires buffa/buffa-types/buffa-codegen 0.7; checked-in generated code is regenerated with the 0.7.0 toolchain.

extern_path types use the same wrappers (second commit). The earlier borrowed-view fallback for inputs mapped via extern_path is gone; instead the requirement is documented (README, plugin option docs, Options rustdoc, generated trait docs): every extern_path target must be buffa ≥ 0.7.0 generated code with views enabled, the same way the stubs already rely on the JSON impls. buffa-types 0.7+ satisfies this for well-known types; a non-conforming crate fails to compile on the missing HasMessageView impl, and anthropics/buffa#161 adds a #[diagnostic::on_unimplemented] note to that trait so the error explains the fix. The output side is unchanged: Encodable view-body impls are still per-type and skipped for extern outputs (a blanket impl keyed through the HasMessageView GAT was tried and is not coherent next to the M: Message + Serialize blanket).

Status — not yet complete

  • connectrpc, connectrpc-codegen, connectrpc-build, and the tests/streaming e2e suite build and pass against published buffa 0.7.0; clippy and rustfmt clean.
  • Not yet ported: conformance, examples/* (eliza, multiservice, middleware, mtls-identity, streaming-tour), and benches/rpc still implement the old OwnedView<...> handler signatures, so workspace-wide clippy/test CI will be red until they are updated.
  • ❌ Planned: a Heartbeat(google.protobuf.Empty) → Timestamp-style RPC in the multiservice WKT example, so the extern-input/output paths are compiled in CI rather than only asserted in codegen unit tests.
  • docs/guide.md and the README handler examples still show the old signatures.
  • ❌ No CHANGELOG entry yet (will cover the handler API, the buffa 0.7 floor, and the extern_path requirement).

Opening as a draft so the API surface can be reviewed holistically ahead of a connect-rust 0.7.0 release alongside buffa 0.7.0.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 29, 2026

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

…n buffa 0.7.0

Unary and server-streaming handlers now take ServiceRequest<'_, Req>, a
borrowed request wrapper that Derefs to the request view for field access
and offers to_owned_message() (zero-copy from the retained body bytes),
bytes(), and view(). Client-streaming and bidi inbound items become
StreamMessage<M>, which Derefs to the buffa-generated FooOwnedView
wrapper for per-field accessors and re-encodes from the retained wire
bytes when forwarded. On the client, UnaryResponse::view() returns the
reborrowed view and raw_bytes() is renamed to bytes().

Generated service traits and dispatchers adopt the new signatures. The
view-family impls (HasMessageView, owned-view wrappers) now come from
buffa 0.7.0's generated code instead of connect-codegen; inputs from
extern_path crates fall back to &FooView<'_> parameters. The workspace
requires buffa/buffa-types/buffa-codegen 0.7 and the checked-in
generated code is regenerated with the 0.7.0 toolchain.

Not yet ported to the new signatures: the conformance server, the
examples, the rpc benches, and the guide/README handler examples.
@iainmcgin iainmcgin force-pushed the prototype/borrowed-unary-views branch from 47aac9a to a2e1b52 Compare May 29, 2026 02:09
iainmcgin added 2 commits May 29, 2026 15:49
…ionally

Drop the borrowed-view fallback for request parameters and inbound
stream items whose types resolve through extern_path. The fallback
existed because connect could not know whether the foreign crate's
generated code provides buffa::HasMessageView; that is now a documented
requirement instead: every extern_path target must be buffa >= 0.7.0
generated code with views enabled, the same way the stubs already rely
on the JSON serialization impls. buffa-types 0.7+ satisfies this for
the well-known types, and a non-conforming crate fails to compile with
a missing HasMessageView impl.

All Router, Dispatcher, and trait-method emission sites now produce the
same ServiceRequest<'_, Req> / StreamMessage<Req> surface regardless of
where the input type lives. The now-dead owned_view_input_arg_type
helper and unused BatchState parameters are removed, and the
requirement is documented in the Options rustdoc, the plugin option
docs, the README, and the generated trait docs.

The output-side rule is unchanged: Encodable view-body impls are still
not emitted for extern output types (those would be orphan impls in the
consumer crate).
connyay added a commit to connyay/connectrpc-workers that referenced this pull request Jun 2, 2026
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.

1 participant