Skip to content

Commit 56a5a0a

Browse files
committed
Merge branch 'prost' of https://github.com/justxuewei/ttrpc-rust into prost
2 parents d713dd4 + bfa8710 commit 56a5a0a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+4744
-32
lines changed

.github/workflows/bvt.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ jobs:
2929
make -C compiler
3030
make -C ttrpc-codegen
3131
make -C example build-examples
32+
make -C example2 build-examples
3233
# It's important for windows to fail correctly
3334
# https://github.com/actions/runner-images/issues/6668
3435
shell: bash

Cargo.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ description = "A Rust version of ttrpc."
1212
rust-version = "1.70"
1313

1414
[dependencies]
15-
protobuf = { version = "3.1.0" }
15+
prost = { version = "0.11", optional = true }
16+
protobuf = "3.1.0"
1617
libc = { version = "0.2.59", features = [ "extra_traits" ] }
1718
nix = "0.26.2"
1819
log = "0.4"
@@ -33,11 +34,13 @@ tokio-vsock = { version = "0.4.0", optional = true }
3334
# lock home to avoid conflict with latest version
3435
home = "=0.5.9"
3536
protobuf-codegen = "3.1.0"
37+
prost-build = { version = "0.11", optional = true }
3638

3739
[features]
3840
default = ["sync"]
39-
async = ["async-trait", "tokio", "futures", "tokio-vsock"]
41+
async = ["dep:async-trait", "dep:tokio", "dep:futures", "dep:tokio-vsock"]
4042
sync = []
43+
prost = ["dep:prost", "dep:prost-build"]
4144

4245
[package.metadata.docs.rs]
4346
all-features = true

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
export PROTOC=${HOME}/protoc/bin/protoc
2+
13
all: debug test
24

35
#
@@ -31,7 +33,8 @@ endif
3133
.PHONY: check
3234
check:
3335
cargo fmt --all -- --check
34-
cargo clippy --all-targets --all-features -- -D warnings
36+
cargo clippy --all-targets --features sync,async -- -D warnings
37+
cargo clippy --all-targets --features sync,async,prost -- -D warnings
3538

