continue prost - #286
Conversation
|
@jokemanfire I appreciate you taking on this work very much. Thanks agian. |
There are some conflicts and API changes that need to be resolved and some code needs to be packaged to adapt to the current API. It's not easy to operate with the previous version of PR. I need to add some commit to complete this feature. I have communicated with the original author. |
dcf4304 to
781c816
Compare
|
@Tim-Zhang @justxuewei Local test all pass but i don't know how to install protoc in CI. |
21ebbd3 to
4a76b7b
Compare
a29312f to
5fadae0
Compare
|
Basically enough @Tim-Zhang @justxuewei just take a look . :) |
|
Nice work, thanks @jokemanfire! Could you cleanup your commits? It makes us easier to review and maintain.
Thanks! |
I have changed it. |
00fce61 to
735a10e
Compare
|
Once this feature gets merged, I prefer to bump a major version to 2 to avoid some compatibility issues, as it nearly changes the entire codegen engine. WDYT? @jokemanfire @Tim-Zhang |
This modification is indeed quite significant, and I agree. It depends on the maintainer's thoughts |
|
I tried to minimize conditional compilation as much as possible @Tim-Zhang @justxuewei |
|
@Tim-Zhang Can you take some time to advance this feature? In the previous puncture, it was found that the prost library uses less memory during operation than the Rust Protobuf library |
thanks , I will take some time to resolve it. |
This commit refactors the ttrpc-codegen and the compiler, and merges the two crates into a single crate, named "codegen". The codegen uses prost crate, a protobuf compiler for Rust. Signed-off-by: Xuewei Niu <niuxuewei.nxw@antgroup.com>
The ttrpc provides a "prost" feature to support the new version of codegen. An "example2" has been added to demonstrate how to use the codegen. Signed-off-by: Xuewei Niu <niuxuewei.nxw@antgroup.com>
Install protoc when executing `make deps` of the ttrpc. Add codegen's check and build, and example2' build to the ci testing. Signed-off-by: Xuewei Niu <niuxuewei.nxw@antgroup.com>
Fix all issues reported by cargo clippy to make ci testing pass. Signed-off-by: Xuewei Niu <niuxuewei.nxw@antgroup.com>
merge from remote branch. ref: containerd#173 Co-authored-by: Xuewei Niu <niuxuewei.nxw@antgroup.com> Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
fix ci for protoc Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
because of the api change 1. fix the marco in prost 2. fix the test Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
fix rebase error. Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
skip build example2 in windows Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
while use protoc,rename the Code enum. Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
fix marco Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
Resolve Tim-Zhang's review on containerd#286 and adapt the prost backend to the master workspace. codegen (prost): - Use path-aware type_token() for method input/output types instead of format_ident!(), which panicked on qualified paths like super::google::protobuf::Empty. - Emit package-level imports once via finalize_package instead of per service, fixing E0252 on packages with multiple services. - Prefix per-method handler types with the service name so overlapping method names (Foo.Get / Bar.Get) no longer collide. - Make NameSpliter robust against empty segments to avoid panics on underscore-only / trailing-underscore names. - Refactor CodegenBuilder to owned PathBuf/Vec<PathBuf>, direct defaults, and build(self); drop the unrelated P: Default bound. - Add focused fixtures for imported types, overlapping method names, and package-less schemas. runtime / deps: - Align the prost family to 0.13 across ttrpc, prost-build, codegen, and example2 to avoid version drift. - Configure docs.rs with an explicit compatible feature set instead of all-features (prost and rustprotobuf are mutually exclusive). build / ci / docs: - Makefile: use $(OS) so the Windows branch is reachable. - bvt.yml: keep shell: bash on the multi-command Build step. - .gitignore: drop duplicate example2 rules. - README: document default-features = false for the prost feature. - build.rs: operate on the generated content in place (no clone). rebase onto master: - Adopt master's Cargo workspace; keep codegen and example2 as standalone workspace roots to avoid the ttrpc-codegen name collision. - Silence clippy::doc_overindented_list_items in prost-generated code. - Fix a stray brace in tests/run-examples.rs introduced during rebase. Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
There was a problem hiding this comment.
Pull request overview
This pull request continues the migration path toward supporting tokio-rs/prost alongside the existing rust-protobuf backend, adding a new standalone prost-based codegen crate plus a new example2 tree to exercise the prost workflow, and updating CI/build plumbing to install protoc and test both backends.
Changes:
- Add
prost+rustprotobufmutually-exclusive feature support in thettrpccrate, with conditional encode/decode paths across sync/async runtimes. - Introduce a new standalone
codegen/crate (prost-build based) and a newexample2/project that uses it. - Update CI and build scripts (including a new
install_protoc.sh) to ensureprotocis available and both backends build/test appropriately.
Reviewed changes
Copilot reviewed 54 out of 55 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| ttrpc-codegen/Makefile | Add local check/test targets for the legacy codegen crate. |
| compiler/Makefile | Add local check/test targets for the compiler crate. |
| tests/run-examples.rs | Run examples conditionally for rustprotobuf vs prost and add per-example working directory support. |
| src/ttrpc.proto | Change proto package to ttrpc (aligns with prost codegen expectations). |
| src/sync/utils.rs | Add prost-specific request/response helpers and macro variants. |
| src/sync/server.rs | Add prost decode/encode handling in sync server request path. |
| src/sync/mod.rs | Export utils as public module (macros/helpers used externally). |
| src/sync/client.rs | Add prost-specific oversize/status handling in sync client. |
| src/proto.rs | Add Codec impl for prost messages and gate protobuf stream codecs behind feature flags. |
| src/lib.rs | Re-export sync helpers and enforce mutual exclusivity of prost/rustprotobuf. |
| src/error.rs | Make Error -> Response and get_status work for both backends. |
| src/context.rs | Construct metadata KeyValue values compatibly for both backends. |
| src/asynchronous/utils.rs | Add prost variants of async handler/client macros and gate existing ones. |
| src/asynchronous/server.rs | Adjust async server response/status paths for prost message layout/size checks. |
| src/asynchronous/client.rs | Make async client request conversion/status handling work for both backends. |
| README.md | Document how to use the prost backend and its differences. |
| Makefile | Split CI checks/tests to run rustprotobuf and prost configurations (and skip prost where needed on Windows). |
| install_protoc.sh | Add helper to install protoc across GitHub Actions runner OSes. |
| example2/utils.rs | Add shared utilities for the prost-based example project. |
| example2/server.rs | Add sync prost example server. |
| example2/protocols/sync/mod.rs | Include generated sync prost protocol modules. |
| example2/protocols/protos/streaming.proto | Add streaming proto schema for example2. |
| example2/protocols/protos/oci.proto | Add OCI proto schema for example2. |
| example2/protocols/protos/health.proto | Add health proto schema for example2. |
| example2/protocols/protos/google/protobuf/test_empty.proto | Add test Empty message for example2 protos. |
| example2/protocols/protos/google/protobuf/empty.proto | Vendor protobuf well-known Empty type for example2 compilation. |
| example2/protocols/protos/google/protobuf/descriptor.proto | Vendor protobuf descriptor type for example2 compilation. |
| example2/protocols/protos/github.com/kata-containers/agent/pkg/types/types.proto | Vendor kata agent types proto used by example2. |
| example2/protocols/protos/github.com/gogo/protobuf/gogoproto/gogo.proto | Vendor gogo proto options used by example2 schemas. |
| example2/protocols/protos/agent.proto | Vendor kata agent service proto used by example2. |
| example2/protocols/mod.rs | Define example2 protocol module layout. |
| example2/protocols/hack/update-generated-proto.sh | Add script for updating/regenerating vendored protos + rust output. |
| example2/protocols/asynchronous/mod.rs | Include generated async prost protocol modules. |
| example2/Makefile | Add build/build-examples/deps targets (including protoc install). |
| example2/client.rs | Add sync prost example client. |
| example2/Cargo.toml | Define example2 crate dependencies and examples (prost + ttrpc prost feature). |
| example2/build.rs | Generate sync/async prost services via new codegen crate. |
| example2/async_stream_server.rs | Add async streaming server example for prost. |
| example2/async_stream_client.rs | Add async streaming client example for prost. |
| example2/async_server.rs | Add async unary server example for prost. |
| example2/async_client.rs | Add async unary client example for prost. |
| example/protocols/sync/mod.rs | Adjust example protocol module exports for legacy layout. |
| example/protocols/asynchronous/mod.rs | Adjust example async protocol module exports for legacy layout. |
| example/Cargo.toml | Ensure example explicitly enables rustprotobuf backend feature. |
| codegen/src/util.rs | Add identifier casing/type-path helper utilities for prost codegen. |
| codegen/src/svcgen.rs | Implement prost-build ServiceGenerator for ttrpc services/clients (sync+async+streaming). |
| codegen/src/lib.rs | Export the codegen API surface. |
| codegen/src/codegen.rs | Implement codegen builder + header injection using prost-build and fd_set introspection. |
| codegen/README.md | Document how to use the new prost-based codegen crate. |
| codegen/Makefile | Add build/test/check/deps targets for codegen crate. |
| codegen/Cargo.toml | Define new standalone ttrpc-codegen (prost-based) crate. |
| Cargo.toml | Add optional prost deps, define prost vs rustprotobuf features, and exclude new standalone crates from workspace. |
| build.rs | Generate ttrpc protos via protobuf-codegen or prost-build depending on selected backend, with prost enum variant rewriting. |
| .gitignore | Ignore generated protocol Rust files while keeping mod.rs tracked for both example trees. |
| .github/workflows/bvt.yml | Install protoc in CI and build example2 as part of the build job. |
Suppressed comments (2)
src/sync/utils.rs:182
- In the prost client macro,
mergeis called with an immutable slice.prost::Message::mergeneeds&mutinput (e.g.&mut &[u8]), otherwise this won’t compile.
src/asynchronous/utils.rs:317 - In the prost async client macro,
mergeis called with an immutable slice.prost::Message::mergerequires&mutinput (e.g.&mut &[u8]), otherwise it won’t compile.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 54 out of 55 changed files in this pull request and generated 2 comments.
Suppressed comments (10)
src/sync/utils.rs:113
- With the prost backend,
prost::Message::mergeexpects a mutableBuf(e.g.&mut &[u8]). Passing an immutable&[u8]won’t type-check, so this macro expansion will fail to compile under--features prost.
src/sync/utils.rs:182 - In the prost
client_request!macro,prost::Message::mergerequires a mutableBuf(e.g.&mut &[u8]). The currentmerge(&res.payload as &[u8])will not compile with prost 0.13.
src/asynchronous/utils.rs:317 - In the prost
async_client_request!macro,prost::Message::mergerequires a mutableBuf(e.g.&mut &[u8]). The currentmerge(&res.payload as &[u8])won’t type-check with prost 0.13.
tests/run-examples.rs:126 - In the prost test block, the sync
server/clientexample is commented out, so CI no longer exercises the basic sync example under the prost backend even thoughexample2provides it.
src/sync/client.rs:166 - For the prost backend, the oversize check currently only considers
req.payload.len(), but the encoded request size also includesservice,method,metadata, etc. This can bypass the max message size check with large metadata. Use the encoded size instead (via the existingCodec::size()implementation).
src/sync/utils.rs:58 - The prost
response_to_channelvariant doesn’t enforcecheck_oversizelike the rustprotobuf path does. That can send oversized responses and violate the library’s message size limits. Mirror the existing oversize handling before sending.
This issue also appears in the following locations of the same file:
- line 110
- line 179
compiler/Makefile:8
make -C compiler(as invoked by.github/workflows/bvt.yml) now defaults to running only thechecktarget, which means the build job no longer actually builds/tests this crate by default. Add an explicitalldefault target (or restore the previous include-based targets) so CI and localmakebehave as expected.
.PHONY: check
check:
cargo fmt --all -- --check
cargo clippy --all-targets -- -D warnings
ttrpc-codegen/Makefile:8
make -C ttrpc-codegen(as invoked by.github/workflows/bvt.yml) now defaults to running only thechecktarget, so the build job no longer builds/tests this crate by default. Add analldefault target somakecontinues to validate both linting and tests.
Makefile:3PROTOCis introduced but not used anywhere in the Makefile (no$(PROTOC)references). This adds confusion for maintainers; either wire it into the relevant targets or remove it.
PROTOC ?= $(shell which protoc 2>/dev/null || echo $(HOME)/protoc/bin/protoc)
all: debug test
src/error.rs:17
use crate::proto::{self, ...}importsproto::selfbut it’s never referenced, and the surrounding#[allow(unused_imports)]masks that. This can hide real unused-import issues; remove the unused import and the allow.
- error.rs: drop the unused `self` (proto module) import and the `#[allow(unused_imports)]` that masked it; Code/Response/Status are the only proto items referenced in this file. - sync/utils.rs: replace `#[allow(unused_imports)]` with explicit `#[cfg(not(feature = "prost"))]` gating for `Codec` and `check_oversize`, which are only used by the rustprotobuf backend (`Codec` provides the `encode()` trait method). Shared imports remain ungated. - README.md: fix "genereated" typo. - tests/run-examples.rs: remove a commented-out dead example2 call. Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
Tim-Zhang
left a comment
There was a problem hiding this comment.
Thanks for the continued updates. I hope we can stay in close communication and get this PR merged within the next two weeks.
The latest revision fixes several earlier issues, and the current checks are green. I also verified locally that the codegen tests and the main library tests for both protobuf backends pass.
The main remaining items are:
- Preserve the existing
ttrpc-codegenfluent API and add.prost()for backend selection instead of requiring users to migrate toCodegenBuilder. - Avoid unnecessary generated API differences, including
Arc<Box<dyn Trait>>, backend-dependent macro signatures, and newly exposed internal helpers. - Keep the original protobuf package declarations. Rust module layout differences should be handled in the build or module glue rather than by changing protocol identities.
- Keep the standalone Prost example, but rename
example2toexample-prostand reuse the existing proto schemas. Removing the duplicated proto directory and update script would eliminate 2,252 of the 3,238 added example lines. - Make the example tests validate RPC results and execute the sync example in CI.
- Make the codegen dependencies backend-specific, fix package-less service names, enforce size limits against complete encoded messages, and run the codegen crate tests explicitly in CI.
Acronym casing differences such as OnlineCPUMemRequest and OnlineCpuMemRequest are determined by the respective generators. I am not requesting automatic compatibility aliases for these types in this PR.
The PR also currently conflicts with the target branch and will need to be updated before merging.
Resolve conflicts with master (security_extension, send_response pipeline, docs, CHANGELOGs) and adapt the prost backend on top: - ttrpc.proto keeps `package grpc`; the backend-specific generated module name (ttrpc.rs vs grpc.rs) is absorbed by the mod.rs glue. - build.rs appends Code compatibility constants instead of rewriting generated source text. - Backend-neutral Codec gains merge(); sync/async codegen macros share one implementation and accept both the historical six-argument and path-aware five-argument forms; oversized requests are validated against the complete encoded buffer. - protobuf-codegen is optional behind the rustprotobuf feature; a compile error is reported when no backend is selected. - codegen restores the fluent Codegen API (.prost() backend selector, Customize), always generates services, and uses Arc<dyn Trait>. Package-less wire names no longer contain a stray dot. - example2 is renamed to example-prost, reuses the unchanged schemas from example/protocols/protos, and restores success assertions; the prost BVT now runs the sync example pair as well. - CI explicitly runs the codegen crate's check and tests. Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
The async unary and streaming client paths only checked the payload size via Message::new_request. Check the complete encoded GenMessage buffer against MESSAGE_LENGTH_MAX after encoding, consistent with the sync client fix requested in review. Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
The compiler and ttrpc-codegen Makefiles include the root Makefile, so the prost test/clippy legs added there failed in the sub-crates with "the package 'ttrpc-compiler' does not contain these features: async, prost, sync". Mark the sub-crates with SUBCRATE and only run the prost legs from the root crate. Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
There was a problem hiding this comment.
@jokemanfire Thanks for the updates. One last codegen issue:
| .map_err(|e| io::Error::other(format!("decode fd_set: {e}")))?; | ||
|
|
||
| for fd in fd_set.file.iter() { | ||
| let rs_path = self.out_dir.join(format!("{}.rs", fd.package())); |
There was a problem hiding this comment.
Multiple proto files can share the same package and therefore the same output file. Here, health.proto, agent.proto, and oci.proto all map to grpc.rs, so the generated file starts with the same header three times:
// This file is generated by ttrpc-codegen 1.0.0. Do not edit
// @generated
// This file is generated by ttrpc-codegen 1.0.0. Do not edit
// @generated
// This file is generated by ttrpc-codegen 1.0.0. Do not edit
// @generatedPlease deduplicate rs_path before rewriting the file.
work continue with #173
Closes #258