1 use protobuf::descriptor::field_descriptor_proto::Type;
2 use protobuf::reflect::RuntimeFieldType;
3 use protobuf::rt::tag_size;
4 use protobuf_parse::ProtobufAbsPath;
5
6 use crate::gen::code_writer::CodeWriter;
7 use crate::gen::field::type_ext::TypeExt;
8 use crate::gen::file_and_mod::FileAndMod;
9 use crate::gen::inside::protobuf_crate_path;
10 use crate::gen::message::RustTypeMessage;
11 use crate::gen::rust::ident_with_path::RustIdentWithPath;
12 use crate::gen::rust_types_values::message_or_enum_to_rust_relative;
13 use crate::gen::rust_types_values::PrimitiveTypeVariant;
14 use crate::gen::rust_types_values::RustType;
15 use crate::gen::rust_types_values::RustValueTyped;
16 use crate::gen::scope::EnumValueWithContext;
17 use crate::gen::scope::FieldWithContext;
18 use crate::gen::scope::MessageOrEnumWithScope;
19 use crate::gen::scope::MessageWithScope;
20 use crate::gen::scope::RootScope;
21 use crate::Customize;
22
23 #[derive(Clone, Debug)]
24 pub(crate) struct FieldElemEnum<'a> {
25 /// Enum default value variant, either from proto or from enum definition
26 default_value: EnumValueWithContext<'a>,
27 }
28
29 impl<'a> FieldElemEnum<'a> {
rust_name_relative(&self, reference: &FileAndMod) -> RustIdentWithPath30 fn rust_name_relative(&self, reference: &FileAndMod) -> RustIdentWithPath {
31 message_or_enum_to_rust_relative(&self.default_value.en, reference)
32 }
33
enum_rust_type(&self, reference: &FileAndMod) -> RustType34 pub(crate) fn enum_rust_type(&self, reference: &FileAndMod) -> RustType {
35 RustType::Enum(
36 self.rust_name_relative(reference),
37 self.default_value.rust_name(),
38 self.default_value.proto.proto().number(),
39 )
40 }
41
enum_or_unknown_rust_type(&self, reference: &FileAndMod) -> RustType42 fn enum_or_unknown_rust_type(&self, reference: &FileAndMod) -> RustType {
43 RustType::EnumOrUnknown(
44 self.rust_name_relative(reference),
45 self.default_value.rust_name(),
46 self.default_value.proto.proto().number(),
47 )
48 }
49
default_value_rust_expr(&self, reference: &FileAndMod) -> RustIdentWithPath50 pub(crate) fn default_value_rust_expr(&self, reference: &FileAndMod) -> RustIdentWithPath {
51 self.rust_name_relative(reference)
52 .to_path()
53 .with_ident(self.default_value.rust_name())
54 }
55 }
56
57 #[derive(Clone, Debug)]
58 pub(crate) struct FieldElemMessage<'a> {
59 pub message: MessageWithScope<'a>,
60 }
61
62 impl<'a> FieldElemMessage<'a> {
rust_name_relative(&self, reference: &FileAndMod) -> RustTypeMessage63 pub(crate) fn rust_name_relative(&self, reference: &FileAndMod) -> RustTypeMessage {
64 RustTypeMessage(message_or_enum_to_rust_relative(&self.message, reference))
65 }
66
rust_type(&self, reference: &FileAndMod) -> RustType67 fn rust_type(&self, reference: &FileAndMod) -> RustType {
68 RustType::Message(self.rust_name_relative(reference))
69 }
70 }
71
72 #[derive(Clone, Debug)]
73 pub(crate) enum FieldElem<'a> {
74 Primitive(Type, PrimitiveTypeVariant),
75 Message(FieldElemMessage<'a>),
76 Enum(FieldElemEnum<'a>),
77 Group,
78 }
79
80 pub(crate) enum HowToGetMessageSize {
81 Compute,
82 GetCached,
83 }
84
85 impl<'a> FieldElem<'a> {
proto_type(&self) -> Type86 pub(crate) fn proto_type(&self) -> Type {
87 match *self {
88 FieldElem::Primitive(t, ..) => t,
89 FieldElem::Group => Type::TYPE_GROUP,
90 FieldElem::Message(..) => Type::TYPE_MESSAGE,
91 FieldElem::Enum(..) => Type::TYPE_ENUM,
92 }
93 }
94
is_copy(&self) -> bool95 pub(crate) fn is_copy(&self) -> bool {
96 self.proto_type().is_copy()
97 }
98
rust_storage_elem_type(&self, reference: &FileAndMod) -> RustType99 pub(crate) fn rust_storage_elem_type(&self, reference: &FileAndMod) -> RustType {
100 match *self {
101 FieldElem::Primitive(t, PrimitiveTypeVariant::Default) => t.rust_type(),
102 FieldElem::Primitive(Type::TYPE_STRING, PrimitiveTypeVariant::TokioBytes) => {
103 RustType::Chars
104 }
105 FieldElem::Primitive(Type::TYPE_BYTES, PrimitiveTypeVariant::TokioBytes) => {
106 RustType::Bytes
107 }
108 FieldElem::Primitive(.., PrimitiveTypeVariant::TokioBytes) => unreachable!(),
109 FieldElem::Group => RustType::Group,
110 FieldElem::Message(ref m) => m.rust_type(reference),
111 FieldElem::Enum(ref en) => en.enum_or_unknown_rust_type(reference),
112 }
113 }
114
115 // Type of set_xxx function parameter type for singular fields
rust_set_xxx_param_type(&self, reference: &FileAndMod) -> RustType116 pub(crate) fn rust_set_xxx_param_type(&self, reference: &FileAndMod) -> RustType {
117 if let FieldElem::Enum(ref en) = *self {
118 en.enum_rust_type(reference)
119 } else {
120 self.rust_storage_elem_type(reference)
121 }
122 }
123
primitive_type_variant(&self) -> PrimitiveTypeVariant124 pub(crate) fn primitive_type_variant(&self) -> PrimitiveTypeVariant {
125 match self {
126 &FieldElem::Primitive(_, v) => v,
127 _ => PrimitiveTypeVariant::Default,
128 }
129 }
130
singular_field_size( &self, field_number: u32, var: &RustValueTyped, customize: &Customize, ) -> String131 pub(crate) fn singular_field_size(
132 &self,
133 field_number: u32,
134 var: &RustValueTyped,
135 customize: &Customize,
136 ) -> String {
137 let tag_size = tag_size(field_number);
138 match self.proto_type().encoded_size() {
139 Some(data_size) => format!("{tag_size} + {data_size}"),
140 None => match self.proto_type() {
141 Type::TYPE_MESSAGE => panic!("not a single-liner"),
142 // We are not inlining `bytes_size` here,
143 // assuming the compiler is smart enough to do it for us.
144 // https://rust.godbolt.org/z/GrKa5zxq6
145 Type::TYPE_BYTES => format!(
146 "{}::rt::bytes_size({}, &{})",
147 protobuf_crate_path(customize),
148 field_number,
149 var.value
150 ),
151 Type::TYPE_STRING => format!(
152 "{}::rt::string_size({}, &{})",
153 protobuf_crate_path(customize),
154 field_number,
155 var.value
156 ),
157 Type::TYPE_ENUM => {
158 format!(
159 "{}::rt::int32_size({}, {}.value())",
160 protobuf_crate_path(customize),
161 field_number,
162 var.value,
163 )
164 }
165 _ => {
166 let param_type = match &var.rust_type {
167 RustType::Ref(t) => (**t).clone(),
168 t => t.clone(),
169 };
170 let f = match self.proto_type() {
171 Type::TYPE_SINT32 => "sint32_size",
172 Type::TYPE_SINT64 => "sint64_size",
173 Type::TYPE_INT32 => "int32_size",
174 Type::TYPE_INT64 => "int64_size",
175 Type::TYPE_UINT32 => "uint32_size",
176 Type::TYPE_UINT64 => "uint64_size",
177 t => unreachable!("unexpected type: {:?}", t),
178 };
179 format!(
180 "{}::rt::{f}({}, {})",
181 protobuf_crate_path(customize),
182 field_number,
183 var.into_type(param_type, customize).value
184 )
185 }
186 },
187 }
188 }
189
write_element_size( &self, field_number: u32, item_var: &RustValueTyped, how_to_get_message_size: HowToGetMessageSize, sum_var: &str, customize: &Customize, w: &mut CodeWriter, )190 pub(crate) fn write_element_size(
191 &self,
192 field_number: u32,
193 item_var: &RustValueTyped,
194 how_to_get_message_size: HowToGetMessageSize,
195 sum_var: &str,
196 customize: &Customize,
197 w: &mut CodeWriter,
198 ) {
199 let tag_size = tag_size(field_number);
200 match self.proto_type() {
201 Type::TYPE_MESSAGE => {
202 match how_to_get_message_size {
203 HowToGetMessageSize::Compute => {
204 w.write_line(&format!("let len = {}.compute_size();", item_var.value))
205 }
206 HowToGetMessageSize::GetCached => w.write_line(&format!(
207 "let len = {}.cached_size() as u64;",
208 item_var.value
209 )),
210 }
211 w.write_line(&format!(
212 "{sum_var} += {tag_size} + {}::rt::compute_raw_varint64_size(len) + len;",
213 protobuf_crate_path(customize),
214 ));
215 }
216 _ => {
217 w.write_line(&format!(
218 "{sum_var} += {};",
219 self.singular_field_size(field_number, item_var, customize)
220 ));
221 }
222 }
223 }
224
write_write_element( &self, field_number: u32, v: &RustValueTyped, file_and_mod: &FileAndMod, customize: &Customize, os: &str, w: &mut CodeWriter, )225 pub(crate) fn write_write_element(
226 &self,
227 field_number: u32,
228 v: &RustValueTyped,
229 file_and_mod: &FileAndMod,
230 customize: &Customize,
231 os: &str,
232 w: &mut CodeWriter,
233 ) {
234 match self.proto_type() {
235 Type::TYPE_MESSAGE => {
236 let param_type = RustType::Ref(Box::new(self.rust_storage_elem_type(file_and_mod)));
237
238 w.write_line(&format!(
239 "{}::rt::write_message_field_with_cached_size({}, {}, {})?;",
240 protobuf_crate_path(customize),
241 field_number,
242 v.into_type(param_type, customize).value,
243 os
244 ));
245 }
246 _ => {
247 let param_type = self.proto_type().os_write_fn_param_type();
248 let os_write_fn_suffix = self.proto_type().protobuf_name();
249 w.write_line(&format!(
250 "{}.write_{}({}, {})?;",
251 os,
252 os_write_fn_suffix,
253 field_number,
254 v.into_type(param_type, customize).value
255 ));
256 }
257 }
258 }
259
read_one_liner(&self) -> String260 pub(crate) fn read_one_liner(&self) -> String {
261 format!(
262 "{}?",
263 self.proto_type().read("is", self.primitive_type_variant())
264 )
265 }
266 }
267
field_elem<'a>( field: &FieldWithContext, root_scope: &'a RootScope<'a>, customize: &Customize, ) -> FieldElem<'a>268 pub(crate) fn field_elem<'a>(
269 field: &FieldWithContext,
270 root_scope: &'a RootScope<'a>,
271 customize: &Customize,
272 ) -> FieldElem<'a> {
273 if let RuntimeFieldType::Map(..) = field.field.runtime_field_type() {
274 unreachable!();
275 }
276
277 if field.field.proto().type_() == Type::TYPE_GROUP {
278 FieldElem::Group
279 } else if field.field.proto().has_type_name() {
280 let message_or_enum = root_scope
281 .find_message_or_enum(&ProtobufAbsPath::from(field.field.proto().type_name()));
282 match (field.field.proto().type_(), message_or_enum) {
283 (Type::TYPE_MESSAGE, MessageOrEnumWithScope::Message(message)) => {
284 FieldElem::Message(FieldElemMessage {
285 message: message.clone(),
286 })
287 }
288 (Type::TYPE_ENUM, MessageOrEnumWithScope::Enum(enum_with_scope)) => {
289 let default_value = if field.field.proto().has_default_value() {
290 enum_with_scope.value_by_name(field.field.proto().default_value())
291 } else {
292 enum_with_scope.values()[0].clone()
293 };
294 FieldElem::Enum(FieldElemEnum { default_value })
295 }
296 _ => panic!("unknown named type: {:?}", field.field.proto().type_()),
297 }
298 } else if field.field.proto().has_type() {
299 let tokio_for_bytes = customize.tokio_bytes.unwrap_or(false);
300 let tokio_for_string = customize.tokio_bytes_for_string.unwrap_or(false);
301
302 let elem = match field.field.proto().type_() {
303 Type::TYPE_STRING if tokio_for_string => {
304 FieldElem::Primitive(Type::TYPE_STRING, PrimitiveTypeVariant::TokioBytes)
305 }
306 Type::TYPE_BYTES if tokio_for_bytes => {
307 FieldElem::Primitive(Type::TYPE_BYTES, PrimitiveTypeVariant::TokioBytes)
308 }
309 t => FieldElem::Primitive(t, PrimitiveTypeVariant::Default),
310 };
311
312 elem
313 } else {
314 panic!(
315 "neither type_name, nor field_type specified for field: {}",
316 field.field.name()
317 );
318 }
319 }
320