1 //! Oneof-related codegen functions.
2 
3 use code_writer::CodeWriter;
4 use field::FieldElem;
5 use field::FieldGen;
6 use message::MessageGen;
7 use protobuf::descriptor::FieldDescriptorProto_Type;
8 use protobuf_name::ProtobufAbsolutePath;
9 use rust_name::RustIdent;
10 use rust_types_values::RustType;
11 use scope::FieldWithContext;
12 use scope::OneofVariantWithContext;
13 use scope::OneofWithContext;
14 use scope::RootScope;
15 use scope::WithScope;
16 use serde;
17 use std::collections::HashSet;
18 use Customize;
19 
20 // oneof one { ... }
21 #[derive(Clone)]
22 pub(crate) struct OneofField<'a> {
23     pub elem: FieldElem<'a>,
24     pub oneof_rust_field_name: RustIdent,
25     pub oneof_type_name: RustType,
26     pub boxed: bool,
27 }
28 
29 impl<'a> OneofField<'a> {
30     // Detecting recursion: if oneof fields contains a self-reference
31     // or another message which has a reference to self,
32     // put oneof variant into a box.
need_boxed(field: &FieldWithContext, root_scope: &RootScope, owner_name: &str) -> bool33     fn need_boxed(field: &FieldWithContext, root_scope: &RootScope, owner_name: &str) -> bool {
34         let mut visited_messages = HashSet::new();
35         let mut fields = vec![field.clone()];
36         while let Some(field) = fields.pop() {
37             if field.field.get_field_type() == FieldDescriptorProto_Type::TYPE_MESSAGE {
38                 let message_name = ProtobufAbsolutePath::from(field.field.get_type_name());
39                 if !visited_messages.insert(message_name.clone()) {
40                     continue;
41                 }
42                 if message_name.path == owner_name {
43                     return true;
44                 }
45                 let message = root_scope.find_message(&message_name);
46                 fields.extend(message.fields().into_iter().filter(|f| f.is_oneof()));
47             }
48         }
49         false
50     }
51 
parse( oneof: &OneofWithContext<'a>, field: &FieldWithContext<'a>, elem: FieldElem<'a>, root_scope: &RootScope, ) -> OneofField<'a>52     pub fn parse(
53         oneof: &OneofWithContext<'a>,
54         field: &FieldWithContext<'a>,
55         elem: FieldElem<'a>,
56         root_scope: &RootScope,
57     ) -> OneofField<'a> {
58         let boxed = OneofField::need_boxed(field, root_scope, &oneof.message.name_absolute().path);
59 
60         OneofField {
61             elem,
62             boxed,
63             oneof_rust_field_name: oneof.field_name().into(),
64             oneof_type_name: RustType::Oneof(oneof.rust_name().to_string()),
65         }
66     }
67 
rust_type(&self) -> RustType68     pub fn rust_type(&self) -> RustType {
69         let t = self.elem.rust_storage_type();
70 
71         if self.boxed {
72             RustType::Uniq(Box::new(t))
73         } else {
74             t
75         }
76     }
77 }
78 
79 #[derive(Clone)]
80 pub(crate) struct OneofVariantGen<'a> {
81     oneof: &'a OneofGen<'a>,
82     variant: OneofVariantWithContext<'a>,
83     oneof_field: OneofField<'a>,
84     pub field: FieldGen<'a>,
85     path: String,
86     customize: Customize,
87 }
88 
89 impl<'a> OneofVariantGen<'a> {
parse( oneof: &'a OneofGen<'a>, variant: OneofVariantWithContext<'a>, field: &'a FieldGen, _root_scope: &RootScope, customize: Customize, ) -> OneofVariantGen<'a>90     fn parse(
91         oneof: &'a OneofGen<'a>,
92         variant: OneofVariantWithContext<'a>,
93         field: &'a FieldGen,
94         _root_scope: &RootScope,
95         customize: Customize,
96     ) -> OneofVariantGen<'a> {
97         OneofVariantGen {
98             oneof,
99             variant: variant.clone(),
100             field: field.clone(),
101             path: format!(
102                 "{}::{}",
103                 oneof.type_name.to_code(&field.customize),
104                 field.rust_name
105             ),
106             oneof_field: OneofField::parse(
107                 variant.oneof,
108                 &field.proto_field,
109                 field.oneof().elem.clone(),
110                 oneof.message.root_scope,
111             ),
112             customize,
113         }
114     }
115 
rust_type(&self) -> RustType116     fn rust_type(&self) -> RustType {
117         self.oneof_field.rust_type()
118     }
119 
path(&self) -> String120     pub fn path(&self) -> String {
121         self.path.clone()
122     }
123 }
124 
125 #[derive(Clone)]
126 pub(crate) struct OneofGen<'a> {
127     // Message containing this oneof
128     message: &'a MessageGen<'a>,
129     pub oneof: OneofWithContext<'a>,
130     type_name: RustType,
131     lite_runtime: bool,
132     customize: Customize,
133 }
134 
135 impl<'a> OneofGen<'a> {
parse( message: &'a MessageGen, oneof: OneofWithContext<'a>, customize: &Customize, ) -> OneofGen<'a>136     pub fn parse(
137         message: &'a MessageGen,
138         oneof: OneofWithContext<'a>,
139         customize: &Customize,
140     ) -> OneofGen<'a> {
141         let rust_name = oneof.rust_name();
142         OneofGen {
143             message,
144             oneof,
145             type_name: RustType::Oneof(rust_name.to_string()),
146             lite_runtime: message.lite_runtime,
147             customize: customize.clone(),
148         }
149     }
150 
variants_except_group(&'a self) -> Vec<OneofVariantGen<'a>>151     pub fn variants_except_group(&'a self) -> Vec<OneofVariantGen<'a>> {
152         self.oneof
153             .variants()
154             .into_iter()
155             .filter_map(|v| {
156                 let field = self
157                     .message
158                     .fields
159                     .iter()
160                     .filter(|f| f.proto_field.name() == v.field.get_name())
161                     .next()
162                     .expect(&format!("field not found by name: {}", v.field.get_name()));
163                 match field.proto_type {
164                     FieldDescriptorProto_Type::TYPE_GROUP => None,
165                     _ => Some(OneofVariantGen::parse(
166                         self,
167                         v,
168                         field,
169                         self.message.root_scope,
170                         self.customize.clone(),
171                     )),
172                 }
173             })
174             .collect()
175     }
176 
full_storage_type(&self) -> RustType177     pub fn full_storage_type(&self) -> RustType {
178         RustType::Option(Box::new(self.type_name.clone()))
179     }
180 
write_enum(&self, w: &mut CodeWriter)181     pub fn write_enum(&self, w: &mut CodeWriter) {
182         let derive = vec!["Clone", "PartialEq", "Debug"];
183         w.derive(&derive);
184         serde::write_serde_attr(
185             w,
186             &self.customize,
187             "derive(::serde::Serialize, ::serde::Deserialize)",
188         );
189         w.pub_enum(&self.type_name.to_code(&self.customize), |w| {
190             for variant in self.variants_except_group() {
191                 w.write_line(&format!(
192                     "{}({}),",
193                     variant.field.rust_name,
194                     &variant.rust_type().to_code(&self.customize)
195                 ));
196             }
197         });
198     }
199 }
200