aboutsummaryrefslogtreecommitdiff
path: root/2.27.1/src/message.rs
diff options
context:
space:
mode:
Diffstat (limited to '2.27.1/src/message.rs')
-rw-r--r--2.27.1/src/message.rs626
1 files changed, 626 insertions, 0 deletions
diff --git a/2.27.1/src/message.rs b/2.27.1/src/message.rs
new file mode 100644
index 0000000..fbe9ed4
--- /dev/null
+++ b/2.27.1/src/message.rs
@@ -0,0 +1,626 @@
+use std::fmt;
+
+use file_descriptor::file_descriptor_proto_expr;
+use inside::protobuf_crate_path;
+use oneof::OneofGen;
+use oneof::OneofVariantGen;
+use protobuf::descriptor::*;
+use rust_name::RustIdentWithPath;
+use scope::MessageWithScope;
+use scope::RootScope;
+use scope::WithScope;
+use serde;
+
+use super::code_writer::*;
+use super::customize::customize_from_rustproto_for_message;
+use super::customize::Customize;
+use super::enums::*;
+use super::field::*;
+use super::rust_types_values::*;
+
+/// Protobuf message Rust type name
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub(crate) struct RustTypeMessage(pub RustIdentWithPath);
+
+impl fmt::Display for RustTypeMessage {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(&self.0, f)
+ }
+}
+
+impl RustTypeMessage {
+ /// Code which emits default instance.
+ pub fn default_instance(&self, customize: &Customize) -> String {
+ format!(
+ "<{} as {}::Message>::default_instance()",
+ self.0,
+ protobuf_crate_path(customize)
+ )
+ }
+}
+
+/// Message info for codegen
+pub(crate) struct MessageGen<'a> {
+ pub message: &'a MessageWithScope<'a>,
+ pub root_scope: &'a RootScope<'a>,
+ type_name: RustIdentWithPath,
+ pub fields: Vec<FieldGen<'a>>,
+ pub lite_runtime: bool,
+ customize: Customize,
+}
+
+impl<'a> MessageGen<'a> {
+ pub fn new(
+ message: &'a MessageWithScope<'a>,
+ root_scope: &'a RootScope<'a>,
+ customize: &Customize,
+ ) -> MessageGen<'a> {
+ let mut customize = customize.clone();
+ customize.update_with(&customize_from_rustproto_for_message(
+ message.message.get_options(),
+ ));
+
+ let fields: Vec<_> = message
+ .fields()
+ .into_iter()
+ .map(|field| FieldGen::parse(field, root_scope, &customize))
+ .collect();
+ let lite_runtime = customize.lite_runtime.unwrap_or_else(|| {
+ message
+ .get_file_descriptor()
+ .get_options()
+ .get_optimize_for()
+ == FileOptions_OptimizeMode::LITE_RUNTIME
+ });
+ MessageGen {
+ message,
+ root_scope,
+ type_name: message.rust_name().into(),
+ fields,
+ lite_runtime,
+ customize,
+ }
+ }
+
+ fn expose_oneof(&self) -> bool {
+ self.customize.expose_oneof.unwrap_or(true)
+ }
+
+ fn oneofs(&'a self) -> Vec<OneofGen<'a>> {
+ self.message
+ .oneofs()
+ .into_iter()
+ .map(|oneof| OneofGen::parse(self, oneof, &self.customize))
+ .collect()
+ }
+
+ fn required_fields(&'a self) -> Vec<&'a FieldGen> {
+ self.fields
+ .iter()
+ .filter(|f| match f.kind {
+ FieldKind::Singular(ref singular) => singular.flag.is_required(),
+ _ => false,
+ })
+ .collect()
+ }
+
+ fn message_fields(&'a self) -> Vec<&'a FieldGen> {
+ self.fields
+ .iter()
+ .filter(|f| f.proto_type == FieldDescriptorProto_Type::TYPE_MESSAGE)
+ .collect()
+ }
+
+ fn fields_except_oneof(&'a self) -> Vec<&'a FieldGen> {
+ self.fields.iter().filter(|f| !f.is_oneof()).collect()
+ }
+
+ fn fields_except_group(&'a self) -> Vec<&'a FieldGen> {
+ self.fields
+ .iter()
+ .filter(|f| f.proto_type != FieldDescriptorProto_Type::TYPE_GROUP)
+ .collect()
+ }
+
+ fn fields_except_oneof_and_group(&'a self) -> Vec<&'a FieldGen> {
+ self.fields
+ .iter()
+ .filter(|f| !f.is_oneof() && f.proto_type != FieldDescriptorProto_Type::TYPE_GROUP)
+ .collect()
+ }
+
+ fn write_match_each_oneof_variant<F>(&self, w: &mut CodeWriter, cb: F)
+ where
+ F: Fn(&mut CodeWriter, &OneofVariantGen, &str, &RustType),
+ {
+ for oneof in self.oneofs() {
+ w.if_let_stmt(
+ "::std::option::Option::Some(ref v)",
+ &format!("self.{}", oneof.oneof.field_name())[..],
+ |w| {
+ w.match_block("v", |w| {
+ for variant in oneof.variants_except_group() {
+ let ref field = variant.field;
+ let (refv, vtype) = if !field.elem_type_is_copy() {
+ ("ref v", field.elem().rust_storage_type().ref_type())
+ } else {
+ ("v", field.elem().rust_storage_type())
+ };
+ w.case_block(format!("&{}({})", variant.path(), refv), |w| {
+ cb(w, &variant, "v", &vtype);
+ });
+ }
+ });
+ },
+ );
+ }
+ }
+
+ fn write_write_to_with_cached_sizes(&self, w: &mut CodeWriter) {
+ let sig = format!(
+ "write_to_with_cached_sizes(&self, os: &mut {}::CodedOutputStream<'_>) -> {}::ProtobufResult<()>",
+ protobuf_crate_path(&self.customize),
+ protobuf_crate_path(&self.customize),
+ );
+ w.def_fn(&sig, |w| {
+ // To have access to its methods but not polute the name space.
+ for f in self.fields_except_oneof_and_group() {
+ f.write_message_write_field(w);
+ }
+ self.write_match_each_oneof_variant(w, |w, variant, v, v_type| {
+ variant.field.write_write_element(w, "os", v, v_type);
+ });
+ w.write_line("os.write_unknown_fields(self.get_unknown_fields())?;");
+ w.write_line("::std::result::Result::Ok(())");
+ });
+ }
+
+ fn write_get_cached_size(&self, w: &mut CodeWriter) {
+ w.def_fn("get_cached_size(&self) -> u32", |w| {
+ w.write_line("self.cached_size.get()");
+ });
+ }
+
+ fn write_default_instance(&self, w: &mut CodeWriter) {
+ w.def_fn(
+ &format!("default_instance() -> &'static {}", self.type_name),
+ |w| {
+ w.lazy_static_decl_get_simple(
+ "instance",
+ &self.type_name.to_string(),
+ &format!("{}::new", self.type_name),
+ &self.customize,
+ );
+ },
+ );
+ }
+
+ fn write_compute_size(&self, w: &mut CodeWriter) {
+ // Append sizes of messages in the tree to the specified vector.
+ // First appended element is size of self, and then nested message sizes.
+ // in serialization order are appended recursively.");
+ w.comment("Compute sizes of nested messages");
+ // there are unused variables in oneof
+ w.allow(&["unused_variables"]);
+ w.def_fn("compute_size(&self) -> u32", |w| {
+ // To have access to its methods but not polute the name space.
+ w.write_line("let mut my_size = 0;");
+ for field in self.fields_except_oneof_and_group() {
+ field.write_message_compute_field_size("my_size", w);
+ }
+ self.write_match_each_oneof_variant(w, |w, variant, v, vtype| {
+ variant.field.write_element_size(w, v, vtype, "my_size");
+ });
+ w.write_line(&format!(
+ "my_size += {}::rt::unknown_fields_size(self.get_unknown_fields());",
+ protobuf_crate_path(&self.customize)
+ ));
+ w.write_line("self.cached_size.set(my_size);");
+ w.write_line("my_size");
+ });
+ }
+
+ fn write_field_accessors(&self, w: &mut CodeWriter) {
+ for f in self.fields_except_group() {
+ w.write_line("");
+ let reconstruct_def = f.reconstruct_def();
+ w.comment(&(reconstruct_def + ";"));
+ w.write_line("");
+ f.write_message_single_field_accessors(w);
+ }
+ }
+
+ fn write_impl_self(&self, w: &mut CodeWriter) {
+ w.impl_self_block(&self.type_name.to_string(), |w| {
+ // TODO: new should probably be a part of Message trait
+ w.pub_fn(&format!("new() -> {}", self.type_name), |w| {
+ w.write_line("::std::default::Default::default()");
+ });
+
+ self.write_field_accessors(w);
+ });
+ }
+
+ fn write_unknown_fields(&self, w: &mut CodeWriter) {
+ w.def_fn(
+ &format!(
+ "get_unknown_fields(&self) -> &{}::UnknownFields",
+ protobuf_crate_path(&self.customize)
+ ),
+ |w| {
+ w.write_line("&self.unknown_fields");
+ },
+ );
+ w.write_line("");
+ w.def_fn(
+ &format!(
+ "mut_unknown_fields(&mut self) -> &mut {}::UnknownFields",
+ protobuf_crate_path(&self.customize)
+ ),
+ |w| {
+ w.write_line("&mut self.unknown_fields");
+ },
+ );
+ }
+
+ fn write_merge_from(&self, w: &mut CodeWriter) {
+ let sig = format!(
+ "merge_from(&mut self, is: &mut {}::CodedInputStream<'_>) -> {}::ProtobufResult<()>",
+ protobuf_crate_path(&self.customize),
+ protobuf_crate_path(&self.customize),
+ );
+ w.def_fn(&sig, |w| {
+ w.while_block("!is.eof()?", |w| {
+ w.write_line(&format!("let (field_number, wire_type) = is.read_tag_unpack()?;"));
+ w.match_block("field_number", |w| {
+ for f in &self.fields_except_group() {
+ let number = f.proto_field.number();
+ w.case_block(number.to_string(), |w| {
+ f.write_merge_from_field("wire_type", w);
+ });
+ }
+ w.case_block("_", |w| {
+ w.write_line(&format!("{}::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;", protobuf_crate_path(&self.customize)));
+ });
+ });
+ });
+ w.write_line("::std::result::Result::Ok(())");
+ });
+ }
+
+ fn write_descriptor_field(&self, fields_var: &str, field: &FieldGen, w: &mut CodeWriter) {
+ let accessor_fn = field.accessor_fn();
+ w.write_line(&format!(
+ "{}.push({}::reflect::accessor::{}(",
+ fields_var,
+ protobuf_crate_path(&self.customize),
+ accessor_fn.sig()
+ ));
+ w.indented(|w| {
+ w.write_line(&format!("\"{}\",", field.proto_field.name()));
+ match accessor_fn.style {
+ AccessorStyle::Lambda => {
+ w.write_line(&format!(
+ "|m: &{}| {{ &m.{} }},",
+ self.type_name, field.rust_name
+ ));
+ w.write_line(&format!(
+ "|m: &mut {}| {{ &mut m.{} }},",
+ self.type_name, field.rust_name
+ ));
+ }
+ AccessorStyle::HasGet => {
+ w.write_line(&format!("{}::has_{},", self.type_name, field.rust_name));
+ w.write_line(&format!("{}::get_{},", self.type_name, field.rust_name));
+ }
+ }
+ });
+ w.write_line("));");
+ }
+
+ fn write_descriptor_static(&self, w: &mut CodeWriter) {
+ w.def_fn(
+ &format!(
+ "descriptor_static() -> &'static {}::reflect::MessageDescriptor",
+ protobuf_crate_path(&self.customize)
+ ),
+ |w| {
+ w.lazy_static_decl_get(
+ "descriptor",
+ &format!(
+ "{}::reflect::MessageDescriptor",
+ protobuf_crate_path(&self.customize)
+ ),
+ &self.customize,
+ |w| {
+ let fields = self.fields_except_group();
+ if fields.is_empty() {
+ w.write_line(&format!("let fields = ::std::vec::Vec::new();"));
+ } else {
+ w.write_line(&format!("let mut fields = ::std::vec::Vec::new();"));
+ }
+ for field in fields {
+ self.write_descriptor_field("fields", field, w);
+ }
+ w.write_line(&format!(
+ "{}::reflect::MessageDescriptor::new_pb_name::<{}>(",
+ protobuf_crate_path(&self.customize),
+ self.type_name
+ ));
+ w.indented(|w| {
+ w.write_line(&format!("\"{}\",", self.message.name_to_package()));
+ w.write_line("fields,");
+ w.write_line(&file_descriptor_proto_expr(&self.message.scope));
+ });
+ w.write_line(")");
+ },
+ );
+ },
+ );
+ }
+
+ fn write_is_initialized(&self, w: &mut CodeWriter) {
+ w.def_fn(&format!("is_initialized(&self) -> bool"), |w| {
+ // TODO: use single loop
+
+ for f in self.required_fields() {
+ f.write_if_self_field_is_none(w, |w| {
+ w.write_line("return false;");
+ });
+ }
+
+ for f in self.message_fields() {
+ if let FieldKind::Map(..) = f.kind {
+ // TODO: check values
+ continue;
+ }
+
+ // TODO:
+ // if message is declared in this file and has no message fields,
+ // we could skip the check here
+ f.write_for_self_field(w, "v", |w, _t| {
+ w.if_stmt("!v.is_initialized()", |w| {
+ w.write_line("return false;");
+ });
+ });
+ }
+ w.write_line("true");
+ });
+ }
+
+ fn write_impl_message(&self, w: &mut CodeWriter) {
+ w.impl_for_block(
+ &format!("{}::Message", protobuf_crate_path(&self.customize)),
+ &self.type_name.to_string(), |w| {
+ self.write_is_initialized(w);
+ w.write_line("");
+ self.write_merge_from(w);
+ w.write_line("");
+ self.write_compute_size(w);
+ w.write_line("");
+ self.write_write_to_with_cached_sizes(w);
+ w.write_line("");
+ self.write_get_cached_size(w);
+ w.write_line("");
+ self.write_unknown_fields(w);
+ w.write_line("");
+ w.def_fn("as_any(&self) -> &dyn (::std::any::Any)", |w| {
+ w.write_line("self as &dyn (::std::any::Any)");
+ });
+ w.def_fn("as_any_mut(&mut self) -> &mut dyn (::std::any::Any)", |w| {
+ w.write_line("self as &mut dyn (::std::any::Any)");
+ });
+ w.def_fn(
+ "into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)>",
+ |w| {
+ w.write_line("self");
+ },
+ );
+ w.write_line("");
+ w.def_fn(
+ &format!("descriptor(&self) -> &'static {}::reflect::MessageDescriptor", protobuf_crate_path(&self.customize)),
+ |w| {
+ w.write_line("Self::descriptor_static()");
+ },
+ );
+ w.write_line("");
+ w.def_fn(&format!("new() -> {}", self.type_name), |w| {
+ w.write_line(&format!("{}::new()", self.type_name));
+ });
+ if !self.lite_runtime {
+ w.write_line("");
+ self.write_descriptor_static(w);
+ }
+ w.write_line("");
+ self.write_default_instance(w);
+ });
+ }
+
+ fn write_impl_value(&self, w: &mut CodeWriter) {
+ w.impl_for_block(
+ &format!(
+ "{}::reflect::ProtobufValue",
+ protobuf_crate_path(&self.customize)
+ ),
+ &self.type_name.to_string(),
+ |w| {
+ w.def_fn(
+ &format!(
+ "as_ref(&self) -> {}::reflect::ReflectValueRef",
+ protobuf_crate_path(&self.customize)
+ ),
+ |w| {
+ w.write_line(&format!(
+ "{}::reflect::ReflectValueRef::Message(self)",
+ protobuf_crate_path(&self.customize)
+ ))
+ },
+ )
+ },
+ )
+ }
+
+ fn write_impl_show(&self, w: &mut CodeWriter) {
+ w.impl_for_block("::std::fmt::Debug", &self.type_name.to_string(), |w| {
+ w.def_fn(
+ "fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result",
+ |w| {
+ w.write_line(&format!(
+ "{}::text_format::fmt(self, f)",
+ protobuf_crate_path(&self.customize)
+ ));
+ },
+ );
+ });
+ }
+
+ fn write_impl_clear(&self, w: &mut CodeWriter) {
+ w.impl_for_block(
+ &format!("{}::Clear", protobuf_crate_path(&self.customize)),
+ &format!("{}", self.type_name),
+ |w| {
+ w.def_fn("clear(&mut self)", |w| {
+ for f in self.fields_except_group() {
+ f.write_clear(w);
+ }
+ w.write_line("self.unknown_fields.clear();");
+ });
+ },
+ );
+ }
+
+ #[allow(dead_code)]
+ fn supports_derive_partial_eq(&self) -> bool {
+ // There's stack overflow in the compiler when struct has too many fields
+ // https://github.com/rust-lang/rust/issues/40119
+ self.fields.len() <= 500
+ }
+
+ fn write_struct(&self, w: &mut CodeWriter) {
+ let mut derive = vec!["PartialEq", "Clone", "Default"];
+ if self.lite_runtime {
+ derive.push("Debug");
+ }
+ w.derive(&derive);
+ serde::write_serde_attr(
+ w,
+ &self.customize,
+ "derive(::serde::Serialize, ::serde::Deserialize)",
+ );
+ w.pub_struct(&self.type_name.to_string(), |w| {
+ if !self.fields_except_oneof().is_empty() {
+ w.comment("message fields");
+ for field in self.fields_except_oneof() {
+ if field.proto_type == FieldDescriptorProto_Type::TYPE_GROUP {
+ w.comment(&format!("{}: <group>", &field.rust_name));
+ } else {
+ let vis = if field.expose_field {
+ Visibility::Public
+ } else {
+ match field.kind {
+ FieldKind::Repeated(..) => Visibility::Default,
+ FieldKind::Singular(SingularField { ref flag, .. }) => {
+ match *flag {
+ SingularFieldFlag::WithFlag { .. } => Visibility::Default,
+ SingularFieldFlag::WithoutFlag => Visibility::Public,
+ }
+ }
+ FieldKind::Map(..) => Visibility::Public,
+ FieldKind::Oneof(..) => unreachable!(),
+ }
+ };
+ w.field_decl_vis(
+ vis,
+ &field.rust_name.get(),
+ &field.full_storage_type().to_code(&self.customize),
+ );
+ }
+ }
+ }
+ if !self.oneofs().is_empty() {
+ w.comment("message oneof groups");
+ for oneof in self.oneofs() {
+ let vis = match self.expose_oneof() {
+ true => Visibility::Public,
+ false => Visibility::Default,
+ };
+ w.field_decl_vis(
+ vis,
+ oneof.oneof.field_name().get(),
+ &oneof.full_storage_type().to_code(&self.customize),
+ );
+ }
+ }
+ w.comment("special fields");
+ serde::write_serde_attr(w, &self.customize, "serde(skip)");
+ w.pub_field_decl(
+ "unknown_fields",
+ &format!("{}::UnknownFields", protobuf_crate_path(&self.customize)),
+ );
+ serde::write_serde_attr(w, &self.customize, "serde(skip)");
+ w.pub_field_decl(
+ "cached_size",
+ &format!("{}::CachedSize", protobuf_crate_path(&self.customize)),
+ );
+ });
+ }
+
+ fn write_impl_default_for_amp(&self, w: &mut CodeWriter) {
+ w.impl_args_for_block(
+ &["'a"],
+ "::std::default::Default",
+ &format!("&'a {}", self.type_name),
+ |w| {
+ w.def_fn(&format!("default() -> &'a {}", self.type_name), |w| {
+ w.write_line(&format!(
+ "<{} as {}::Message>::default_instance()",
+ self.type_name,
+ protobuf_crate_path(&self.customize),
+ ));
+ });
+ },
+ );
+ }
+
+ pub fn write(&self, w: &mut CodeWriter) {
+ self.write_struct(w);
+
+ w.write_line("");
+ self.write_impl_default_for_amp(w);
+
+ for oneof in self.oneofs() {
+ w.write_line("");
+ oneof.write_enum(w);
+ }
+
+ w.write_line("");
+ self.write_impl_self(w);
+ w.write_line("");
+ self.write_impl_message(w);
+ w.write_line("");
+ self.write_impl_clear(w);
+ if !self.lite_runtime {
+ w.write_line("");
+ self.write_impl_show(w);
+ }
+ w.write_line("");
+ self.write_impl_value(w);
+
+ let mut nested_prefix = self.type_name.to_string();
+ nested_prefix.push_str("_");
+
+ for nested in &self.message.to_scope().get_messages() {
+ // ignore map entries, because they are not used in map fields
+ if nested.map_entry().is_none() {
+ w.write_line("");
+ MessageGen::new(nested, self.root_scope, &self.customize).write(w);
+ }
+ }
+
+ for enum_type in &self.message.to_scope().get_enums() {
+ w.write_line("");
+ let current_file = self.message.get_scope().get_file_descriptor();
+ EnumGen::new(enum_type, current_file, &self.customize, self.root_scope).write(w);
+ }
+ }
+}