1 use std::cmp;
2 
3 use once_cell::sync::Lazy;
4 use protobuf::descriptor::*;
5 use protobuf::reflect::FileDescriptor;
6 use protobuf_parse::ProtobufAbsPath;
7 use regex::Regex;
8 
9 use crate::customize::Customize;
10 use crate::gen::field::type_ext::TypeExt;
11 use crate::gen::file_and_mod::FileAndMod;
12 use crate::gen::inside::protobuf_crate_path;
13 use crate::gen::message::RustTypeMessage;
14 use crate::gen::paths::proto_path_to_rust_mod;
15 use crate::gen::rust::component::RustPathComponent;
16 use crate::gen::rust::ident::RustIdent;
17 use crate::gen::rust::ident_with_path::RustIdentWithPath;
18 use crate::gen::rust::path::RustPath;
19 use crate::gen::rust::rel_path::RustRelativePath;
20 use crate::gen::rust::snippets::EXPR_NONE;
21 use crate::gen::rust::snippets::EXPR_VEC_NEW;
22 use crate::gen::scope::RootScope;
23 use crate::gen::scope::WithScope;
24 use crate::gen::strx::capitalize;
25 use crate::gen::well_known_types::is_well_known_type_full;
26 
27 // Represent subset of rust types used in generated code
28 #[derive(Debug, Clone, PartialEq, Eq)]
29 pub(crate) enum RustType {
30     // integer: signed?, size in bits
31     Int(bool, u32),
32     // param is size in bits
33     Float(u32),
34     Bool,
35     Vec(Box<RustType>),
36     HashMap(Box<RustType>, Box<RustType>),
37     String,
38     // [T], not &[T]
39     Slice(Box<RustType>),
40     // str, not &str
41     Str,
42     Option(Box<RustType>),
43     MessageField(Box<RustType>),
44     // Box<T>
45     Uniq(Box<RustType>),
46     // &T
47     Ref(Box<RustType>),
48     // protobuf message
49     Message(RustTypeMessage),
50     // protobuf enum, not any enum
51     Enum(RustIdentWithPath, RustIdent, i32),
52     // protobuf enum or unknown
53     EnumOrUnknown(RustIdentWithPath, RustIdent, i32),
54     // oneof enum
55     Oneof(RustIdentWithPath),
56     // bytes::Bytes
57     Bytes,
58     // chars::Chars
59     Chars,
60     // group
61     Group,
62 }
63 
64 impl RustType {
65     #[inline]
to_code(&self, customize: &Customize) -> String66     pub(crate) fn to_code(&self, customize: &Customize) -> String {
67         match *self {
68             RustType::Int(true, bits) => format!("i{}", bits),
69             RustType::Int(false, bits) => format!("u{}", bits),
70             RustType::Float(bits) => format!("f{}", bits),
71             RustType::Bool => format!("bool"),
72             RustType::Vec(ref param) => format!("::std::vec::Vec<{}>", param.to_code(customize)),
73             RustType::HashMap(ref key, ref value) => format!(
74                 "::std::collections::HashMap<{}, {}>",
75                 key.to_code(customize),
76                 value.to_code(customize)
77             ),
78             RustType::String => format!("::std::string::String"),
79             RustType::Slice(ref param) => format!("[{}]", param.to_code(customize)),
80             RustType::Str => format!("str"),
81             RustType::Option(ref param) => {
82                 format!("::std::option::Option<{}>", param.to_code(customize))
83             }
84             RustType::MessageField(ref param) => format!(
85                 "{}::MessageField<{}>",
86                 protobuf_crate_path(customize),
87                 param.to_code(customize)
88             ),
89             RustType::Uniq(ref param) => format!("::std::boxed::Box<{}>", param.to_code(customize)),
90             RustType::Ref(ref param) => format!("&{}", param.to_code(customize)),
91             RustType::Message(ref name) => format!("{}", name),
92             RustType::Enum(ref name, ..) | RustType::Oneof(ref name) => format!("{}", name),
93             RustType::EnumOrUnknown(ref name, ..) => format!(
94                 "{}::EnumOrUnknown<{}>",
95                 protobuf_crate_path(customize),
96                 name
97             ),
98             RustType::Group => format!("<group>"),
99             RustType::Bytes => format!("::bytes::Bytes"),
100             RustType::Chars => format!("{}::Chars", protobuf_crate_path(customize)),
101         }
102     }
103 }
104 
105 impl RustType {
u8() -> RustType106     pub(crate) fn u8() -> RustType {
107         RustType::Int(false, 8)
108     }
109 
i32() -> RustType110     pub(crate) fn i32() -> RustType {
111         RustType::Int(true, 32)
112     }
113 
114     /// `&str`.
amp_str() -> RustType115     pub(crate) fn amp_str() -> RustType {
116         RustType::Str.wrap_ref()
117     }
118 
119     /// `&[u8]`.
amp_slice_of_u8() -> RustType120     pub(crate) fn amp_slice_of_u8() -> RustType {
121         RustType::u8().wrap_slice().wrap_ref()
122     }
123 
124     /// Type is rust primitive?
is_primitive(&self) -> bool125     pub(crate) fn is_primitive(&self) -> bool {
126         match *self {
127             RustType::Int(..) | RustType::Float(..) | RustType::Bool => true,
128             _ => false,
129         }
130     }
131 
is_u8(&self) -> bool132     pub fn is_u8(&self) -> bool {
133         match *self {
134             RustType::Int(false, 8) => true,
135             _ => false,
136         }
137     }
138 
is_copy(&self) -> bool139     pub fn is_copy(&self) -> bool {
140         if self.is_primitive() {
141             true
142         } else if let RustType::Enum(..) = *self {
143             true
144         } else if let RustType::EnumOrUnknown(..) = *self {
145             true
146         } else {
147             false
148         }
149     }
150 
is_str(&self) -> bool151     fn is_str(&self) -> bool {
152         match *self {
153             RustType::Str => true,
154             _ => false,
155         }
156     }
157 
is_string(&self) -> bool158     fn is_string(&self) -> bool {
159         match *self {
160             RustType::String => true,
161             _ => false,
162         }
163     }
164 
is_slice(&self) -> Option<&RustType>165     fn is_slice(&self) -> Option<&RustType> {
166         match *self {
167             RustType::Slice(ref v) => Some(&**v),
168             _ => None,
169         }
170     }
171 
is_slice_u8(&self) -> bool172     fn is_slice_u8(&self) -> bool {
173         match self.is_slice() {
174             Some(t) => t.is_u8(),
175             None => false,
176         }
177     }
178 
is_message(&self) -> bool179     fn is_message(&self) -> bool {
180         match *self {
181             RustType::Message(..) => true,
182             _ => false,
183         }
184     }
185 
is_enum(&self) -> bool186     fn is_enum(&self) -> bool {
187         match *self {
188             RustType::Enum(..) => true,
189             _ => false,
190         }
191     }
192 
is_enum_or_unknown(&self) -> bool193     fn is_enum_or_unknown(&self) -> bool {
194         match *self {
195             RustType::EnumOrUnknown(..) => true,
196             _ => false,
197         }
198     }
199 
is_ref(&self) -> Option<&RustType>200     pub fn is_ref(&self) -> Option<&RustType> {
201         match *self {
202             RustType::Ref(ref v) => Some(&**v),
203             _ => None,
204         }
205     }
206 
is_box(&self) -> Option<&RustType>207     pub fn is_box(&self) -> Option<&RustType> {
208         match *self {
209             RustType::Uniq(ref v) => Some(&**v),
210             _ => None,
211         }
212     }
213 
214     // default value for type
default_value(&self, customize: &Customize, const_expr: bool) -> String215     pub fn default_value(&self, customize: &Customize, const_expr: bool) -> String {
216         match *self {
217             RustType::Ref(ref t) if t.is_str() => "\"\"".to_string(),
218             RustType::Ref(ref t) if t.is_slice().is_some() => "&[]".to_string(),
219             RustType::Int(..) => "0".to_string(),
220             RustType::Float(..) => "0.".to_string(),
221             RustType::Bool => "false".to_string(),
222             RustType::Vec(..) => EXPR_VEC_NEW.to_string(),
223             RustType::HashMap(..) => "::std::collections::HashMap::new()".to_string(),
224             RustType::String => "::std::string::String::new()".to_string(),
225             RustType::Bytes => "::bytes::Bytes::new()".to_string(),
226             RustType::Chars => format!("{}::Chars::new()", protobuf_crate_path(customize)),
227             RustType::Option(..) => EXPR_NONE.to_string(),
228             RustType::MessageField(..) => {
229                 format!("{}::MessageField::none()", protobuf_crate_path(customize))
230             }
231             RustType::Message(ref name) => format!("{}::new()", name),
232             RustType::Ref(ref m) if m.is_message() => match **m {
233                 RustType::Message(ref name) => name.default_instance(customize),
234                 _ => unreachable!(),
235             },
236             // Note: default value of enum type may not be equal to default value of field
237             RustType::Enum(ref name, ref default, ..) => format!("{}::{}", name, default),
238             RustType::EnumOrUnknown(_, _, number) if const_expr => format!(
239                 "{}::EnumOrUnknown::from_i32({})",
240                 protobuf_crate_path(customize),
241                 number,
242             ),
243             RustType::EnumOrUnknown(ref name, ref default, ..) if !const_expr => format!(
244                 "{}::EnumOrUnknown::new({}::{})",
245                 protobuf_crate_path(customize),
246                 name,
247                 default
248             ),
249             _ => panic!("cannot create default value for: {:?}", self),
250         }
251     }
252 
default_value_typed(self, customize: &Customize, const_expr: bool) -> RustValueTyped253     pub fn default_value_typed(self, customize: &Customize, const_expr: bool) -> RustValueTyped {
254         RustValueTyped {
255             value: self.default_value(customize, const_expr),
256             rust_type: self,
257         }
258     }
259 
260     /// Emit a code to clear a variable `v`
clear(&self, v: &str, customize: &Customize) -> String261     pub fn clear(&self, v: &str, customize: &Customize) -> String {
262         match *self {
263             RustType::Option(..) => format!("{} = {}", v, EXPR_NONE),
264             RustType::Vec(..)
265             | RustType::Bytes
266             | RustType::Chars
267             | RustType::String
268             | RustType::MessageField(..)
269             | RustType::HashMap(..) => format!("{}.clear()", v),
270             RustType::Bool
271             | RustType::Float(..)
272             | RustType::Int(..)
273             | RustType::Enum(..)
274             | RustType::EnumOrUnknown(..) => {
275                 format!("{} = {}", v, self.default_value(customize, false))
276             }
277             ref ty => panic!("cannot clear type: {:?}", ty),
278         }
279     }
280 
281     // expression to convert `v` of type `self` to type `target`
into_target(&self, target: &RustType, v: &str, customize: &Customize) -> String282     pub fn into_target(&self, target: &RustType, v: &str, customize: &Customize) -> String {
283         self.try_into_target(target, v, customize)
284             .expect(&format!("failed to convert {:?} into {:?}", self, target))
285     }
286 
287     // https://github.com/rust-lang-nursery/rustfmt/issues/3131
288     #[cfg_attr(rustfmt, rustfmt_skip)]
try_into_target(&self, target: &RustType, v: &str, customize: &Customize) -> Result<String, ()>289     fn try_into_target(&self, target: &RustType, v: &str, customize: &Customize) -> Result<String, ()> {
290         {
291             if let Some(t1) = self.is_ref().and_then(|t| t.is_box()) {
292                 if let Some(t2) = target.is_ref() {
293                     if t1 == t2 {
294                         return Ok(format!("&**{}", v));
295                     }
296                 }
297             }
298         }
299 
300         match (self, target) {
301             (x, y) if x == y => return Ok(format!("{}", v)),
302             (&RustType::Ref(ref x), y) if **x == *y => return Ok(format!("*{}", v)),
303             (x, &RustType::Uniq(ref y)) if *x == **y => {
304                 return Ok(format!("::std::boxed::Box::new({})", v))
305             }
306             (&RustType::Uniq(ref x), y) if **x == *y => return Ok(format!("*{}", v)),
307             (&RustType::String, &RustType::Ref(ref t)) if **t == RustType::Str => {
308                 return Ok(format!("&{}", v))
309             }
310             (&RustType::Chars, &RustType::Ref(ref t)) if **t == RustType::Str => {
311                 return Ok(format!("&{}", v))
312             }
313             (&RustType::Ref(ref t1), &RustType::Ref(ref t2)) if t1.is_string() && t2.is_str() => {
314                 return Ok(format!("&{}", v))
315             }
316             (&RustType::Ref(ref t1), &RustType::String)
317                 if match **t1 {
318                        RustType::Str => true,
319                        _ => false,
320                    } => return Ok(format!("{}.to_owned()", v)),
321             (&RustType::Ref(ref t1), &RustType::Chars)
322                 if match **t1 {
323                        RustType::Str => true,
324                        _ => false,
325                    } => {
326                 return Ok(format!("<{}::Chars as ::std::convert::From<_>>::from({}.to_owned())",
327                     protobuf_crate_path(customize), v))
328             },
329             (&RustType::Ref(ref t1), &RustType::Vec(ref t2))
330                 if match (&**t1, &**t2) {
331                        (&RustType::Slice(ref x), ref y) => **x == **y,
332                        _ => false,
333                    } => return Ok(format!("{}.to_vec()", v)),
334             (&RustType::Ref(ref t1), &RustType::Bytes)
335                 if t1.is_slice_u8() =>
336                     return Ok(format!("<::bytes::Bytes as ::std::convert::From<_>>::from({}.to_vec())", v)),
337             (&RustType::Vec(ref x), &RustType::Ref(ref t))
338                 if match **t {
339                        RustType::Slice(ref y) => x == y,
340                        _ => false,
341                    } => return Ok(format!("&{}", v)),
342             (&RustType::Bytes, &RustType::Ref(ref t))
343                 if match **t {
344                        RustType::Slice(ref y) => **y == RustType::u8(),
345                        _ => false,
346                    } => return Ok(format!("&{}", v)),
347             (&RustType::Ref(ref t1), &RustType::Ref(ref t2))
348                 if match (&**t1, &**t2) {
349                        (&RustType::Vec(ref x), &RustType::Slice(ref y)) => x == y,
350                        _ => false,
351                    } => return Ok(format!("&{}", v)),
352             (&RustType::Enum(..), &RustType::Int(true, 32)) => {
353                 return Ok(format!("{}::Enum::value(&{})", protobuf_crate_path(customize), v))
354             },
355             (&RustType::EnumOrUnknown(..), &RustType::Int(true, 32)) => {
356                 return Ok(format!("{}::EnumOrUnknown::value(&{})", protobuf_crate_path(customize), v))
357             },
358             (&RustType::Ref(ref t), &RustType::Int(true, 32)) if t.is_enum() => {
359                 return Ok(format!("{}::Enum::value({})", protobuf_crate_path(customize), v))
360             }
361             (&RustType::Ref(ref t), &RustType::Int(true, 32)) if t.is_enum_or_unknown() => {
362                 return Ok(format!("{}::EnumOrUnknown::value({})", protobuf_crate_path(customize), v))
363             },
364             (&RustType::EnumOrUnknown(ref f, ..), &RustType::Enum(ref t, ..)) if f == t => {
365                 return Ok(format!("{}::EnumOrUnknown::enum_value_or_default(&{})", protobuf_crate_path(customize), v))
366             }
367             (&RustType::Enum(ref f, ..), &RustType::EnumOrUnknown(ref t, ..)) if f == t => {
368                 return Ok(format!("{}::EnumOrUnknown::new({})", protobuf_crate_path(customize), v))
369             }
370             _ => (),
371         };
372 
373         if let &RustType::Ref(ref s) = self {
374             if let Ok(conv) = s.try_into_target(target, v, customize) {
375                 return Ok(conv);
376             }
377         }
378 
379         Err(())
380     }
381 
382     /// Type to view data of this type
ref_type(&self) -> RustType383     pub fn ref_type(&self) -> RustType {
384         RustType::Ref(Box::new(match self {
385             &RustType::String | &RustType::Chars => RustType::Str,
386             &RustType::Vec(ref p) => RustType::Slice(p.clone()),
387             &RustType::Bytes => RustType::Slice(Box::new(RustType::u8())),
388             &RustType::Message(ref p) => RustType::Message(p.clone()),
389             &RustType::Uniq(ref p) => RustType::Uniq(p.clone()),
390             x => panic!("no ref type for {:?}", x),
391         }))
392     }
393 
wrap_ref(&self) -> RustType394     pub(crate) fn wrap_ref(&self) -> RustType {
395         RustType::Ref(Box::new(self.clone()))
396     }
397 
wrap_slice(&self) -> RustType398     pub(crate) fn wrap_slice(&self) -> RustType {
399         RustType::Slice(Box::new(self.clone()))
400     }
401 
elem_type(&self) -> RustType402     pub fn elem_type(&self) -> RustType {
403         match self {
404             &RustType::Option(ref ty) => (**ty).clone(),
405             &RustType::MessageField(ref ty) => (**ty).clone(),
406             x => panic!("cannot get elem type of {:?}", x),
407         }
408     }
409 
410     // type of `v` in `for v in xxx`
iter_elem_type(&self) -> RustType411     pub fn iter_elem_type(&self) -> RustType {
412         match self {
413             &RustType::Vec(ref ty)
414             | &RustType::Option(ref ty)
415             | &RustType::MessageField(ref ty) => RustType::Ref(ty.clone()),
416             x => panic!("cannot iterate {:?}", x),
417         }
418     }
419 
value(self, value: String) -> RustValueTyped420     pub fn value(self, value: String) -> RustValueTyped {
421         RustValueTyped {
422             value: value,
423             rust_type: self,
424         }
425     }
426 }
427 
428 /// Representation of an expression in code generator: text and type
429 pub(crate) struct RustValueTyped {
430     pub value: String,
431     pub rust_type: RustType,
432 }
433 
434 impl RustValueTyped {
into_type(&self, target: RustType, customize: &Customize) -> RustValueTyped435     pub fn into_type(&self, target: RustType, customize: &Customize) -> RustValueTyped {
436         let target_value = self.rust_type.into_target(&target, &self.value, customize);
437         RustValueTyped {
438             value: target_value,
439             rust_type: target,
440         }
441     }
442 
boxed(self, customize: &Customize) -> RustValueTyped443     pub fn boxed(self, customize: &Customize) -> RustValueTyped {
444         self.into_type(RustType::Uniq(Box::new(self.rust_type.clone())), customize)
445     }
446 }
447 
file_last_component(file: &str) -> &str448 fn file_last_component(file: &str) -> &str {
449     let bs = file.rfind('\\').map(|i| i + 1).unwrap_or(0);
450     let fs = file.rfind('/').map(|i| i + 1).unwrap_or(0);
451     &file[cmp::max(fs, bs)..]
452 }
453 
454 #[cfg(test)]
455 #[test]
test_file_last_component()456 fn test_file_last_component() {
457     assert_eq!("ab.proto", file_last_component("ab.proto"));
458     assert_eq!("ab.proto", file_last_component("xx/ab.proto"));
459     assert_eq!("ab.proto", file_last_component("xx\\ab.proto"));
460     assert_eq!("ab.proto", file_last_component("yy\\xx\\ab.proto"));
461 }
462 
is_descriptor_proto(file: &FileDescriptor) -> bool463 fn is_descriptor_proto(file: &FileDescriptor) -> bool {
464     file.package() == "google.protobuf" && file_last_component(file.name()) == "descriptor.proto"
465 }
466 
make_path_to_path(source: &RustRelativePath, dest: &RustPath) -> RustPath467 fn make_path_to_path(source: &RustRelativePath, dest: &RustPath) -> RustPath {
468     if dest.is_absolute() {
469         return dest.clone();
470     }
471 
472     let mut source = source.clone();
473     let mut dest = dest.clone();
474     while !source.is_empty() && source.first() == dest.first() {
475         source.remove_first().unwrap();
476         dest.remove_first().unwrap();
477     }
478     source.to_reverse().into_path().append(dest)
479 }
480 
make_path(source: &RustRelativePath, dest: &RustIdentWithPath) -> RustIdentWithPath481 pub(crate) fn make_path(source: &RustRelativePath, dest: &RustIdentWithPath) -> RustIdentWithPath {
482     make_path_to_path(source, &dest.path).with_ident(dest.ident.clone())
483 }
484 
message_or_enum_to_rust_relative( message_or_enum: &dyn WithScope, current: &FileAndMod, ) -> RustIdentWithPath485 pub(crate) fn message_or_enum_to_rust_relative(
486     message_or_enum: &dyn WithScope,
487     current: &FileAndMod,
488 ) -> RustIdentWithPath {
489     let same_file = message_or_enum.file_descriptor().name() == current.file;
490     if same_file {
491         // field type is a message or enum declared in the same file
492         make_path(&current.relative_mod, &message_or_enum.rust_name_to_file())
493     } else if let Some(name) = is_well_known_type_full(&message_or_enum.name_absolute()) {
494         // Well-known types are included in rust-protobuf library
495         // https://developers.google.com/protocol-buffers/docs/reference/google.protobuf
496         let file_descriptor = message_or_enum.file_descriptor();
497         static REGEX: Lazy<Regex> =
498             Lazy::new(|| Regex::new(r"^google/protobuf/([^/]+\.proto)$").unwrap());
499         let captures = REGEX
500             .captures(file_descriptor.name())
501             .unwrap_or_else(|| panic!("`{}` does not match the regex", file_descriptor.name()));
502         let file_name = captures.get(1).unwrap().as_str();
503         let mod_name = proto_path_to_rust_mod(file_name);
504         RustIdentWithPath::from(format!(
505             "{protobuf_crate}::well_known_types::{mod_name}::{name}",
506             protobuf_crate = protobuf_crate_path(&current.customize),
507         ))
508     } else if is_descriptor_proto(&message_or_enum.file_descriptor()) {
509         // Messages defined in descriptor.proto
510         RustIdentWithPath::from(format!(
511             "{}::descriptor::{}",
512             protobuf_crate_path(&current.customize),
513             message_or_enum.rust_name_to_file()
514         ))
515     } else {
516         current
517             .relative_mod
518             .to_reverse()
519             .into_path()
520             .append_component(RustPathComponent::SUPER)
521             .append_with_ident(message_or_enum.rust_name_with_file())
522     }
523 }
524 
type_name_to_rust_relative( type_name: &ProtobufAbsPath, current: &FileAndMod, root_scope: &RootScope, ) -> RustIdentWithPath525 pub(crate) fn type_name_to_rust_relative(
526     type_name: &ProtobufAbsPath,
527     current: &FileAndMod,
528     root_scope: &RootScope,
529 ) -> RustIdentWithPath {
530     assert!(!type_name.is_root());
531     let message_or_enum = root_scope.find_message_or_enum(type_name);
532     message_or_enum_to_rust_relative(&message_or_enum, current)
533 }
534 
535 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
536 pub enum PrimitiveTypeVariant {
537     Default,
538     TokioBytes,
539 }
540 
541 pub enum _TokioBytesType {
542     Bytes,
543     Chars,
544 }
545 
546 // ProtobufType trait name
547 pub(crate) enum ProtobufTypeGen {
548     Primitive(field_descriptor_proto::Type, PrimitiveTypeVariant),
549     Message(RustTypeMessage),
550     EnumOrUnknown(RustIdentWithPath),
551 }
552 
553 impl ProtobufTypeGen {
protobuf_value(&self, customize: &Customize) -> String554     pub(crate) fn protobuf_value(&self, customize: &Customize) -> String {
555         match self {
556             ProtobufTypeGen::Primitive(t, PrimitiveTypeVariant::Default) => {
557                 t.rust_type().to_code(customize)
558             }
559             ProtobufTypeGen::Primitive(_, PrimitiveTypeVariant::TokioBytes) => unimplemented!(),
560             ProtobufTypeGen::Message(m) => m.0.to_string(),
561             ProtobufTypeGen::EnumOrUnknown(e) => format!(
562                 "{protobuf_crate}::EnumOrUnknown<{e}>",
563                 protobuf_crate = protobuf_crate_path(customize)
564             ),
565         }
566     }
567 
_rust_type(&self, customize: &Customize) -> String568     pub(crate) fn _rust_type(&self, customize: &Customize) -> String {
569         match self {
570             &ProtobufTypeGen::Primitive(t, PrimitiveTypeVariant::Default) => format!(
571                 "{}::reflect::types::ProtobufType{}",
572                 protobuf_crate_path(customize),
573                 capitalize(t.protobuf_name())
574             ),
575             &ProtobufTypeGen::Primitive(
576                 field_descriptor_proto::Type::TYPE_BYTES,
577                 PrimitiveTypeVariant::TokioBytes,
578             ) => format!(
579                 "{}::reflect::types::ProtobufTypeTokioBytes",
580                 protobuf_crate_path(customize)
581             ),
582             &ProtobufTypeGen::Primitive(
583                 field_descriptor_proto::Type::TYPE_STRING,
584                 PrimitiveTypeVariant::TokioBytes,
585             ) => format!(
586                 "{}::reflect::types::ProtobufTypeTokioChars",
587                 protobuf_crate_path(customize)
588             ),
589             &ProtobufTypeGen::Primitive(.., PrimitiveTypeVariant::TokioBytes) => unreachable!(),
590             &ProtobufTypeGen::Message(ref name) => format!(
591                 "{}::reflect::types::ProtobufTypeMessage<{}>",
592                 protobuf_crate_path(customize),
593                 name
594             ),
595             &ProtobufTypeGen::EnumOrUnknown(ref name) => format!(
596                 "{}::reflect::types::ProtobufTypeEnumOrUnknown<{}>",
597                 protobuf_crate_path(customize),
598                 name
599             ),
600         }
601     }
602 }
603 
604 #[cfg(test)]
605 mod test {
606     use super::*;
607 
608     #[test]
into_target_ref_box_to_ref()609     fn into_target_ref_box_to_ref() {
610         let t1 = RustType::Ref(Box::new(RustType::Uniq(Box::new(RustType::Message(
611             RustTypeMessage::from("Ab"),
612         )))));
613         let t2 = RustType::Ref(Box::new(RustType::Message(RustTypeMessage::from("Ab"))));
614 
615         assert_eq!("&**v", t1.into_target(&t2, "v", &Customize::default()));
616     }
617 }
618