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(¤t.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(¤t.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(¤t.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