#![warn(missing_docs)]
#![warn(rustdoc::broken_intra_doc_links)]
pub use protobuf_codegen::{
Customize as ProtobufCustomize, CustomizeCallback as ProtobufCustomizeCallback,
};
use std::io;
use std::path::Path;
use std::path::PathBuf;
pub use ttrpc_compiler::Customize;
#[derive(Debug, Default)]
pub struct Codegen {
out_dir: Option<PathBuf>,
includes: Vec<PathBuf>,
inputs: Vec<PathBuf>,
rust_protobuf: bool,
rust_protobuf_codegen: protobuf_codegen::Codegen,
customize: Customize,
}
impl Codegen {
pub fn new() -> Self {
Self::default()
}
pub fn out_dir(&mut self, out_dir: impl AsRef<Path>) -> &mut Self {
self.out_dir = Some(out_dir.as_ref().to_owned());
self
}
pub fn include(&mut self, include: impl AsRef<Path>) -> &mut Self {
self.includes.push(include.as_ref().to_owned());
self
}
pub fn includes(&mut self, includes: impl IntoIterator<Item = impl AsRef<Path>>) -> &mut Self {
for include in includes {
self.include(include);
}
self
}
pub fn input(&mut self, input: impl AsRef<Path>) -> &mut Self {
self.inputs.push(input.as_ref().to_owned());
self
}
pub fn inputs(&mut self, inputs: impl IntoIterator<Item = impl AsRef<Path>>) -> &mut Self {
for input in inputs {
self.input(input);
}
self
}
pub fn rust_protobuf(&mut self) -> &mut Self {
self.rust_protobuf = true;
self
}
pub fn rust_protobuf_customize(&mut self, customize: ProtobufCustomize) -> &mut Self {
self.rust_protobuf_codegen.customize(customize);
self
}
pub fn rust_protobuf_customize_callback(
&mut self,
customize: impl ProtobufCustomizeCallback,
) -> &mut Self {
self.rust_protobuf_codegen.customize_callback(customize);
self
}
pub fn customize(&mut self, customize: Customize) -> &mut Self {
self.customize = customize;
self
}
pub fn run(&mut self) -> io::Result<()> {
let includes: Vec<&Path> = self.includes.iter().map(|p| p.as_path()).collect();
let inputs: Vec<&Path> = self.inputs.iter().map(|p| p.as_path()).collect();
let p = parse_and_typecheck(&includes, &inputs)?;
let dst_path = self.out_dir.clone().unwrap_or_else(|| {
std::env::var("OUT_DIR").map_or_else(
|_| std::env::current_dir().unwrap_or_default(),
PathBuf::from,
)
});
if self.rust_protobuf {
self.rust_protobuf_codegen
.pure()
.out_dir(&dst_path)
.inputs(&self.inputs)
.includes(&self.includes)
.run()
.expect("Gen rust protobuf failed.");
}
ttrpc_compiler::codegen::gen_and_write(
p.file_descriptors.as_slice(),
&p.relative_paths,
&dst_path,
&self.customize,
)
}
}
#[doc(hidden)]
pub struct ParsedAndTypechecked {
pub relative_paths: Vec<String>,
pub file_descriptors: Vec<protobuf::descriptor::FileDescriptorProto>,
}
#[doc(hidden)]
pub fn parse_and_typecheck(
includes: &[&Path],
input: &[&Path],
) -> io::Result<ParsedAndTypechecked> {
let mut parser = protobuf_parse::Parser::new();
parser
.pure()
.includes(includes.iter().copied())
.inputs(input.iter().copied());
let parsed = parser
.parse_and_typecheck()
.map_err(|error| io::Error::other(format!("{error:#}")))?;
Ok(ParsedAndTypechecked {
relative_paths: parsed
.relative_paths
.into_iter()
.map(|path| path.to_string())
.collect(),
file_descriptors: parsed.file_descriptors,
})
}