Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions .github/workflows/bvt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install Protoc
run: ./install_protoc.sh
shell: bash
- name: Check
run: |
make check-all
Expand All @@ -23,15 +26,16 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install Protoc
run: ./install_protoc.sh
shell: bash
- name: Build
run: |
make
make -C compiler
make -C ttrpc-codegen
make -C example build-examples
# It's important for windows to fail correctly
# https://github.com/actions/runner-images/issues/6668
shell: bash
make -C example2 build-examples

@Tim-Zhang Tim-Zhang Aug 5, 2026

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.

Removing shell: bash makes this multi-command step use PowerShell on Windows, where an earlier native-command failure can be hidden by a later successful command. Keep shell: bash, or split the commands into separate steps with explicit failure handling.


deny:
runs-on: ubuntu-latest
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@ Cargo.lock
.idea
*.o
example/protocols/**/*.rs
!example/protocols/**/mod.rs
example2/protocols/**/*.rs
!example2/protocols/**/mod.rs
src/ttrpc.rs
example2/protocols/**/*.rs

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.

These example2 ignore/negation rules duplicate lines 10-11. Please remove the redundant entries and keep the file's final newline.

!example2/protocols/**/mod.rs
8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ description = "A Rust version of ttrpc."
rust-version = "1.70"

[dependencies]
protobuf = { version = "3.1.0" }
prost = { version = "0.11", optional = true }
protobuf = {version = "3.1.0", optional = true}
libc = { version = "0.2.59", features = [ "extra_traits" ] }
nix = "0.26.2"
log = "0.4"
Expand All @@ -34,11 +35,14 @@ tokio-vsock = { version = "0.7.0", optional = true }
# lock home to avoid conflict with latest version
home = "=0.5.9"
protobuf-codegen = "3.1.0"
prost-build = { version = "0.13", optional = true }

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.

Refactor/dependencies: the runtime uses prost 0.11 here while the root build uses prost-build 0.13, and the new codegen crate pins the Prost family to 0.11. Keep the Prost crates on one compatible version and centralize the versions to avoid duplicate dependency trees and generated/runtime drift.


[features]
default = ["sync"]
default = ["sync","rustprotobuf"]
async = ["async-trait", "async-stream", "tokio", "futures", "tokio-vsock"]
sync = []
prost = ["dep:prost", "dep:prost-build"]
rustprotobuf = ["dep:protobuf"]

[package.metadata.docs.rs]
all-features = true
Expand Down
18 changes: 16 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
PROTOC ?= $(shell which protoc 2>/dev/null || echo $(HOME)/protoc/bin/protoc)

all: debug test

#
Expand All @@ -21,12 +23,24 @@ build: debug

.PHONY: test
test:
cargo test --all-features --verbose
ifeq ($OS,Windows_NT)

@Tim-Zhang Tim-Zhang Aug 5, 2026

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.

GNU make parses $OS as the one-character variable $O followed by S, so this Windows branch is never selected. Use $(OS).

cargo test --features sync,async,rustprotobuf
else
# cargo test --all-features --verbose
cargo test --features sync,async,rustprotobuf
cargo test --no-default-features --features sync,async,prost
endif

.PHONY: check
check:
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo clippy --all-targets --features sync,async -- -D warnings
# Skip prost check on Windows
ifeq ($(OS),Windows_NT)
@echo "Skipping prost check on Windows"
else
cargo clippy --all-targets --no-default-features --features sync,async,prost -- -D warnings
endif

