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