3639
.PHONY: check-all
3740
check-all:

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,19 @@ cargo update
138138
cargo install --force --path .
139139
```
140140
3. Build your project.
141+
142+
# ttrpc-rust with the Prost
143+
144+
The new version of the ttrpc-rust is built with the Prost crate, a modern
145+
protobuf compiler written by Rust. There are certain different behaviors from
146+
the Rust-protobuf version:
147+
148+
1. The protoc should be installed.
149+
2. Enabling "prost" feature for the ttrpc-rust.
150+
3. The Rust files are named based on their package name, rather than the proto
151+
filename, e.g. `ttrpc = { version = "1.0", features = ["prost"] }`.
152+
4. Some variable names are different, e.g. for "cpu", "CPU" is generated by the
153+
Rust-protobuf, and "Cpu" is genereated by the Prost.
154+
155+
The "example" is an example with the Rust-protobuf version, and the "example2"
156+
is an example with the Prost version.

build.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ fn main() {
77
let path: PathBuf = [out_dir.clone(), "mod.rs".to_string()].iter().collect();
88
fs::write(path, "pub mod ttrpc;").unwrap();
99

10+
generate_ttrpc(&out_dir);
11+
}
12+
13+
#[cfg(not(feature = "prost"))]
14+
fn generate_ttrpc(out_dir: &str) {
1015
let customize = protobuf_codegen::Customize::default()
1116
.gen_mod_rs(false)
1217
.generate_accessors(true);
@@ -20,3 +25,13 @@ fn main() {
2025
.run()
2126
.expect("Codegen failed.");
2227
}
28+
29+
#[cfg(feature = "prost")]
30+
fn generate_ttrpc(out_dir: &str) {
31+
prost_build::Config::new()
32+
.out_dir(out_dir)
33+
.compile_well_known_types()
34+
.protoc_arg("--experimental_allow_proto3_optional")
35+
.compile_protos(&["src/ttrpc.proto"], &["src"])
36+
.expect("Codegen failed")
37+
}

codegen/Cargo.toml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[package]
2+
name = "ttrpc-codegen"
3+
version = "1.0.0"
4+
edition = "2021"
5+
authors = ["The Ant Group Kata Team <kata@list.alibaba-inc.com>"]
6+
license = "Apache-2.0"
7+
keywords = ["codegen", "ttrpc", "protobuf"]
8+
description = "Rust codegen for ttrpc using prost crate"
9+
categories = ["network-programming", "development-tools::build-utils"]
10+
repository = "https://github.com/containerd/ttrpc-rust/tree/master/codegen"
11+
homepage = "https://github.com/containerd/ttrpc-rust/tree/master/codegen"
12+
readme = "README.md"
13+
14+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
15+
16+
[dependencies]
17+
prost = "0.11"
18+
prost-types = "0.11"
19+
prost-build = "0.11"
20+
proc-macro2 = "1.0"
21+
quote = "1.0"
22+
anyhow = "^1.0"
23+
lazy_static = "1.4"
24+
regex = "1.7"

codegen/Makefile

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
all: debug test
2+
3+
#
4+
# Build
5+
#
6+
7+
.PHONY: debug
8+
debug:
9+
cargo build --verbose --all-targets
10+
11+
.PHONY: release
12+
release:
13+
cargo build --release
14+
15+
.PHONY: build
16+
build: debug
17+
18+
#
19+
# Tests and linters
20+
#
21+
22+
.PHONY: test
23+
test:
24+
cargo test --verbose
25+
26+
.PHONY: check
27+
check:
28+
cargo fmt --all -- --check
29+
cargo clippy --all-targets --all-features -- -D warnings
30+
31+
.PHONY: deps
32+
deps:
33+
rustup update stable
34+
rustup default stable
35+
rustup component add rustfmt clippy

codegen/README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Ttrpc-rust Codegen
2+
3+
## Getting started
4+
5+
Please ensure that the protoc has been installed on your local environment. Then
6+
write the following code into "build.rs".
7+
8+
```rust
9+
let mut protos = vec![
10+
"protocols/protos/health.proto",
11+
"protocols/protos/agent.proto",
12+
"protocols/protos/oci.proto",
13+
];
14+
15+
let includes = vec!["protocols/protos"];
16+
17+
let codegen = CodegenBuilder::new()
18+
.set_out_dir(&"protocols/sync")
19+
.set_protos(&protos)
20+
.set_includes(&includes)
21+
.set_serde(true)
22+
.set_async_mode(AsyncMode::None)
23+
.set_generate_service(true)
24+
.build()
25+
.unwrap();
26+
codegen.generate().unwrap();
27+
```
28+
29+
Add ttrpc-codegen to "build-dependencies" section in "Cargo.toml".
30+
31+
```toml
32+
[build-dependencies]
33+
ttrpc-codegen = "1.0"
34+
```

codegen/src/codegen.rs

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
use anyhow::{anyhow, Context, Result};
2+
use prost::Message;
3+
use prost_build::Config;
4+
use prost_types::FileDescriptorSet;
5+
use std::{
6+
fs::{self, File},
7+
io::{BufReader, Read, Write},
8+
path::{Path, PathBuf},
9+
};
10+
11+
use crate::svcgen::{AsyncMode, TtrpcServiceGenerator};
12+
13+
const FILE_DESCRIPTOR_SET: &str = "fd_set.bin";
14+
15+
pub struct Codegen<'a, P: AsRef<Path>> {
16+
out_dir: &'a P,
17+
protos: &'a [P],
18+
includes: &'a [P],
19+
/// Whether to enable serde
20+
serde: bool,
21+
async_mode: AsyncMode,
22+
/// Whether to generate service
23+
generate_service: bool,
24+
}
25+
26+
impl<'a, P> Codegen<'a, P>
27+
where
28+
P: AsRef<Path>,
29+
{
30+
pub fn generate(&self) -> Result<()> {
31+
self.compile_protos().context("Compile protos")?;
32+
self.write_header().context("Write header")?;
33+
self.clean_up().context("Clean up")?;
34+
35+
Ok(())
36+
}
37+
38+
// TODO: Do not write header to the files that already has the header
39+
// TODO: Write header to the files generated by the codegen
40+
fn write_header(&self) -> Result<()> {
41+
// Read fd_set.bin
42+
let f = File::open(PathBuf::from(self.out_dir.as_ref()).join(FILE_DESCRIPTOR_SET))
43+
.context("Open fd_set.bin")?;
44+
let mut reader = BufReader::new(f);
45+
let mut buffer = Vec::new();
46+
reader.read_to_end(&mut buffer).context("Read fd_set.bin")?;
47+
48+
let fd_set = FileDescriptorSet::decode(&buffer as &[u8]).context("Decode fd_set")?;
49+
50+
for fd in fd_set.file.iter() {
51+
let rs_path = PathBuf::from(self.out_dir.as_ref()).join(format!("{}.rs", fd.package()));
52+
let mut f = match File::open(&rs_path) {
53+
Ok(f) => f,
54+
_ => continue,
55+
};
56+
let header = format!(
57+
r#"// This file is generated by ttrpc-codegen {}. Do not edit
58+
// @generated
59+
60+
"#,
61+
env!("CARGO_PKG_VERSION")
62+
);
63+
64+
let mut buf = Vec::<u8>::new();
65+
buf.write(header.as_bytes()).context("Write header")?;
66+
f.read_to_end(&mut buf)
67+
.context(format!("Read from rust file {:?}", rs_path))?;
68+
let mut f = File::create(&rs_path).context(format!("Open rust file {:?}", rs_path))?;
69+
f.write_all(buf.as_slice())
70+
.context(format!("Write to rust file {:?}", rs_path))?;
71+
}
72+
73+
Ok(())
74+
}
75+
76+
fn compile_protos(&self) -> Result<()> {
77+
let mut config = Config::new();
78+
config.out_dir(self.out_dir.as_ref());
79+
config.service_generator(Box::new(TtrpcServiceGenerator::new(self.async_mode)));
80+
config.protoc_arg("--experimental_allow_proto3_optional");
81+
config.compile_well_known_types();
82+
config.file_descriptor_set_path(
83+
PathBuf::from(self.out_dir.as_ref()).join(FILE_DESCRIPTOR_SET),
84+
);
85+
if self.generate_service {
86+
config.include_file("_include.rs");
87+
if self.serde {
88+
config
89+
.message_attribute(".", "#[derive(::serde::Serialize, ::serde::Deserialize)]");
90+
}
91+
}
92+
config
93+
.compile_protos(self.protos, self.includes)
94+
.context("Compile protos by prost")?;
95+
Ok(())
96+
}
97+
98+
fn clean_up(&self) -> Result<()> {
99+
fs::remove_file(PathBuf::from(self.out_dir.as_ref()).join(FILE_DESCRIPTOR_SET))
100+
.context("Remove fd_set.bin")?;
101+
Ok(())
102+
}
103+
}
104+
105+
#[derive(Default)]
106+
pub struct CodegenBuilder<'a, P: AsRef<Path> + Default> {
107+
out_dir: Option<&'a P>,
108+
protos: Option<&'a [P]>,
109+
includes: Option<&'a [P]>,
110+
/// Whether to enable serde
111+
serde: Option<bool>,
112+
async_mode: Option<AsyncMode>,
113+
/// Whether to generate service
114+
generate_service: Option<bool>,
115+
}
116+
117+
impl<'a, P> CodegenBuilder<'a, P>
118+
where
119+
P: AsRef<Path> + Default,
120+
{
121+
pub fn new() -> Self {
122+
Default::default()
123+
}
124+
125+
pub fn set_out_dir(mut self, out_dir: &'a P) -> Self {
126+
self.out_dir = Some(out_dir);
127+
self
128+
}
129+
130+
pub fn set_protos(mut self, protos: &'a [P]) -> Self {
131+
self.protos = Some(protos);
132+
self
133+
}
134+
135+
pub fn set_includes(mut self, includes: &'a [P]) -> Self {
136+
self.includes = Some(includes);
137+
self
138+
}
139+
140+
pub fn set_serde(mut self, serde: bool) -> Self {
141+
self.serde = Some(serde);
142+
self
143+
}
144+
145+
pub fn set_async_mode(mut self, async_mode: AsyncMode) -> Self {
146+
self.async_mode = Some(async_mode);
147+
self
148+
}
149+
150+
pub fn set_generate_service(mut self, generate_service: bool) -> Self {
151+
self.generate_service = Some(generate_service);
152+
self
153+
}
154+
155+
pub fn build(&self) -> Result<Codegen<'a, P>> {
156+
let out_dir = match self.out_dir {
157+
Some(out_dir) => out_dir,
158+
None => return Err(anyhow!("The out dir is required.")),
159+
};
160+
161+
let protos = match self.protos {
162+
Some(protos) => protos,
163+
None => return Err(anyhow!("The protos are required.")),
164+
};
165+
166+
let includes = match self.includes {
167+
Some(includes) => includes,
168+
None => return Err(anyhow!("The includes are required.")),
169+
};
170+
171+
let serde = self.serde.unwrap_or(false);
172+
173+
let async_mode = match self.async_mode {
174+
Some(mode) => mode,
175+
None => AsyncMode::None,
176+
};
177+
178+
let generate_service = self.generate_service.unwrap_or(false);
179+
180+
Ok(Codegen {
181+
out_dir,
182+
protos,
183+
includes,
184+
serde,
185+
async_mode,
186+
generate_service,
187+
})
188+
}
189+
}

codegen/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
mod codegen;
2+
mod svcgen;
3+
mod util;
4+
5+
pub use codegen::{Codegen, CodegenBuilder};
6+
pub use svcgen::AsyncMode;

0 commit comments

Comments
 (0)