protoc_gen_rust_temporal/lib.rs
1//! `protoc-gen-rust-temporal` library entry point.
2//!
3//! The binary in `main.rs` is a thin stdin/stdout shell; the actual
4//! `CodeGeneratorRequest -> CodeGeneratorResponse` pipeline lives here so
5//! tests (and the eventual golden harness) can exercise it without spawning a
6//! subprocess.
7//!
8//! Phase 0 ships only the plumbing: `run_with_pool` accepts a descriptor pool
9//! that already has `temporal.v1.*` extensions attached (per `main.rs`'s
10//! descriptor-pool extraction trick), plus the set of files the caller asked
11//! the plugin to generate. Phase 1 wires up `parse → validate → render`.
12
13use std::collections::HashSet;
14
15use anyhow::Result;
16use prost_reflect::DescriptorPool;
17use prost_types::compiler::code_generator_response::File;
18
19pub mod model;
20pub mod parse;
21pub mod render;
22pub mod validate;
23
24/// Generated prost types for cludden's `temporal.v1.*` annotation schema and
25/// the transitively-referenced `temporal.api.enums.v1` enums. The parser uses
26/// `prost-reflect` against the descriptor pool, but these types are exposed
27/// for downstream introspection (e.g. tests round-tripping options).
28pub mod temporal {
29 pub mod v1 {
30 include!(concat!(env!("OUT_DIR"), "/temporal.v1.rs"));
31 }
32 pub mod api {
33 pub mod enums {
34 pub mod v1 {
35 include!(concat!(env!("OUT_DIR"), "/temporal.api.enums.v1.rs"));
36 }
37 }
38 }
39}
40
41/// Run the plugin pipeline against a fully-populated descriptor pool.
42///
43/// `files_to_generate` is the set of `.proto` file paths the plugin was asked
44/// to emit code for (mirrors `CodeGeneratorRequest::file_to_generate`).
45pub fn run_with_pool(
46 pool: &DescriptorPool,
47 files_to_generate: &HashSet<String>,
48) -> Result<Vec<File>> {
49 let services = parse::parse(pool, files_to_generate)?;
50 let mut files = Vec::with_capacity(services.len());
51 for service in &services {
52 validate::validate(service)?;
53 let content = render::render(service);
54 let name = output_file_name(service);
55 files.push(File {
56 name: Some(name),
57 insertion_point: None,
58 content: Some(content),
59 generated_code_info: None,
60 });
61 }
62 Ok(files)
63}
64
65/// Output path for the generated module file. Matches cludden's convention:
66/// the source proto's directory, with `_temporal.rs` appended to the file
67/// stem so consumer build scripts can `include!` it deterministically.
68fn output_file_name(svc: &crate::model::ServiceModel) -> String {
69 let stem = svc.source_file.trim_end_matches(".proto");
70 format!("{stem}_temporal.rs")
71}