1 use std::cmp;
2
3 use super::well_known_types::is_well_known_type_full;
4 use inside::protobuf_crate_path;
5 use message::RustTypeMessage;
6 use protobuf::descriptor::*;
7 use protobuf_name::ProtobufAbsolutePath;
8 use rust_name::RustIdent;
9 use scope::RootScope;
10 use scope::WithScope;
11 use strx::capitalize;
12 use Customize;
13
14 // Represent subset of rust types used in generated code
15 #[derive(Debug, Clone, PartialEq, Eq)]
16 pub(crate) enum RustType {
17 // integer: signed?, size in bits
18 Int(bool, u32),
19 // param is size in bits
20 Float(u32),
21 Bool,
22 Vec(Box<RustType>),
23 HashMap(Box<RustType>, Box<RustType>),
24 String,
25 // [T], not &[T]
26 Slice(Box<RustType>),
27 // str, not &str
28 Str,
29 Option(Box<RustType>),
30 SingularField(Box<RustType>),
31 SingularPtrField(Box<RustType>),
32 RepeatedField(Box<RustType>),
33 // Box<T>
34 Uniq(Box<RustType>),
35 // &T
36 Ref(Box<RustType>),
37 // protobuf message
38 Message(RustTypeMessage),
39 // protobuf enum, not any enum
40 Enum(String, RustIdent),
41 // oneof enum
42 Oneof(String),
43 // bytes::Bytes
44 Bytes,
45 // chars::Chars
46 Chars,
47 // group
48 Group,
49 }
50
51 impl RustType {
52 #[inline]
to_code(&self, customize: &Customize) -> String53 pub(crate) fn to_code(&self, customize: &Customize) -> String {
54 match *self {
55 RustType::Int(true, bits) => format!("i{}", bits),
56 RustType::Int(false, bits) => format!("u{}", bits),
57 RustType::Float(bits) => format!("f{}", bits),
58 RustType::Bool => format!("bool"),
59 RustType::Vec(ref param) => format!("::std::vec::Vec<{}>", param.to_code(customize)),
60 RustType::HashMap(ref key, ref value) => format!(
61 "::std::collections::HashMap<{}, {}>",
62 key.to_code(customize),
63 value.to_code(customize)
64 ),
65 RustType::String => format!("::std::string::String"),
66 RustType::Slice(ref param) => format!("[{}]", param.to_code(customize)),
67 RustType::Str => format!("str"),
68 RustType::Option(ref param) => {
69 format!("::std::option::Option<{}>", param.to_code(customize))
70 }
71 RustType::SingularField(ref param) => format!(
72 "{}::SingularField<{}>",
73 protobuf_crate_path(customize),
74 param.to_code(customize)
75 ),
76 RustType::SingularPtrField(ref param) => format!(
77 "{}::SingularPtrField<{}>",
78 protobuf_crate_path(customize),
79 param.to_code(customize)
80 ),
81 RustType::RepeatedField(ref param) => format!(
82 "{}::RepeatedField<{}>",
83 protobuf_crate_path(customize),
84 param.to_code(customize)
85 ),
86 RustType::Uniq(ref param) => format!("::std::boxed::Box<{}>", param.to_code(customize)),
87 RustType::Ref(ref param) => format!("&{}", param.to_code(customize)),
88 RustType::Message(ref name) => format!("{}", name),
89 RustType::Enum(ref name, _) | RustType::Oneof(ref name) => format!("{}", name),
90 RustType::Group => format!("<group>"),
91 RustType::Bytes => format!("::bytes::Bytes"),
92 RustType::Chars => format!("{}::Chars", protobuf_crate_path(customize)),
93 }
94 }
95 }
96
97 impl RustType {
u8() -> RustType98 pub fn u8() -> RustType {
99 RustType::Int(false, 8)
100 }
101
102 /// Type is rust primitive?
is_primitive(&self) -> bool103 pub fn is_primitive(&self) -> bool {
104 match *self {
105 RustType::Int(..) | RustType::Float(..) | RustType::Bool => true,
106 _ => false,
107 }
108 }
109
is_u8(&self) -> bool110 pub fn is_u8(&self) -> bool {
111 match *self {
112 RustType::Int(false, 8) => true,
113 _ => false,
114 }
115 }
116
is_copy(&self) -> bool117 pub fn is_copy(&self) -> bool {
118 if self.is_primitive() {
119 true
120 } else if let RustType::Enum(..) = *self {
121 true
122 } else {
123 false
124 }
125 }
126
is_str(&self) -> bool127 fn is_str(&self) -> bool {
128 match *self {
129 RustType::Str => true,
130 _ => false,
131 }
132 }
133
is_string(&self) -> bool134 fn is_string(&self) -> bool {
135 match *self {
136 RustType::String => true,
137 _ => false,
138 }
139 }
140
is_slice(&self) -> Option<&RustType>141 fn is_slice(&self) -> Option<&RustType> {
142 match *self {
143 RustType::Slice(ref v) => Some(&**v),
144 _ => None,
145 }
146 }
147
is_slice_u8(&self) -> bool148 fn is_slice_u8(&self) -> bool {
149 match self.is_slice() {
150 Some(t) => t.is_u8(),
151 None => false,
152 }
153 }
154
is_message(&self) -> bool155 fn is_message(&self) -> bool {
156 match *self {
157 RustType::Message(..) => true,
158 _ => false,
159 }
160 }
161
is_enum(&self) -> bool162 fn is_enum(&self) -> bool {
163 match *self {
164 RustType::Enum(..) => true,
165 _ => false,
166 }
167 }
168
is_ref(&self) -> bool169 pub fn is_ref(&self) -> bool {
170 match *self {
171 RustType::Ref(..) => true,
172 _ => false,
173 }
174 }
175
176 // default value for type
default_value(&self, customize: &Customize) -> String177 pub fn default_value(&self, customize: &Customize) -> String {
178 match *self {
179 RustType::Ref(ref t) if t.is_str() => "\"\"".to_string(),
180 RustType::Ref(ref t) if t.is_slice().is_some() => "&[]".to_string(),
181 RustType::Int(..) => "0".to_string(),
182 RustType::Float(..) => "0.".to_string(),
183 RustType::Bool => "false".to_string(),
184 RustType::Vec(..) => "::std::vec::Vec::new()".to_string(),
185 RustType::HashMap(..) => "::std::collections::HashMap::new()".to_string(),
186 RustType::String => "::std::string::String::new()".to_string(),
187 RustType::Bytes => "::bytes::Bytes::new()".to_string(),
188 RustType::Chars => format!("{}::Chars::new()", protobuf_crate_path(customize)),
189 RustType::Option(..) => "::std::option::Option::None".to_string(),
190 RustType::SingularField(..) => {
191 format!("{}::SingularField::none()", protobuf_crate_path(customize))
192 }
193 RustType::SingularPtrField(..) => format!(
194 "{}::SingularPtrField::none()",
195 protobuf_crate_path(customize)
196 ),
197 RustType::RepeatedField(..) => {
198 format!("{}::RepeatedField::new()", protobuf_crate_path(customize))
199 }
200 RustType::Message(ref name) => format!("{}::new()", name),
201 RustType::Ref(ref m) if m.is_message() => match **m {
202 RustType::Message(ref name) => name.default_instance(customize),
203 _ => unreachable!(),
204 },
205 // Note: default value of enum type may not be equal to default value of field
206 RustType::Enum(ref name, ref default) => format!("{}::{}", name, default),
207 _ => panic!("cannot create default value for: {:?}", *self),
208 }
209 }
210
default_value_typed(self, customize: &Customize) -> RustValueTyped211 pub fn default_value_typed(self, customize: &Customize) -> RustValueTyped {
212 RustValueTyped {
213 value: self.default_value(customize),
214 rust_type: self,
215 }
216 }
217
218 /// Emit a code to clear a variable `v`
clear(&self, v: &str, customize: &Customize) -> String219 pub fn clear(&self, v: &str, customize: &Customize) -> String {
220 match *self {
221 RustType::Option(..) => format!("{} = ::std::option::Option::None", v),
222 RustType::Vec(..)
223 | RustType::Bytes
224 | RustType::String
225 | RustType::RepeatedField(..)
226 | RustType::SingularField(..)
227 | RustType::SingularPtrField(..)
228 | RustType::HashMap(..) => format!("{}.clear()", v),
229 RustType::Chars => format!(
230 "{}::Clear::clear(&mut {})",
231 protobuf_crate_path(customize),
232 v
233 ),
234 RustType::Bool | RustType::Float(..) | RustType::Int(..) | RustType::Enum(..) => {
235 format!("{} = {}", v, self.default_value(customize))
236 }
237 ref ty => panic!("cannot clear type: {:?}", ty),
238 }
239 }
240
241 // wrap value in storage type
wrap_value(&self, value: &str, customize: &Customize) -> String242 pub fn wrap_value(&self, value: &str, customize: &Customize) -> String {
243 match *self {
244 RustType::Option(..) => format!("::std::option::Option::Some({})", value),
245 RustType::SingularField(..) => format!(
246 "{}::SingularField::some({})",
247 protobuf_crate_path(customize),
248 value
249 ),
250 RustType::SingularPtrField(..) => format!(
251 "{}::SingularPtrField::some({})",
252 protobuf_crate_path(customize),
253 value
254 ),
255 _ => panic!("not a wrapper type: {:?}", *self),
256 }
257 }
258
259 // expression to convert `v` of type `self` to type `target`
into_target(&self, target: &RustType, v: &str, customize: &Customize) -> String260 pub fn into_target(&self, target: &RustType, v: &str, customize: &Customize) -> String {
261 self.try_into_target(target, v, customize)
262 .expect(&format!("failed to convert {:?} into {:?}", self, target))
263 }
264
try_into_target( &self, target: &RustType, v: &str, customize: &Customize, ) -> Result<String, ()>265 fn try_into_target(
266 &self,
267 target: &RustType,
268 v: &str,
269 customize: &Customize,
270 ) -> Result<String, ()> {
271 match (self, target) {
272 (x, y) if x == y => return Ok(format!("{}", v)),
273 (&RustType::Ref(ref x), y) if **x == *y => return Ok(format!("*{}", v)),
274 (x, &RustType::Uniq(ref y)) if *x == **y => {
275 return Ok(format!("::std::boxed::Box::new({})", v))
276 }
277 (&RustType::Uniq(ref x), y) if **x == *y => return Ok(format!("*{}", v)),
278 (&RustType::String, &RustType::Ref(ref t)) if **t == RustType::Str => {
279 return Ok(format!("&{}", v))
280 }
281 (&RustType::Chars, &RustType::Ref(ref t)) if **t == RustType::Str => {
282 return Ok(format!("&{}", v))
283 }
284 (&RustType::Ref(ref t1), &RustType::Ref(ref t2)) if t1.is_string() && t2.is_str() => {
285 return Ok(format!("&{}", v))
286 }
287 (&RustType::Ref(ref t1), &RustType::String)
288 if match **t1 {
289 RustType::Str => true,
290 _ => false,
291 } =>
292 {
293 return Ok(format!("{}.to_owned()", v))
294 }
295 (&RustType::Ref(ref t1), &RustType::Chars)
296 if match **t1 {
297 RustType::Str => true,
298 _ => false,
299 // TODO: from_static
300 } =>
301 {
302 return Ok(format!(
303 "<{}::Chars as ::std::convert::From<_>>::from({}.to_owned())",
304 protobuf_crate_path(customize),
305 v
306 ))
307 }
308 (&RustType::Ref(ref t1), &RustType::Vec(ref t2))
309 if match (&**t1, &**t2) {
310 (&RustType::Slice(ref x), ref y) => **x == **y,
311 _ => false,
312 } =>
313 {
314 return Ok(format!("{}.to_vec()", v))
315 }
316 (&RustType::Ref(ref t1), &RustType::Bytes) if t1.is_slice_u8() => {
317 return Ok(format!(
318 "<::bytes::Bytes as ::std::convert::From<_>>::from({}.to_vec())",
319 v
320 ))
321 }
322 (&RustType::Vec(ref x), &RustType::Ref(ref t))
323 if match **t {
324 RustType::Slice(ref y) => x == y,
325 _ => false,
326 } =>
327 {
328 return Ok(format!("&{}", v))
329 }
330 (&RustType::Bytes, &RustType::Ref(ref t))
331 if match **t {
332 RustType::Slice(ref y) => **y == RustType::u8(),
333 _ => false,
334 } =>
335 {
336 return Ok(format!("&{}", v))
337 }
338 (&RustType::Ref(ref t1), &RustType::Ref(ref t2))
339 if match (&**t1, &**t2) {
340 (&RustType::Vec(ref x), &RustType::Slice(ref y)) => x == y,
341 _ => false,
342 } =>
343 {
344 return Ok(format!("&{}", v))
345 }
346 (&RustType::Enum(..), &RustType::Int(true, 32)) => {
347 return Ok(format!(
348 "{}::ProtobufEnum::value(&{})",
349 protobuf_crate_path(customize),
350 v
351 ))
352 }
353 (&RustType::Ref(ref t), &RustType::Int(true, 32)) if t.is_enum() => {
354 return Ok(format!(
355 "{}::ProtobufEnum::value({})",
356 protobuf_crate_path(customize),
357 v
358 ))
359 }
360 _ => (),
361 };
362
363 if let &RustType::Ref(ref s) = self {
364 if let Ok(conv) = s.try_into_target(target, v, customize) {
365 return Ok(conv);
366 }
367 }
368
369 Err(())
370 }
371
372 /// Type to view data of this type
ref_type(&self) -> RustType373 pub fn ref_type(&self) -> RustType {
374 RustType::Ref(Box::new(match self {
375 &RustType::String | &RustType::Chars => RustType::Str,
376 &RustType::Vec(ref p) | &RustType::RepeatedField(ref p) => RustType::Slice(p.clone()),
377 &RustType::Bytes => RustType::Slice(Box::new(RustType::u8())),
378 &RustType::Message(ref p) => RustType::Message(p.clone()),
379 x => panic!("no ref type for {:?}", x),
380 }))
381 }
382
elem_type(&self) -> RustType383 pub fn elem_type(&self) -> RustType {
384 match self {
385 &RustType::Option(ref ty) => (**ty).clone(),
386 x => panic!("cannot get elem type of {:?}", x),
387 }
388 }
389
390 // type of `v` in `for v in xxx`
iter_elem_type(&self) -> RustType391 pub fn iter_elem_type(&self) -> RustType {
392 match self {
393 &RustType::Vec(ref ty)
394 | &RustType::Option(ref ty)
395 | &RustType::RepeatedField(ref ty)
396 | &RustType::SingularField(ref ty)
397 | &RustType::SingularPtrField(ref ty) => RustType::Ref(ty.clone()),
398 x => panic!("cannot iterate {:?}", x),
399 }
400 }
401
value(self, value: String) -> RustValueTyped402 pub fn value(self, value: String) -> RustValueTyped {
403 RustValueTyped {
404 value: value,
405 rust_type: self,
406 }
407 }
408 }
409
410 /// Representation of an expression in code generator: text and type
411 pub(crate) struct RustValueTyped {
412 pub value: String,
413 pub rust_type: RustType,
414 }
415
416 impl RustValueTyped {
into_type(&self, target: RustType, customize: &Customize) -> RustValueTyped417 pub fn into_type(&self, target: RustType, customize: &Customize) -> RustValueTyped {
418 let target_value = self.rust_type.into_target(&target, &self.value, customize);
419 RustValueTyped {
420 value: target_value,
421 rust_type: target,
422 }
423 }
424
boxed(self, customize: &Customize) -> RustValueTyped425 pub fn boxed(self, customize: &Customize) -> RustValueTyped {
426 self.into_type(RustType::Uniq(Box::new(self.rust_type.clone())), customize)
427 }
428 }
429
430 // protobuf type name for protobuf base type
protobuf_name(field_type: FieldDescriptorProto_Type) -> &'static str431 pub fn protobuf_name(field_type: FieldDescriptorProto_Type) -> &'static str {
432 match field_type {
433 FieldDescriptorProto_Type::TYPE_DOUBLE => "double",
434 FieldDescriptorProto_Type::TYPE_FLOAT => "float",
435 FieldDescriptorProto_Type::TYPE_INT32 => "int32",
436 FieldDescriptorProto_Type::TYPE_INT64 => "int64",
437 FieldDescriptorProto_Type::TYPE_UINT32 => "uint32",
438 FieldDescriptorProto_Type::TYPE_UINT64 => "uint64",
439 FieldDescriptorProto_Type::TYPE_SINT32 => "sint32",
440 FieldDescriptorProto_Type::TYPE_SINT64 => "sint64",
441 FieldDescriptorProto_Type::TYPE_FIXED32 => "fixed32",
442 FieldDescriptorProto_Type::TYPE_FIXED64 => "fixed64",
443 FieldDescriptorProto_Type::TYPE_SFIXED32 => "sfixed32",
444 FieldDescriptorProto_Type::TYPE_SFIXED64 => "sfixed64",
445 FieldDescriptorProto_Type::TYPE_BOOL => "bool",
446 FieldDescriptorProto_Type::TYPE_STRING => "string",
447 FieldDescriptorProto_Type::TYPE_BYTES => "bytes",
448 FieldDescriptorProto_Type::TYPE_ENUM => "enum",
449 FieldDescriptorProto_Type::TYPE_MESSAGE => "message",
450 FieldDescriptorProto_Type::TYPE_GROUP => "group",
451 }
452 }
453
454 // rust type for protobuf base type
rust_name(field_type: FieldDescriptorProto_Type) -> RustType455 pub(crate) fn rust_name(field_type: FieldDescriptorProto_Type) -> RustType {
456 match field_type {
457 FieldDescriptorProto_Type::TYPE_DOUBLE => RustType::Float(64),
458 FieldDescriptorProto_Type::TYPE_FLOAT => RustType::Float(32),
459 FieldDescriptorProto_Type::TYPE_INT32 => RustType::Int(true, 32),
460 FieldDescriptorProto_Type::TYPE_INT64 => RustType::Int(true, 64),
461 FieldDescriptorProto_Type::TYPE_UINT32 => RustType::Int(false, 32),
462 FieldDescriptorProto_Type::TYPE_UINT64 => RustType::Int(false, 64),
463 FieldDescriptorProto_Type::TYPE_SINT32 => RustType::Int(true, 32),
464 FieldDescriptorProto_Type::TYPE_SINT64 => RustType::Int(true, 64),
465 FieldDescriptorProto_Type::TYPE_FIXED32 => RustType::Int(false, 32),
466 FieldDescriptorProto_Type::TYPE_FIXED64 => RustType::Int(false, 64),
467 FieldDescriptorProto_Type::TYPE_SFIXED32 => RustType::Int(true, 32),
468 FieldDescriptorProto_Type::TYPE_SFIXED64 => RustType::Int(true, 64),
469 FieldDescriptorProto_Type::TYPE_BOOL => RustType::Bool,
470 FieldDescriptorProto_Type::TYPE_STRING => RustType::String,
471 FieldDescriptorProto_Type::TYPE_BYTES => RustType::Vec(Box::new(RustType::Int(false, 8))),
472 FieldDescriptorProto_Type::TYPE_ENUM
473 | FieldDescriptorProto_Type::TYPE_GROUP
474 | FieldDescriptorProto_Type::TYPE_MESSAGE => {
475 panic!("there is no rust name for {:?}", field_type)
476 }
477 }
478 }
479
file_last_component(file: &str) -> &str480 fn file_last_component(file: &str) -> &str {
481 let bs = file.rfind('\\').map(|i| i + 1).unwrap_or(0);
482 let fs = file.rfind('/').map(|i| i + 1).unwrap_or(0);
483 &file[cmp::max(fs, bs)..]
484 }
485
486 #[cfg(test)]
487 #[test]
test_file_last_component()488 fn test_file_last_component() {
489 assert_eq!("ab.proto", file_last_component("ab.proto"));
490 assert_eq!("ab.proto", file_last_component("xx/ab.proto"));
491 assert_eq!("ab.proto", file_last_component("xx\\ab.proto"));
492 assert_eq!("ab.proto", file_last_component("yy\\xx\\ab.proto"));
493 }
494
is_descriptor_proto(file: &FileDescriptorProto) -> bool495 fn is_descriptor_proto(file: &FileDescriptorProto) -> bool {
496 file.get_package() == "google.protobuf"
497 && file_last_component(file.get_name()) == "descriptor.proto"
498 }
499
type_name_to_rust_relative( type_name: &ProtobufAbsolutePath, file: &FileDescriptorProto, subm: bool, root_scope: &RootScope, customize: &Customize, ) -> String500 pub(crate) fn type_name_to_rust_relative(
501 type_name: &ProtobufAbsolutePath,
502 file: &FileDescriptorProto,
503 subm: bool,
504 root_scope: &RootScope,
505 customize: &Customize,
506 ) -> String {
507 let message_or_enum = root_scope.find_message_or_enum(type_name);
508 if message_or_enum.get_scope().get_file_descriptor().get_name() == file.get_name() {
509 // field type is a message or enum declared in the same file
510 if subm {
511 format!("super::{}", message_or_enum.rust_name())
512 } else {
513 format!("{}", message_or_enum.rust_name())
514 }
515 } else if let Some(name) = is_well_known_type_full(&type_name.path) {
516 // Well-known types are included in rust-protobuf library
517 // https://developers.google.com/protocol-buffers/docs/reference/google.protobuf
518 format!(
519 "{}::well_known_types::{}",
520 protobuf_crate_path(customize),
521 name
522 )
523 } else if is_descriptor_proto(message_or_enum.get_file_descriptor()) {
524 // Messages defined in descriptor.proto
525 format!(
526 "{}::descriptor::{}",
527 protobuf_crate_path(customize),
528 message_or_enum.name_to_package()
529 )
530 } else {
531 if subm {
532 format!("super::super::{}", message_or_enum.rust_fq_name())
533 } else {
534 format!("super::{}", message_or_enum.rust_fq_name())
535 }
536 }
537 }
538
539 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
540 pub enum PrimitiveTypeVariant {
541 Default,
542 Carllerche,
543 }
544
545 pub enum _CarllercheBytesType {
546 Bytes,
547 Chars,
548 }
549
550 // ProtobufType trait name
551 pub enum ProtobufTypeGen {
552 Primitive(FieldDescriptorProto_Type, PrimitiveTypeVariant),
553 Message(String),
554 Enum(String),
555 }
556
557 impl ProtobufTypeGen {
rust_type(&self, customize: &Customize) -> String558 pub fn rust_type(&self, customize: &Customize) -> String {
559 match self {
560 &ProtobufTypeGen::Primitive(t, PrimitiveTypeVariant::Default) => format!(
561 "{}::types::ProtobufType{}",
562 protobuf_crate_path(customize),
563 capitalize(protobuf_name(t))
564 ),
565 &ProtobufTypeGen::Primitive(
566 FieldDescriptorProto_Type::TYPE_BYTES,
567 PrimitiveTypeVariant::Carllerche,
568 ) => format!(
569 "{}::types::ProtobufTypeCarllercheBytes",
570 protobuf_crate_path(customize)
571 ),
572 &ProtobufTypeGen::Primitive(
573 FieldDescriptorProto_Type::TYPE_STRING,
574 PrimitiveTypeVariant::Carllerche,
575 ) => format!(
576 "{}::types::ProtobufTypeCarllercheChars",
577 protobuf_crate_path(customize)
578 ),
579 &ProtobufTypeGen::Primitive(.., PrimitiveTypeVariant::Carllerche) => unreachable!(),
580 &ProtobufTypeGen::Message(ref name) => format!(
581 "{}::types::ProtobufTypeMessage<{}>",
582 protobuf_crate_path(customize),
583 name
584 ),
585 &ProtobufTypeGen::Enum(ref name) => format!(
586 "{}::types::ProtobufTypeEnum<{}>",
587 protobuf_crate_path(customize),
588 name
589 ),
590 }
591 }
592 }
593