use std::{
env, fs,
io::Write,
path::{Path, PathBuf},
};
use miette::IntoDiagnostic;
use protox::prost::Message;
fn main() -> miette::Result<()> {
compile_tonic_server_proto()?;
Ok(())
}
fn compile_tonic_server_proto() -> miette::Result<()> {
let crate_root =
PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR should be set"));
let dst_dir = crate_root.join("src").join("generated");
let proto_dir = crate_root.join("proto");
fs::remove_file(dst_dir.join("api.rs")).into_diagnostic().ok();
let out_dir = env::var("OUT_DIR").into_diagnostic()?;
let file_descriptor_path = PathBuf::from(out_dir).join("file_descriptor_set.bin");
let protos = &[proto_dir.join("api.proto")];
let includes = &[proto_dir];
let file_descriptors = protox::compile(protos, includes)?;
fs::write(&file_descriptor_path, file_descriptors.encode_to_vec()).into_diagnostic()?;
let nostd_path = dst_dir.join("nostd");
let std_path = dst_dir.join("std");
build_tonic_server(&file_descriptor_path, &std_path, protos, includes, false)?;
build_tonic_server(&file_descriptor_path, &nostd_path, protos, includes, true)?;
let nostd_file_path = nostd_path.join("api.rs");
let file_content = fs::read_to_string(&nostd_file_path).into_diagnostic()?;
let updated_content = file_content
.replace("std::result", "core::result")
.replace("std::marker", "core::marker")
.replace("format!", "alloc::format!");
let mut file = fs::OpenOptions::new()
.write(true)
.truncate(true)
.open(&nostd_file_path)
.into_diagnostic()?;
file.write_all(updated_content.as_bytes()).into_diagnostic()?;
Ok(())
}
fn build_tonic_server(
file_descriptor_path: &Path,
out_dir: &Path,
protos: &[PathBuf],
includes: &[PathBuf],
for_no_std: bool,
) -> miette::Result<()> {
tonic_build::configure()
.file_descriptor_set_path(file_descriptor_path)
.skip_protoc_run()
.out_dir(out_dir)
.build_server(!for_no_std)
.build_transport(!for_no_std)
.compile_protos_with_config(prost_build::Config::new(), protos, includes)
.into_diagnostic()
}