.PHONY: check-all
check-all:
Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,19 @@ cargo update
cargo install --force --path .
```
3. Build your project.

# ttrpc-rust with the Prost

The new version of the ttrpc-rust is built with the Prost crate, a modern
protobuf compiler written by Rust. There are certain different behaviors from
the Rust-protobuf version:

1. The protoc should be installed.
2. Enabling "prost" feature for the ttrpc-rust.
3. The Rust files are named based on their package name, rather than the proto
filename, e.g. `ttrpc = { version = "1.0", features = ["prost"] }`.

@Tim-Zhang Tim-Zhang Aug 5, 2026

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 example enables prost while keeping default features, which also enables rustprotobuf; the mutual-exclusion check then aborts compilation. Please document default-features = false and include the desired runtime feature explicitly, for example features = ["sync", "prost"].

4. Some variable names are different, e.g. for "cpu", "CPU" is generated by the
Rust-protobuf, and "Cpu" is genereated by the Prost.

The "example" is an example with the Rust-protobuf version, and the "example2"
is an example with the Prost version.
72 changes: 72 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ fn main() {
let path: PathBuf = [out_dir.clone(), "mod.rs".to_string()].iter().collect();
fs::write(path, "pub mod ttrpc;").unwrap();

generate_ttrpc(&out_dir);

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.

To get unified internal APIs which was defined in ttrpc.proto, how about keeping build script untouched?

I think we can try to avoid so many condition compiling sentences like #[cfg(not(feature = "prost"))] in code.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

right ,I think adding a transformation to the camel hump naming convention can reduce this conditional compilation code

}

#[cfg(not(feature = "prost"))]
fn generate_ttrpc(out_dir: &str) {
let customize = protobuf_codegen::Customize::default()
.gen_mod_rs(false)
.generate_accessors(true);
Expand All @@ -20,3 +25,70 @@ fn main() {
.run()
.expect("Codegen failed.");
}

#[cfg(feature = "prost")]
fn generate_ttrpc(out_dir: &str) {
let mut config = prost_build::Config::new();
config
.out_dir(out_dir)
.compile_well_known_types()
.protoc_arg("--experimental_allow_proto3_optional")
.enum_attribute("Code", "#[allow(non_camel_case_types)]")
.compile_protos(&["src/ttrpc.proto"], &["src"])
.expect("Codegen failed");

// read ttrpc.rs
let ttrpc_path = format!("{}/ttrpc.rs", out_dir);
let content = fs::read_to_string(&ttrpc_path).expect("Failed to read ttrpc.rs");

// define the enum value name pairs
let replacements = [
("Ok", "OK"),
("Cancelled", "CANCELLED"),
("Unknown", "UNKNOWN"),
("InvalidArgument", "INVALID_ARGUMENT"),
("DeadlineExceeded", "DEADLINE_EXCEEDED"),
("NotFound", "NOT_FOUND"),
("AlreadyExists", "ALREADY_EXISTS"),
("PermissionDenied", "PERMISSION_DENIED"),
("Unauthenticated", "UNAUTHENTICATED"),
("ResourceExhausted", "RESOURCE_EXHAUSTED"),
("FailedPrecondition", "FAILED_PRECONDITION"),
("Aborted", "ABORTED"),
("OutOfRange", "OUT_OF_RANGE"),
("Unimplemented", "UNIMPLEMENTED"),
("Internal", "INTERNAL"),
("Unavailable", "UNAVAILABLE"),
("DataLoss", "DATA_LOSS"),
];

// replace the enum value in the file
let mut modified_content = content.clone();

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.

Refactor/performance: please avoid rewriting Prost-generated Rust as text. This is coupled to Prost's formatting and performs many full-string replacement passes; content.clone() also duplicates the whole file immediately. Preserve the public enum spelling through a small compatibility layer/associated constants or generator configuration. If this remains temporarily, at least move content instead of cloning it.


// replace the enum definition
for (pascal_case, upper_case) in &replacements {
// replace the enum definition line
let enum_pattern = format!(" {} = ", pascal_case);
let enum_replacement = format!(" {} = ", upper_case);
modified_content = modified_content.replace(&enum_pattern, &enum_replacement);

// replace the as_str_name function
let match_pattern = format!(" Self::{} => ", pascal_case);
let match_replacement = format!(" Self::{} => ", upper_case);
modified_content = modified_content.replace(&match_pattern, &match_replacement);

// replace the from_str_name function
let from_str_pattern = format!(
" \"{}\" => Some(Self::{})",
upper_case, pascal_case
);
let from_str_replacement = format!(
" \"{}\" => Some(Self::{})",
upper_case, upper_case
);
modified_content = modified_content.replace(&from_str_pattern, &from_str_replacement);
}

// write the modified content back to the file
fs::write(&ttrpc_path, modified_content).expect("Failed to write modified ttrpc.rs");
}
24 changes: 24 additions & 0 deletions codegen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "ttrpc-codegen"
version = "1.0.0"
edition = "2021"
authors = ["The Ant Group Kata Team <kata@list.alibaba-inc.com>"]
license = "Apache-2.0"
keywords = ["codegen", "ttrpc", "protobuf"]
description = "Rust codegen for ttrpc using prost crate"
categories = ["network-programming", "development-tools::build-utils"]
repository = "https://github.com/containerd/ttrpc-rust/tree/master/codegen"
homepage = "https://github.com/containerd/ttrpc-rust/tree/master/codegen"
readme = "README.md"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
prost = "0.11"
prost-types = "0.11"
prost-build = "0.11"
proc-macro2 = "1.0"
quote = "1.0"
anyhow = "^1.0"
lazy_static = "1.4"
regex = "1.7"
35 changes: 35 additions & 0 deletions codegen/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
all: debug test

#
# Build
#

.PHONY: debug
debug:
cargo build --verbose --all-targets

.PHONY: release
release:
cargo build --release

.PHONY: build
build: debug

#
# Tests and linters
#

.PHONY: test
test:
cargo test --verbose

.PHONY: check
check:
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings

.PHONY: deps
deps:
rustup update stable
rustup default stable
rustup component add rustfmt clippy
34 changes: 34 additions & 0 deletions codegen/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Ttrpc-rust Codegen

## Getting started

Please ensure that the protoc has been installed on your local environment. Then
write the following code into "build.rs".

```rust
let mut protos = vec![
"protocols/protos/health.proto",
"protocols/protos/agent.proto",
"protocols/protos/oci.proto",
];

let includes = vec!["protocols/protos"];

let codegen = CodegenBuilder::new()
.set_out_dir(&"protocols/sync")
.set_protos(&protos)
.set_includes(&includes)
.set_serde(true)
.set_async_mode(AsyncMode::None)
.set_generate_service(true)
.build()
.unwrap();
codegen.generate().unwrap();
```

Add ttrpc-codegen to "build-dependencies" section in "Cargo.toml".

```toml
[build-dependencies]
ttrpc-codegen = "1.0"
```
Loading