Add service generator extensability

This commit is contained in:
NGnius (Graham) 2023-04-14 23:50:43 -04:00
parent 3f2fde50c9
commit 79c95a0018
4 changed files with 92 additions and 13 deletions

1
Cargo.lock generated
View file

@ -287,6 +287,7 @@ dependencies = [
"prettyplease 0.2.4", "prettyplease 0.2.4",
"proc-macro2", "proc-macro2",
"prost-build", "prost-build",
"prost-types",
"protox", "protox",
"quote", "quote",
"syn 2.0.13", "syn 2.0.13",

View file

@ -13,6 +13,7 @@ description = "Yet another remote procedure call library - codegen"
# gRPC/protobuf # gRPC/protobuf
protox = "0.3" protox = "0.3"
prost-build = "0.11" prost-build = "0.11"
prost-types = "0.11"
# code gen # code gen
prettyplease = "0.2" prettyplease = "0.2"

View file

@ -3,37 +3,114 @@ use std::convert::AsRef;
use std::iter::IntoIterator; use std::iter::IntoIterator;
use prost_build::Config; use prost_build::Config;
use prost_build::{Service, ServiceGenerator};
use prost_types::FileDescriptorSet;
/// Proto -> Rust transpiler configurator
pub struct Transpiler {
prost_config: Config,
files: FileDescriptorSet,
service_generator: MergedServiceGenerator,
}
impl Transpiler {
pub fn new(
files: impl IntoIterator<Item = impl AsRef<Path>>,
includes: impl IntoIterator<Item = impl AsRef<Path>>
) -> Result<Self, impl std::error::Error> {
Ok::<_, protox::Error>(Self {
prost_config: Config::new(),
files: protox::compile(files, includes)?,
service_generator: MergedServiceGenerator::empty()
})
}
/// Generate client and server service implementations
pub fn generate_all(mut self) -> Self {
self.service_generator.add_service(super::ProtobufServiceGenerator::all());
self
}
/// Generate server services implementations
pub fn generate_server(mut self) -> Self {
self.service_generator.add_service(super::ProtobufServiceGenerator::server());
self
}
/// Generate client services implementations
pub fn generate_client(mut self) -> Self {
self.service_generator.add_service(super::ProtobufServiceGenerator::client());
self
}
/// Add additional custom service generator
pub fn with_service_generator<S: ServiceGenerator + 'static>(mut self, gen: S) -> Self {
self.service_generator.add_service(gen);
self
}
/// Actually generate code
pub fn transpile(mut self) -> std::io::Result<()> {
self.prost_config
.service_generator(Box::new(self.service_generator))
.compile_fds(self.files)
}
}
struct MergedServiceGenerator {
generators: Vec<Box<dyn ServiceGenerator + 'static>>,
}
impl MergedServiceGenerator {
fn empty() -> Self {
Self {
generators: Vec::new(),
}
}
fn add_service<S: ServiceGenerator + 'static>(&mut self, service: S) -> &mut Self {
self.generators.push(Box::new(service));
self
}
}
impl ServiceGenerator for MergedServiceGenerator {
fn generate(&mut self, service: Service, buf: &mut String) {
for gen in &mut self.generators {
gen.generate(service.clone(), buf);
}
}
}
/// Compile proto files into Rust with server and client implementations /// Compile proto files into Rust with server and client implementations
pub fn compile( pub fn compile(
files: impl IntoIterator<Item = impl AsRef<Path>>, files: impl IntoIterator<Item = impl AsRef<Path>>,
includes: impl IntoIterator<Item = impl AsRef<Path>> includes: impl IntoIterator<Item = impl AsRef<Path>>
) { ) {
let file_descriptors = protox::compile(files, includes).unwrap(); Transpiler::new(files, includes).unwrap()
Config::new() .generate_all()
.service_generator(Box::new(super::ProtobufServiceGenerator::all())) .transpile()
.compile_fds(file_descriptors)
.unwrap(); .unwrap();
} }
/// Compile proto files into Rust with only client implementations
pub fn compile_clients( pub fn compile_clients(
files: impl IntoIterator<Item = impl AsRef<Path>>, files: impl IntoIterator<Item = impl AsRef<Path>>,
includes: impl IntoIterator<Item = impl AsRef<Path>>, includes: impl IntoIterator<Item = impl AsRef<Path>>,
) { ) {
let file_descriptors = protox::compile(files, includes).unwrap(); Transpiler::new(files, includes).unwrap()
Config::new() .generate_client()
.service_generator(Box::new(super::ProtobufServiceGenerator::client())) .transpile()
.compile_fds(file_descriptors)
.unwrap(); .unwrap();
} }
/// Compile proto files into Rust with only server implementations
pub fn compile_servers( pub fn compile_servers(
files: impl IntoIterator<Item = impl AsRef<Path>>, files: impl IntoIterator<Item = impl AsRef<Path>>,
includes: impl IntoIterator<Item = impl AsRef<Path>>, includes: impl IntoIterator<Item = impl AsRef<Path>>,
) { ) {
let file_descriptors = protox::compile(files, includes).unwrap(); Transpiler::new(files, includes).unwrap()
Config::new() .generate_server()
.service_generator(Box::new(super::ProtobufServiceGenerator::server())) .transpile()
.compile_fds(file_descriptors)
.unwrap(); .unwrap();
} }

View file

@ -1,5 +1,5 @@
mod builder; mod builder;
mod service_gen; mod service_gen;
pub use builder::{compile, compile_servers, compile_clients}; pub use builder::{compile, compile_servers, compile_clients, Transpiler};
pub(crate) use service_gen::ProtobufServiceGenerator; pub(crate) use service_gen::ProtobufServiceGenerator;