protoc_gen_prost/
generator.rs

1//! Code generator modules
2
3use prost_types::compiler::{
4    code_generator_response::{Feature, File},
5    CodeGeneratorResponse,
6};
7
8use crate::ModuleRequestSet;
9
10mod core;
11mod file_descriptor_set;
12
13pub(crate) use self::{core::CoreProstGenerator, file_descriptor_set::FileDescriptorSetGenerator};
14
15/// A code generation result
16pub type Result = std::result::Result<Vec<File>, Error>;
17/// A code generation error
18pub type Error = Box<dyn std::error::Error + Send + Sync + 'static>;
19
20/// Extension function to assist in converting [`Result`] into a [`CodeGeneratorResponse`]
21pub trait GeneratorResultExt {
22    /// Unwrap a [`Result`], producing the relevant [`CodeGeneratorResponse`]
23    fn unwrap_codegen_response(self) -> CodeGeneratorResponse;
24}
25
26impl GeneratorResultExt for Result {
27    fn unwrap_codegen_response(self) -> CodeGeneratorResponse {
28        match self {
29            Ok(file) => CodeGeneratorResponse {
30                file,
31                supported_features: Some(Feature::Proto3Optional as u64),
32                ..Default::default()
33            },
34            Err(error) => error_to_codegen_response(&*error),
35        }
36    }
37}
38
39fn error_to_codegen_response(error: &dyn std::error::Error) -> CodeGeneratorResponse {
40    CodeGeneratorResponse {
41        error: Some(error.to_string()),
42        supported_features: Some(Feature::Proto3Optional as u64),
43        ..Default::default()
44    }
45}
46
47/// A code generator
48pub trait Generator {
49    /// Generate one or more files based on the input request
50    fn generate(&mut self, module_request_set: &ModuleRequestSet) -> Result;
51
52    /// Chain multiple generators together, returning their composite output
53    fn chain<G>(self, next: G) -> ChainedGenerator<Self, G>
54    where
55        Self: Sized,
56    {
57        ChainedGenerator {
58            generator1: self,
59            generator2: next,
60        }
61    }
62}
63
64/// A chain of generators, executed sequentially
65///
66/// Executes `G1` followed by `G2`, returning generated files in the same order as
67/// produced. Execution short circuits in the event `G1` returns an error.
68pub struct ChainedGenerator<G1, G2> {
69    generator1: G1,
70    generator2: G2,
71}
72
73impl<G1, G2> Generator for ChainedGenerator<G1, G2>
74where
75    G1: Generator,
76    G2: Generator,
77{
78    fn generate(&mut self, module_request_set: &ModuleRequestSet) -> Result {
79        let mut files = self.generator1.generate(module_request_set)?;
80        files.extend(self.generator2.generate(module_request_set)?);
81        Ok(files)
82    }
83}
84
85impl<G> Generator for Option<G>
86where
87    G: Generator,
88{
89    fn generate(&mut self, module_request_set: &ModuleRequestSet) -> Result {
90        if let Some(slf) = self {
91            slf.generate(module_request_set)
92        } else {
93            Ok(Vec::new())
94        }
95    }
96}