protoc_gen_prost_serde/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use std::str;
4
5use prost::Message;
6use prost_types::compiler::CodeGeneratorRequest;
7use protoc_gen_prost::{Generator, InvalidParameter, ModuleRequestSet, Param, Params};
8
9use self::generator::PbJsonGenerator;
10
11mod generator;
12
13/// Execute the core _Prost!_ generator from a raw [`CodeGeneratorRequest`]
14pub fn execute(raw_request: &[u8]) -> protoc_gen_prost::Result {
15    let request = CodeGeneratorRequest::decode(raw_request)?;
16    let params = request.parameter().parse::<Parameters>()?;
17
18    let mut builder = params.to_pbjson_builder();
19    for file in &request.proto_file {
20        builder.register_file_descriptor(file.clone());
21    }
22
23    let module_request_set = ModuleRequestSet::new(
24        request.file_to_generate,
25        request.proto_file,
26        raw_request,
27        params.default_package_filename.as_deref(),
28        params.flat_output_dir,
29    )?;
30
31    let files = PbJsonGenerator::new(builder, !params.no_include).generate(&module_request_set)?;
32
33    Ok(files)
34}
35
36/// Parameters use to configure [`Generator`]s built into `protoc-gen-prost-serde`
37///
38/// [`Generator`]: protoc_gen_prost::generators::Generator
39#[derive(Debug, Default)]
40struct Parameters {
41    default_package_filename: Option<String>,
42    extern_path: Vec<(String, String)>,
43    retain_enum_prefix: bool,
44    preserve_proto_field_names: bool,
45    ignore_unknown_fields: bool,
46    emit_fields: bool,
47    use_integers_for_enums: bool,
48    no_include: bool,
49    btree_map: Vec<String>,
50    flat_output_dir: bool,
51    exclude: Vec<String>,
52}
53
54impl Parameters {
55    fn to_pbjson_builder(&self) -> pbjson_build::Builder {
56        let mut builder = pbjson_build::Builder::new();
57
58        for (proto_path, rust_path) in &self.extern_path {
59            builder.extern_path(proto_path, rust_path);
60        }
61
62        if self.retain_enum_prefix {
63            builder.retain_enum_prefix();
64        }
65
66        if self.preserve_proto_field_names {
67            builder.preserve_proto_field_names();
68        }
69
70        if self.ignore_unknown_fields {
71            builder.ignore_unknown_fields();
72        }
73
74        if self.emit_fields {
75            builder.emit_fields();
76        }
77
78        if self.use_integers_for_enums {
79            builder.use_integers_for_enums();
80        }
81
82        if !self.btree_map.is_empty() {
83            builder.btree_map(self.btree_map.clone());
84        }
85
86        builder.btree_map(self.btree_map.clone());
87
88        if !self.exclude.is_empty() {
89            builder.exclude(self.exclude.clone());
90        }
91
92        builder
93    }
94}
95
96impl str::FromStr for Parameters {
97    type Err = InvalidParameter;
98    fn from_str(s: &str) -> Result<Self, Self::Err> {
99        let mut ret_val = Self::default();
100        for param in Params::from_protoc_plugin_opts(s)? {
101            match param {
102                Param::Parameter {
103                    param: "default_package_filename",
104                }
105                | Param::Value {
106                    param: "default_package_filename",
107                    ..
108                } => ret_val.default_package_filename = param.value().map(|s| s.into_owned()),
109                Param::Parameter {
110                    param: "retain_enum_prefix",
111                }
112                | Param::Value {
113                    param: "retain_enum_prefix",
114                    value: "true",
115                } => ret_val.retain_enum_prefix = true,
116                Param::Value {
117                    param: "retain_enum_prefix",
118                    value: "false",
119                } => (),
120                Param::Parameter {
121                    param: "preserve_proto_field_names",
122                }
123                | Param::Value {
124                    param: "preserve_proto_field_names",
125                    value: "true",
126                } => ret_val.preserve_proto_field_names = true,
127                Param::Value {
128                    param: "preserve_proto_field_names",
129                    value: "false",
130                } => (),
131                Param::Parameter {
132                    param: "ignore_unknown_fields",
133                }
134                | Param::Value {
135                    param: "ignore_unknown_fields",
136                    value: "true",
137                } => ret_val.ignore_unknown_fields = true,
138                Param::Parameter {
139                    param: "emit_fields",
140                }
141                | Param::Value {
142                    param: "emit_fields",
143                    value: "true",
144                } => ret_val.emit_fields = true,
145                Param::Parameter {
146                    param: "use_integers_for_enums",
147                }
148                | Param::Value {
149                    param: "use_integers_for_enums",
150                    value: "true",
151                } => ret_val.use_integers_for_enums = true,
152                Param::Parameter {
153                    param: "no_include",
154                }
155                | Param::Value {
156                    param: "no_include",
157                    value: "true",
158                } => ret_val.no_include = true,
159                Param::Value {
160                    param: "no_include",
161                    value: "false",
162                } => (),
163                Param::KeyValue {
164                    param: "extern_path",
165                    key: prefix,
166                    value: module,
167                } => ret_val.extern_path.push((prefix.to_string(), module)),
168                Param::Value {
169                    param: "btree_map",
170                    value,
171                } => ret_val.btree_map.push(value.to_string()),
172                Param::Parameter {
173                    param: "flat_output_dir",
174                }
175                | Param::Value {
176                    param: "flat_output_dir",
177                    value: "true",
178                } => ret_val.flat_output_dir = true,
179                Param::Value {
180                    param: "flat_output_dir",
181                    value: "false",
182                } => (),
183                Param::Value {
184                    param: "exclude",
185                    value: prefix,
186                } => ret_val.exclude.push(prefix.to_string()),
187                _ => return Err(InvalidParameter::from(param)),
188            }
189        }
190
191        Ok(ret_val)
192    }
193}