1use crate::model::rust::*;
2use crate::model::*;
3use std::convert::Infallible;
4
5const TUPLE_VARIABLE_NAME_REPLACEMENT: &str = "value";
6const DATAENUM_VARIABLE_NAME_REPLACEMENT: &str = "value";
7
8#[allow(clippy::module_name_repetitions)]
9#[derive(Debug, Clone, PartialOrd, PartialEq)]
10pub enum ProtobufType {
11 Bool,
12 #[allow(dead_code)]
13 SFixed32,
14 #[allow(dead_code)]
15 SFixed64,
16 UInt32,
17 UInt64,
18 SInt32,
19 SInt64,
20 String,
21 Bytes,
22 BitsReprByBytesAndBitsLen,
23 Repeated(Box<ProtobufType>),
24 OneOf(Vec<(String, ProtobufType)>),
25 Complex(String),
28}
29
30impl ProtobufType {
31 pub fn from(rust: &RustType) -> ProtobufType {
32 Model::definition_type_to_protobuf_type(rust)
33 }
34
35 pub fn to_rust(&self) -> RustType {
36 #[allow(clippy::match_same_arms)] match self {
38 ProtobufType::Bool => RustType::Bool,
39 ProtobufType::SFixed32 => RustType::I32(Range::inclusive(0, i32::MAX)),
40 ProtobufType::SFixed64 => RustType::I64(Range::inclusive(0, i64::MAX)),
41 ProtobufType::UInt32 => RustType::U32(Range::inclusive(0, u32::MAX)),
42 ProtobufType::UInt64 => RustType::U64(Range::none()),
43 ProtobufType::SInt32 => RustType::I32(Range::inclusive(0, i32::MAX)),
44 ProtobufType::SInt64 => RustType::I64(Range::inclusive(0, i64::MAX)),
45 ProtobufType::String => RustType::String(Size::Any, Charset::Utf8),
46 ProtobufType::Bytes => RustType::VecU8(Size::Any),
47 ProtobufType::BitsReprByBytesAndBitsLen => RustType::BitVec(Size::Any),
48 ProtobufType::Repeated(inner) => {
49 RustType::Vec(Box::new(inner.to_rust()), Size::Any, EncodingOrdering::Keep)
50 }
51 ProtobufType::OneOf(_) => panic!("ProtobufType::OneOf cannot be mapped to a RustType"),
52 ProtobufType::Complex(name) => RustType::Complex(name.clone(), None),
53 }
54 }
55
56 pub fn is_primitive(&self) -> bool {
57 #[allow(clippy::match_same_arms)] match self {
59 ProtobufType::Bool => true,
60 ProtobufType::SFixed32 => true,
61 ProtobufType::SFixed64 => true,
62 ProtobufType::UInt32 => true,
63 ProtobufType::UInt64 => true,
64 ProtobufType::SInt32 => true,
65 ProtobufType::SInt64 => true,
66 ProtobufType::String => true,
67 ProtobufType::Bytes | ProtobufType::BitsReprByBytesAndBitsLen => true,
68 ProtobufType::OneOf(_) => false,
69 ProtobufType::Complex(_) => false,
70 ProtobufType::Repeated(_) => false,
71 }
72 }
73}
74
75impl ToString for ProtobufType {
76 fn to_string(&self) -> String {
77 match self {
78 ProtobufType::Bool => "bool",
79 ProtobufType::SFixed32 => "sfixed32",
80 ProtobufType::SFixed64 => "sfixed64",
81 ProtobufType::UInt32 => "uint32",
82 ProtobufType::UInt64 => "uint64",
83 ProtobufType::SInt32 => "sint32",
84 ProtobufType::SInt64 => "sint64",
85 ProtobufType::String => "string",
86 ProtobufType::Bytes => "bytes",
87 ProtobufType::BitsReprByBytesAndBitsLen => "bytes",
88 ProtobufType::OneOf(_) => "oneof",
89 ProtobufType::Complex(name) => return name.clone(),
90 ProtobufType::Repeated(name) => return format!("repeated {}", name.to_string()),
91 }
92 .into()
93 }
94}
95
96pub trait ToProtobufType {
97 fn to_protobuf(&self) -> ProtobufType;
98}
99
100impl ToProtobufType for RustType {
101 fn to_protobuf(&self) -> ProtobufType {
102 ProtobufType::from(self)
103 }
104}
105
106#[derive(Debug, Clone, PartialOrd, PartialEq)]
107pub enum Protobuf {
108 Message(Vec<(String, ProtobufType)>),
109 Enum(Vec<String>),
110}
111
112impl Target for Protobuf {
113 type DefinitionType = Self;
114 type ValueReferenceType = Infallible;
115}
116
117impl Model<Protobuf> {
118 pub fn convert_rust_to_protobuf(rust_model: &Model<Rust>) -> Model<Protobuf> {
119 let mut model = Model {
120 name: rust_model.name.clone(),
121 oid: rust_model.oid.clone(),
122 imports: rust_model.imports.clone(),
123 definitions: Vec::with_capacity(rust_model.definitions.len()),
124 value_references: Vec::default(),
125 };
126 for Definition(name, rust) in &rust_model.definitions {
127 let proto = Self::definition_to_protobuf(rust);
128 model
129 .definitions
130 .push(Definition(proto_definition_name(name), proto));
131 }
132 model
133 }
134
135 pub fn definition_to_protobuf(rust: &Rust) -> Protobuf {
136 match rust {
137 Rust::Struct {
138 fields,
139 tag: _,
140 extension_after: _,
141 ordering: _,
142 } => {
143 let mut proto_fields = Vec::with_capacity(fields.len());
144 for field in fields.iter() {
145 proto_fields.push((
146 proto_field_name(field.name()),
147 Self::definition_type_to_protobuf_type(field.r#type()),
148 ));
149 }
150
151 Protobuf::Message(proto_fields)
152 }
153 Rust::Enum(r_enum) => {
154 Protobuf::Enum(r_enum.variants().map(|v| proto_variant_name(v)).collect())
155 }
156 Rust::DataEnum(enumeration) => {
157 let mut proto_enum = Vec::with_capacity(enumeration.len());
158 for variant in enumeration.variants() {
159 proto_enum.push((
160 proto_field_name(variant.name()),
161 Self::definition_type_to_protobuf_type(variant.r#type()),
162 ))
163 }
164 Protobuf::Message(vec![(
165 DATAENUM_VARIABLE_NAME_REPLACEMENT.into(),
166 ProtobufType::OneOf(proto_enum),
167 )])
168 }
169 Rust::TupleStruct { r#type: inner, .. } => Protobuf::Message(vec![(
170 TUPLE_VARIABLE_NAME_REPLACEMENT.into(),
171 Self::definition_type_to_protobuf_type(inner),
172 )]),
173 }
174 }
175
176 pub fn definition_type_to_protobuf_type(rust_type: &RustType) -> ProtobufType {
177 #[allow(clippy::match_same_arms)] match rust_type {
179 RustType::Bool => ProtobufType::Bool,
180 RustType::U8(_) => ProtobufType::UInt32,
181 RustType::I8(_) => ProtobufType::SInt32,
182 RustType::U16(_) => ProtobufType::UInt32,
183 RustType::I16(_) => ProtobufType::SInt32,
184 RustType::U32(_) => ProtobufType::UInt32,
185 RustType::I32(_) => ProtobufType::SInt32,
186 RustType::U64(_) => ProtobufType::UInt64,
187 RustType::I64(_) => ProtobufType::SInt64,
188 RustType::String(..) => ProtobufType::String,
189 RustType::VecU8(_) => ProtobufType::Bytes,
190 RustType::BitVec(_) => ProtobufType::BitsReprByBytesAndBitsLen,
191 RustType::Null => ProtobufType::Bytes,
192
193 RustType::Complex(complex, _) => ProtobufType::Complex(complex.clone()),
194
195 RustType::Option(inner) => {
196 Self::definition_type_to_protobuf_type(inner)
198 }
199 RustType::Default(inner, ..) => {
200 Self::definition_type_to_protobuf_type(inner)
202 }
203
204 RustType::Vec(inner, _size, _ordering) => {
205 ProtobufType::Repeated(Box::new(Self::definition_type_to_protobuf_type(inner)))
206 }
207 }
208 }
209}
210
211pub trait ToProtobufModel {
212 fn to_protobuf(&self) -> Model<Protobuf>;
213}
214
215impl ToProtobufModel for Model<Rust> {
216 fn to_protobuf(&self) -> Model<Protobuf> {
217 Model::convert_rust_to_protobuf(self)
218 }
219}
220
221pub fn proto_field_name(name: &str) -> String {
222 rust_module_name(name, false)
223}
224
225pub fn proto_variant_name(name: &str) -> String {
226 rust_variant_name(name)
227}
228
229pub fn proto_definition_name(name: &str) -> String {
230 rust_struct_or_enum_name(name)
231}
232
233#[cfg(test)]
234mod tests {
235 use super::*;
236
237 #[test]
238 fn test_non_definitions_rust_to_protobuf() {
239 let mut model_rust = Model::default();
240 model_rust.name = "ModelWithOriginOfRust".into();
241 model_rust.imports = vec![Import {
242 what: vec!["a".into(), "b".into()],
243 from: "some_very_specific_module".into(),
244 from_oid: None,
245 }];
246 let model_proto = model_rust.to_protobuf();
247 assert_eq!(model_rust.name, model_proto.name);
248 assert_eq!(model_rust.imports, model_proto.imports);
249 assert!(model_proto.definitions.is_empty());
250 }
251
252 #[test]
253 fn test_simple_rust_struct_to_protobuf() {
254 test_model_definition_conversion(
255 &[Definition(
256 "Mine".into(),
257 Rust::struct_from_fields(vec![Field::from_name_type(
258 "field",
259 RustType::U8(Range::inclusive(0, 255)),
260 )]),
261 )],
262 &[Definition(
263 "Mine".into(),
264 Protobuf::Message(vec![("field".into(), ProtobufType::UInt32)]),
265 )],
266 );
267 }
268
269 #[test]
270 fn test_simple_rust_tuple_to_protobuf() {
271 test_model_definition_conversion(
272 &[Definition(
273 "SuchTuple".into(),
274 Rust::tuple_struct_from_type(RustType::Complex("VeryWow".into(), None)),
275 )],
276 &[Definition(
277 "SuchTuple".into(),
278 Protobuf::Message(vec![(
279 TUPLE_VARIABLE_NAME_REPLACEMENT.into(),
280 ProtobufType::Complex("VeryWow".into()),
281 )]),
282 )],
283 );
284 }
285
286 #[test]
287 fn test_simple_rust_enum_to_protobuf() {
288 test_model_definition_conversion(
289 &[Definition(
290 "SuchEnum".into(),
291 Rust::Enum(vec!["VeryWow".into(), "MuchGreat".into()].into()),
292 )],
293 &[Definition(
294 "SuchEnum".into(),
295 Protobuf::Enum(vec!["VeryWow".into(), "MuchGreat".into()]),
296 )],
297 );
298 }
299
300 #[test]
301 fn test_simple_rust_strucht_with_option_to_protobuf() {
302 test_model_definition_conversion(
303 &[Definition(
304 "SuchStruct".into(),
305 Rust::struct_from_fields(vec![Field::from_name_type(
306 "very_optional",
307 RustType::Option(Box::new(RustType::String(Size::Any, Charset::Utf8))),
308 )]),
309 )],
310 &[Definition(
311 "SuchStruct".into(),
312 Protobuf::Message(vec![("very_optional".into(), ProtobufType::String)]),
313 )],
314 );
315 }
316
317 #[test]
318 fn test_simple_rust_data_enum_to_protobuf() {
319 test_model_definition_conversion(
320 &[Definition(
321 "SuchDataEnum".into(),
322 Rust::DataEnum(
323 vec![DataVariant::from_name_type(
324 "MuchVariant",
325 RustType::String(Size::Any, Charset::Utf8),
326 )]
327 .into(),
328 ),
329 )],
330 &[Definition(
331 "SuchDataEnum".into(),
332 Protobuf::Message(vec![(
333 DATAENUM_VARIABLE_NAME_REPLACEMENT.into(),
334 ProtobufType::OneOf(vec![("much_variant".into(), ProtobufType::String)]),
335 )]),
336 )],
337 );
338 }
339
340 #[test]
341 fn test_multiple_rust_defs_to_protobuf() {
342 test_model_definition_conversion(
343 &[
344 Definition(
345 "First".into(),
346 Rust::Enum(vec!["A".into(), "B".into()].into()),
347 ),
348 Definition(
349 "Second".into(),
350 Rust::tuple_struct_from_type(RustType::VecU8(Size::Any)),
351 ),
352 ],
353 &[
354 Definition("First".into(), Protobuf::Enum(vec!["A".into(), "B".into()])),
355 Definition(
356 "Second".into(),
357 Protobuf::Message(vec![(
358 TUPLE_VARIABLE_NAME_REPLACEMENT.into(),
359 ProtobufType::Bytes,
360 )]),
361 ),
362 ],
363 )
364 }
365
366 fn test_model_definition_conversion(rust: &[Definition<Rust>], proto: &[Definition<Protobuf>]) {
367 let mut model_rust = Model::default();
368 model_rust.definitions = rust.to_vec();
369 let model_proto = model_rust.to_protobuf();
370 assert_eq!(proto.len(), model_proto.definitions.len());
371 assert_eq!(proto, &model_proto.definitions[..])
372 }
373}