From 7863c4a8ce17863c49c2c3b4bdcebadaff1ccc72 Mon Sep 17 00:00:00 2001 From: Neil Shen Date: Fri, 21 Oct 2022 17:35:58 +0800 Subject: [PATCH 1/3] Add support for wrapping message in Option Signed-off-by: Neil Shen --- proto/rustproto.proto | 6 + protobuf-codegen/src/customize/mod.rs | 12 ++ .../src/customize/rustproto_proto.rs | 6 + protobuf-codegen/src/gen/field/accessor.rs | 19 ++- protobuf-codegen/src/gen/field/mod.rs | 28 +++- protobuf-parse/src/proto/rustproto.proto | 6 + protobuf/src/rt/message.rs | 14 ++ protobuf/src/rt/mod.rs | 1 + protobuf/src/rustproto.rs | 150 ++++++++++-------- .../src/v2/test_option_message_field.rs | 26 +++ ..._option_message_field_file_option_pb.proto | 13 ++ .../src/v2/test_option_message_field_pb.proto | 23 +++ 12 files changed, 228 insertions(+), 76 deletions(-) create mode 100644 test-crates/protobuf-codegen-protoc-test/src/v2/test_option_message_field.rs create mode 100644 test-crates/protobuf-codegen-protoc-test/src/v2/test_option_message_field_file_option_pb.proto create mode 100644 test-crates/protobuf-codegen-protoc-test/src/v2/test_option_message_field_pb.proto diff --git a/proto/rustproto.proto b/proto/rustproto.proto index 89f037775..1c7ff33b5 100644 --- a/proto/rustproto.proto +++ b/proto/rustproto.proto @@ -19,6 +19,8 @@ extend google.protobuf.FileOptions { optional bool tokio_bytes_all = 17011; // Use `bytes::Bytes` for `string` fields optional bool tokio_bytes_for_string_all = 17012; + // Use `Option` for `message` fields. + optional bool option_for_message_all = 17013; // When true, will only generate codes that works with lite runtime. optional bool lite_runtime_all = 17035; @@ -33,6 +35,8 @@ extend google.protobuf.MessageOptions { optional bool tokio_bytes = 17011; // Use `bytes::Bytes` for `string` fields optional bool tokio_bytes_for_string = 17012; + // Use `Option` for `message` fields. + optional bool option_for_message = 17013; } extend google.protobuf.FieldOptions { @@ -44,4 +48,6 @@ extend google.protobuf.FieldOptions { optional bool tokio_bytes_field = 17011; // Use `bytes::Bytes` for `string` fields optional bool tokio_bytes_for_string_field = 17012; + // Use `Option` for `message` fields. + optional bool option_for_message_field = 17013; } diff --git a/protobuf-codegen/src/customize/mod.rs b/protobuf-codegen/src/customize/mod.rs index 826bd3f6d..7aee061fa 100644 --- a/protobuf-codegen/src/customize/mod.rs +++ b/protobuf-codegen/src/customize/mod.rs @@ -98,6 +98,8 @@ pub struct Customize { pub(crate) tokio_bytes: Option, /// Use `bytes::Bytes` for `string` fields pub(crate) tokio_bytes_for_string: Option, + /// Use `Option` for `message` fields. + pub(crate) option_for_message: Option, /// Enable lite runtime. pub(crate) lite_runtime: Option, /// Generate `mod.rs` in the output directory. @@ -148,6 +150,11 @@ impl Customize { self } + pub fn option_for_message(mut self, option_for_message: bool) -> Self { + self.option_for_message = Some(option_for_message); + self + } + /// Generate code for "lite runtime". Generated code contains no code for reflection. /// So the generated code (and more importantly, generated binary size) is smaller, /// but reflection, text format, JSON serialization won't work. @@ -188,6 +195,9 @@ impl Customize { if let Some(v) = that.tokio_bytes_for_string { self.tokio_bytes_for_string = Some(v); } + if let Some(v) = that.option_for_message { + self.option_for_message = Some(v) + } if let Some(v) = that.lite_runtime { self.lite_runtime = Some(v); } @@ -232,6 +242,8 @@ impl Customize { r.tokio_bytes = Some(parse_bool(v)?); } else if n == "tokio_bytes_for_string" { r.tokio_bytes_for_string = Some(parse_bool(v)?); + } else if n == "option_for_message" { + r.option_for_message = Some(parse_bool(v)?); } else if n == "lite_runtime" { r.lite_runtime = Some(parse_bool(v)?); } else if n == "gen_mod_rs" { diff --git a/protobuf-codegen/src/customize/rustproto_proto.rs b/protobuf-codegen/src/customize/rustproto_proto.rs index 3d9a77b2f..01ef2b417 100644 --- a/protobuf-codegen/src/customize/rustproto_proto.rs +++ b/protobuf-codegen/src/customize/rustproto_proto.rs @@ -12,6 +12,7 @@ pub(crate) fn customize_from_rustproto_for_message(source: &MessageOptions) -> C let generate_getter = rustproto::exts::generate_getter.get(source); let tokio_bytes = rustproto::exts::tokio_bytes.get(source); let tokio_bytes_for_string = rustproto::exts::tokio_bytes_for_string.get(source); + let option_for_message = rustproto::exts::option_for_message.get(source); let lite_runtime = None; let gen_mod_rs = None; let inside_protobuf = None; @@ -21,6 +22,7 @@ pub(crate) fn customize_from_rustproto_for_message(source: &MessageOptions) -> C generate_getter, tokio_bytes, tokio_bytes_for_string, + option_for_message, lite_runtime, gen_mod_rs, inside_protobuf, @@ -37,6 +39,7 @@ pub(crate) fn customize_from_rustproto_for_field(source: &FieldOptions) -> Custo let generate_getter = rustproto::exts::generate_getter_field.get(source); let tokio_bytes = rustproto::exts::tokio_bytes_field.get(source); let tokio_bytes_for_string = rustproto::exts::tokio_bytes_for_string_field.get(source); + let option_for_message = rustproto::exts::option_for_message_field.get(source); let lite_runtime = None; let gen_mod_rs = None; let inside_protobuf = None; @@ -46,6 +49,7 @@ pub(crate) fn customize_from_rustproto_for_field(source: &FieldOptions) -> Custo generate_getter, tokio_bytes, tokio_bytes_for_string, + option_for_message, lite_runtime, gen_mod_rs, inside_protobuf, @@ -58,6 +62,7 @@ pub(crate) fn customize_from_rustproto_for_file(source: &FileOptions) -> Customi let generate_getter = rustproto::exts::generate_getter_all.get(source); let tokio_bytes = rustproto::exts::tokio_bytes_all.get(source); let tokio_bytes_for_string = rustproto::exts::tokio_bytes_for_string_all.get(source); + let option_for_message = rustproto::exts::option_for_message_all.get(source); let lite_runtime = rustproto::exts::lite_runtime_all.get(source); let gen_mod_rs = None; let inside_protobuf = None; @@ -67,6 +72,7 @@ pub(crate) fn customize_from_rustproto_for_file(source: &FileOptions) -> Customi generate_getter, tokio_bytes, tokio_bytes_for_string, + option_for_message, lite_runtime, inside_protobuf, gen_mod_rs, diff --git a/protobuf-codegen/src/gen/field/accessor.rs b/protobuf-codegen/src/gen/field/accessor.rs index 26f0ef48a..4d8b2694f 100644 --- a/protobuf-codegen/src/gen/field/accessor.rs +++ b/protobuf-codegen/src/gen/field/accessor.rs @@ -142,14 +142,21 @@ impl FieldGen<'_> { fn accessor_fn_singular_with_flag( &self, elem: &FieldElem, - _option_kind: OptionKind, + option_kind: OptionKind, ) -> AccessorFn { match elem { - FieldElem::Message(m) => AccessorFn { - name: "make_message_field_accessor".to_owned(), - type_params: vec![format!("{}", m.rust_name_relative(&self.file_and_mod()))], - callback_params: self.make_accessor_fns_lambda(), - }, + FieldElem::Message(m) => { + let name = if option_kind == OptionKind::MessageField { + "make_message_field_accessor".to_owned() + } else { + "make_option_accessor".to_owned() + }; + AccessorFn { + name, + type_params: vec![format!("{}", m.rust_name_relative(&self.file_and_mod()))], + callback_params: self.make_accessor_fns_lambda(), + } + } FieldElem::Primitive(..) | FieldElem::Enum(..) => AccessorFn { name: "make_option_accessor".to_owned(), type_params: vec!["_".to_owned()], diff --git a/protobuf-codegen/src/gen/field/mod.rs b/protobuf-codegen/src/gen/field/mod.rs index d6a5e44a4..25d565e14 100644 --- a/protobuf-codegen/src/gen/field/mod.rs +++ b/protobuf-codegen/src/gen/field/mod.rs @@ -206,7 +206,11 @@ impl<'a> FieldGen<'a> { let required = field.field.proto().label() == field_descriptor_proto::Label::LABEL_REQUIRED; let option_kind = match field.field.proto().type_() { - field_descriptor_proto::Type::TYPE_MESSAGE => OptionKind::MessageField, + field_descriptor_proto::Type::TYPE_MESSAGE + if customize.option_for_message != Some(true) => + { + OptionKind::MessageField + } _ => OptionKind::Option, }; @@ -995,11 +999,23 @@ impl<'a> FieldGen<'a> { fn write_merge_from_singular_case_block(&self, s: &SingularField, w: &mut CodeWriter) { w.case_block(&format!("{}", self.tag()), |w| match s.elem { FieldElem::Message(..) => { - w.write_line(&format!( - "{}::rt::read_singular_message_into_field(is, &mut self.{})?;", - protobuf_crate_path(&self.customize), - self.rust_name, - )); + if let SingularFieldFlag::WithFlag { + option_kind: OptionKind::Option { .. }, + .. + } = &s.flag + { + w.write_line(&format!( + "{}::rt::read_option_message_into_field(is, &mut self.{})?;", + protobuf_crate_path(&self.customize), + self.rust_name, + )); + } else { + w.write_line(&format!( + "{}::rt::read_singular_message_into_field(is, &mut self.{})?;", + protobuf_crate_path(&self.customize), + self.rust_name, + )); + } } _ => { let read_proc = s.elem.read_one_liner(); diff --git a/protobuf-parse/src/proto/rustproto.proto b/protobuf-parse/src/proto/rustproto.proto index 89f037775..1c7ff33b5 100644 --- a/protobuf-parse/src/proto/rustproto.proto +++ b/protobuf-parse/src/proto/rustproto.proto @@ -19,6 +19,8 @@ extend google.protobuf.FileOptions { optional bool tokio_bytes_all = 17011; // Use `bytes::Bytes` for `string` fields optional bool tokio_bytes_for_string_all = 17012; + // Use `Option` for `message` fields. + optional bool option_for_message_all = 17013; // When true, will only generate codes that works with lite runtime. optional bool lite_runtime_all = 17035; @@ -33,6 +35,8 @@ extend google.protobuf.MessageOptions { optional bool tokio_bytes = 17011; // Use `bytes::Bytes` for `string` fields optional bool tokio_bytes_for_string = 17012; + // Use `Option` for `message` fields. + optional bool option_for_message = 17013; } extend google.protobuf.FieldOptions { @@ -44,4 +48,6 @@ extend google.protobuf.FieldOptions { optional bool tokio_bytes_field = 17011; // Use `bytes::Bytes` for `string` fields optional bool tokio_bytes_for_string_field = 17012; + // Use `Option` for `message` fields. + optional bool option_for_message_field = 17013; } diff --git a/protobuf/src/rt/message.rs b/protobuf/src/rt/message.rs index 89434c035..a4ee86b8b 100644 --- a/protobuf/src/rt/message.rs +++ b/protobuf/src/rt/message.rs @@ -4,6 +4,20 @@ use crate::CodedOutputStream; use crate::Message; use crate::MessageField; +/// Read option `message` field. +pub fn read_option_message_into_field( + is: &mut CodedInputStream, + target: &mut Option, +) -> crate::Result<()> +where + M: Message, +{ + let mut m = M::new(); + is.merge_message(&mut m)?; + *target = Some(m); + Ok(()) +} + /// Read singular `message` field. pub fn read_singular_message_into_field( is: &mut CodedInputStream, diff --git a/protobuf/src/rt/mod.rs b/protobuf/src/rt/mod.rs index 90db0eb29..8c164b6b7 100644 --- a/protobuf/src/rt/mod.rs +++ b/protobuf/src/rt/mod.rs @@ -11,6 +11,7 @@ pub(crate) mod repeated; pub(crate) mod singular; pub(crate) mod unknown_or_group; +pub use message::read_option_message_into_field; pub use message::read_singular_message_into_field; pub use message::write_message_field_with_cached_size; pub use packed::vec_packed_bool_size; diff --git a/protobuf/src/rustproto.rs b/protobuf/src/rustproto.rs index 84db4409e..1e17cff8f 100644 --- a/protobuf/src/rustproto.rs +++ b/protobuf/src/rustproto.rs @@ -32,6 +32,8 @@ pub mod exts { pub const tokio_bytes_for_string_all: crate::ext::ExtFieldOptional = crate::ext::ExtFieldOptional::new(17012, crate::descriptor::field_descriptor_proto::Type::TYPE_BOOL); + pub const option_for_message_all: crate::ext::ExtFieldOptional = crate::ext::ExtFieldOptional::new(17013, crate::descriptor::field_descriptor_proto::Type::TYPE_BOOL); + pub const lite_runtime_all: crate::ext::ExtFieldOptional = crate::ext::ExtFieldOptional::new(17035, crate::descriptor::field_descriptor_proto::Type::TYPE_BOOL); pub const generate_accessors: crate::ext::ExtFieldOptional = crate::ext::ExtFieldOptional::new(17004, crate::descriptor::field_descriptor_proto::Type::TYPE_BOOL); @@ -42,6 +44,8 @@ pub mod exts { pub const tokio_bytes_for_string: crate::ext::ExtFieldOptional = crate::ext::ExtFieldOptional::new(17012, crate::descriptor::field_descriptor_proto::Type::TYPE_BOOL); + pub const option_for_message: crate::ext::ExtFieldOptional = crate::ext::ExtFieldOptional::new(17013, crate::descriptor::field_descriptor_proto::Type::TYPE_BOOL); + pub const generate_accessors_field: crate::ext::ExtFieldOptional = crate::ext::ExtFieldOptional::new(17004, crate::descriptor::field_descriptor_proto::Type::TYPE_BOOL); pub const generate_getter_field: crate::ext::ExtFieldOptional = crate::ext::ExtFieldOptional::new(17005, crate::descriptor::field_descriptor_proto::Type::TYPE_BOOL); @@ -49,6 +53,8 @@ pub mod exts { pub const tokio_bytes_field: crate::ext::ExtFieldOptional = crate::ext::ExtFieldOptional::new(17011, crate::descriptor::field_descriptor_proto::Type::TYPE_BOOL); pub const tokio_bytes_for_string_field: crate::ext::ExtFieldOptional = crate::ext::ExtFieldOptional::new(17012, crate::descriptor::field_descriptor_proto::Type::TYPE_BOOL); + + pub const option_for_message_field: crate::ext::ExtFieldOptional = crate::ext::ExtFieldOptional::new(17013, crate::descriptor::field_descriptor_proto::Type::TYPE_BOOL); } static file_descriptor_proto_data: &'static [u8] = b"\ @@ -59,32 +65,37 @@ static file_descriptor_proto_data: &'static [u8] = b"\ R\x11generateGetterAll:F\n\x0ftokio_bytes_all\x18\xf3\x84\x01\x20\x01(\ \x08\x12\x1c.google.protobuf.FileOptionsR\rtokioBytesAll:Z\n\x1atokio_by\ tes_for_string_all\x18\xf4\x84\x01\x20\x01(\x08\x12\x1c.google.protobuf.\ - FileOptionsR\x16tokioBytesForStringAll:H\n\x10lite_runtime_all\x18\x8b\ - \x85\x01\x20\x01(\x08\x12\x1c.google.protobuf.FileOptionsR\x0eliteRuntim\ - eAll:P\n\x12generate_accessors\x18\xec\x84\x01\x20\x01(\x08\x12\x1f.goog\ - le.protobuf.MessageOptionsR\x11generateAccessors:J\n\x0fgenerate_getter\ - \x18\xed\x84\x01\x20\x01(\x08\x12\x1f.google.protobuf.MessageOptionsR\ - \x0egenerateGetter:B\n\x0btokio_bytes\x18\xf3\x84\x01\x20\x01(\x08\x12\ - \x1f.google.protobuf.MessageOptionsR\ntokioBytes:V\n\x16tokio_bytes_for_\ - string\x18\xf4\x84\x01\x20\x01(\x08\x12\x1f.google.protobuf.MessageOptio\ - nsR\x13tokioBytesForString:Y\n\x18generate_accessors_field\x18\xec\x84\ - \x01\x20\x01(\x08\x12\x1d.google.protobuf.FieldOptionsR\x16generateAcces\ - sorsField:S\n\x15generate_getter_field\x18\xed\x84\x01\x20\x01(\x08\x12\ - \x1d.google.protobuf.FieldOptionsR\x13generateGetterField:K\n\x11tokio_b\ - ytes_field\x18\xf3\x84\x01\x20\x01(\x08\x12\x1d.google.protobuf.FieldOpt\ - ionsR\x0ftokioBytesField:_\n\x1ctokio_bytes_for_string_field\x18\xf4\x84\ - \x01\x20\x01(\x08\x12\x1d.google.protobuf.FieldOptionsR\x18tokioBytesFor\ - StringFieldJ\x9d\x0f\n\x06\x12\x04\0\0.\x01\n\x08\n\x01\x0c\x12\x03\0\0\ - \x12\n\t\n\x02\x03\0\x12\x03\x02\0*\n\xe5\x01\n\x01\x02\x12\x03\n\0\x122\ - ^\x20see\x20https://github.com/gogo/protobuf/blob/master/gogoproto/gogo.\ - proto\n\x20for\x20the\x20original\x20idea\n2{\x20Generated\x20files\x20c\ - an\x20be\x20customized\x20using\x20this\x20proto\n\x20or\x20using\x20`Cu\ - stomize`\x20struct\x20when\x20codegen\x20is\x20invoked\x20programmatical\ - ly.\n\n\t\n\x01\x07\x12\x04\x0c\0\x18\x01\nP\n\x02\x07\0\x12\x03\x0e\x04\ - 1\x1aE\x20When\x20false,\x20`get_`,\x20`set_`,\x20`mut_`\x20etc.\x20acce\ - ssors\x20are\x20not\x20generated\n\n\n\n\x03\x07\0\x02\x12\x03\x0c\x07\"\ - \n\n\n\x03\x07\0\x04\x12\x03\x0e\x04\x0c\n\n\n\x03\x07\0\x05\x12\x03\x0e\ - \r\x11\n\n\n\x03\x07\0\x01\x12\x03\x0e\x12(\n\n\n\x03\x07\0\x03\x12\x03\ + FileOptionsR\x16tokioBytesForStringAll:S\n\x16option_for_message_all\x18\ + \xf5\x84\x01\x20\x01(\x08\x12\x1c.google.protobuf.FileOptionsR\x13option\ + ForMessageAll:H\n\x10lite_runtime_all\x18\x8b\x85\x01\x20\x01(\x08\x12\ + \x1c.google.protobuf.FileOptionsR\x0eliteRuntimeAll:P\n\x12generate_acce\ + ssors\x18\xec\x84\x01\x20\x01(\x08\x12\x1f.google.protobuf.MessageOption\ + sR\x11generateAccessors:J\n\x0fgenerate_getter\x18\xed\x84\x01\x20\x01(\ + \x08\x12\x1f.google.protobuf.MessageOptionsR\x0egenerateGetter:B\n\x0bto\ + kio_bytes\x18\xf3\x84\x01\x20\x01(\x08\x12\x1f.google.protobuf.MessageOp\ + tionsR\ntokioBytes:V\n\x16tokio_bytes_for_string\x18\xf4\x84\x01\x20\x01\ + (\x08\x12\x1f.google.protobuf.MessageOptionsR\x13tokioBytesForString:O\n\ + \x12option_for_message\x18\xf5\x84\x01\x20\x01(\x08\x12\x1f.google.proto\ + buf.MessageOptionsR\x10optionForMessage:Y\n\x18generate_accessors_field\ + \x18\xec\x84\x01\x20\x01(\x08\x12\x1d.google.protobuf.FieldOptionsR\x16g\ + enerateAccessorsField:S\n\x15generate_getter_field\x18\xed\x84\x01\x20\ + \x01(\x08\x12\x1d.google.protobuf.FieldOptionsR\x13generateGetterField:K\ + \n\x11tokio_bytes_field\x18\xf3\x84\x01\x20\x01(\x08\x12\x1d.google.prot\ + obuf.FieldOptionsR\x0ftokioBytesField:_\n\x1ctokio_bytes_for_string_fiel\ + d\x18\xf4\x84\x01\x20\x01(\x08\x12\x1d.google.protobuf.FieldOptionsR\x18\ + tokioBytesForStringField:X\n\x18option_for_message_field\x18\xf5\x84\x01\ + \x20\x01(\x08\x12\x1d.google.protobuf.FieldOptionsR\x15optionForMessageF\ + ieldJ\xe4\x11\n\x06\x12\x04\0\04\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\t\ + \n\x02\x03\0\x12\x03\x02\0*\n\xe5\x01\n\x01\x02\x12\x03\n\0\x122^\x20see\ + \x20https://github.com/gogo/protobuf/blob/master/gogoproto/gogo.proto\n\ + \x20for\x20the\x20original\x20idea\n2{\x20Generated\x20files\x20can\x20b\ + e\x20customized\x20using\x20this\x20proto\n\x20or\x20using\x20`Customize\ + `\x20struct\x20when\x20codegen\x20is\x20invoked\x20programmatically.\n\n\ + \t\n\x01\x07\x12\x04\x0c\0\x1a\x01\nP\n\x02\x07\0\x12\x03\x0e\x041\x1aE\ + \x20When\x20false,\x20`get_`,\x20`set_`,\x20`mut_`\x20etc.\x20accessors\ + \x20are\x20not\x20generated\n\n\n\n\x03\x07\0\x02\x12\x03\x0c\x07\"\n\n\ + \n\x03\x07\0\x04\x12\x03\x0e\x04\x0c\n\n\n\x03\x07\0\x05\x12\x03\x0e\r\ + \x11\n\n\n\x03\x07\0\x01\x12\x03\x0e\x12(\n\n\n\x03\x07\0\x03\x12\x03\ \x0e+0\nL\n\x02\x07\x01\x12\x03\x10\x04.\x1aA\x20When\x20false,\x20`get_\ `\x20is\x20not\x20generated\x20even\x20if\x20`syntax\x20=\x20\"proto2\"`\ \n\n\n\n\x03\x07\x01\x02\x12\x03\x0c\x07\"\n\n\n\x03\x07\x01\x04\x12\x03\ @@ -98,46 +109,57 @@ static file_descriptor_proto_data: &'static [u8] = b"\ `string`\x20fields\n\n\n\n\x03\x07\x03\x02\x12\x03\x0c\x07\"\n\n\n\x03\ \x07\x03\x04\x12\x03\x14\x04\x0c\n\n\n\x03\x07\x03\x05\x12\x03\x14\r\x11\ \n\n\n\x03\x07\x03\x01\x12\x03\x14\x12,\n\n\n\x03\x07\x03\x03\x12\x03\ - \x14/4\nN\n\x02\x07\x04\x12\x03\x17\x04+\x1aC\x20When\x20true,\x20will\ - \x20only\x20generate\x20codes\x20that\x20works\x20with\x20lite\x20runtim\ - e.\n\n\n\n\x03\x07\x04\x02\x12\x03\x0c\x07\"\n\n\n\x03\x07\x04\x04\x12\ - \x03\x17\x04\x0c\n\n\n\x03\x07\x04\x05\x12\x03\x17\r\x11\n\n\n\x03\x07\ - \x04\x01\x12\x03\x17\x12\"\n\n\n\x03\x07\x04\x03\x12\x03\x17%*\n\t\n\x01\ - \x07\x12\x04\x1a\0#\x01\nP\n\x02\x07\x05\x12\x03\x1c\x04-\x1aE\x20When\ + \x14/4\n/\n\x02\x07\x04\x12\x03\x16\x041\x1a$\x20Use\x20`Option`\x20for\ + \x20`message`\x20fields.\n\n\n\n\x03\x07\x04\x02\x12\x03\x0c\x07\"\n\n\n\ + \x03\x07\x04\x04\x12\x03\x16\x04\x0c\n\n\n\x03\x07\x04\x05\x12\x03\x16\r\ + \x11\n\n\n\x03\x07\x04\x01\x12\x03\x16\x12(\n\n\n\x03\x07\x04\x03\x12\ + \x03\x16+0\nN\n\x02\x07\x05\x12\x03\x19\x04+\x1aC\x20When\x20true,\x20wi\ + ll\x20only\x20generate\x20codes\x20that\x20works\x20with\x20lite\x20runt\ + ime.\n\n\n\n\x03\x07\x05\x02\x12\x03\x0c\x07\"\n\n\n\x03\x07\x05\x04\x12\ + \x03\x19\x04\x0c\n\n\n\x03\x07\x05\x05\x12\x03\x19\r\x11\n\n\n\x03\x07\ + \x05\x01\x12\x03\x19\x12\"\n\n\n\x03\x07\x05\x03\x12\x03\x19%*\n\t\n\x01\ + \x07\x12\x04\x1c\0'\x01\nP\n\x02\x07\x06\x12\x03\x1e\x04-\x1aE\x20When\ \x20false,\x20`get_`,\x20`set_`,\x20`mut_`\x20etc.\x20accessors\x20are\ - \x20not\x20generated\n\n\n\n\x03\x07\x05\x02\x12\x03\x1a\x07%\n\n\n\x03\ - \x07\x05\x04\x12\x03\x1c\x04\x0c\n\n\n\x03\x07\x05\x05\x12\x03\x1c\r\x11\ - \n\n\n\x03\x07\x05\x01\x12\x03\x1c\x12$\n\n\n\x03\x07\x05\x03\x12\x03\ - \x1c',\nL\n\x02\x07\x06\x12\x03\x1e\x04*\x1aA\x20When\x20false,\x20`get_\ + \x20not\x20generated\n\n\n\n\x03\x07\x06\x02\x12\x03\x1c\x07%\n\n\n\x03\ + \x07\x06\x04\x12\x03\x1e\x04\x0c\n\n\n\x03\x07\x06\x05\x12\x03\x1e\r\x11\ + \n\n\n\x03\x07\x06\x01\x12\x03\x1e\x12$\n\n\n\x03\x07\x06\x03\x12\x03\ + \x1e',\nL\n\x02\x07\x07\x12\x03\x20\x04*\x1aA\x20When\x20false,\x20`get_\ `\x20is\x20not\x20generated\x20even\x20if\x20`syntax\x20=\x20\"proto2\"`\ - \n\n\n\n\x03\x07\x06\x02\x12\x03\x1a\x07%\n\n\n\x03\x07\x06\x04\x12\x03\ - \x1e\x04\x0c\n\n\n\x03\x07\x06\x05\x12\x03\x1e\r\x11\n\n\n\x03\x07\x06\ - \x01\x12\x03\x1e\x12!\n\n\n\x03\x07\x06\x03\x12\x03\x1e$)\n2\n\x02\x07\ - \x07\x12\x03\x20\x04&\x1a'\x20Use\x20`bytes::Bytes`\x20for\x20`bytes`\ - \x20fields\n\n\n\n\x03\x07\x07\x02\x12\x03\x1a\x07%\n\n\n\x03\x07\x07\ - \x04\x12\x03\x20\x04\x0c\n\n\n\x03\x07\x07\x05\x12\x03\x20\r\x11\n\n\n\ - \x03\x07\x07\x01\x12\x03\x20\x12\x1d\n\n\n\x03\x07\x07\x03\x12\x03\x20\ - \x20%\n3\n\x02\x07\x08\x12\x03\"\x041\x1a(\x20Use\x20`bytes::Bytes`\x20f\ - or\x20`string`\x20fields\n\n\n\n\x03\x07\x08\x02\x12\x03\x1a\x07%\n\n\n\ - \x03\x07\x08\x04\x12\x03\"\x04\x0c\n\n\n\x03\x07\x08\x05\x12\x03\"\r\x11\ - \n\n\n\x03\x07\x08\x01\x12\x03\"\x12(\n\n\n\x03\x07\x08\x03\x12\x03\"+0\ - \n\t\n\x01\x07\x12\x04%\0.\x01\nP\n\x02\x07\t\x12\x03'\x043\x1aE\x20When\ - \x20false,\x20`get_`,\x20`set_`,\x20`mut_`\x20etc.\x20accessors\x20are\ - \x20not\x20generated\n\n\n\n\x03\x07\t\x02\x12\x03%\x07#\n\n\n\x03\x07\t\ - \x04\x12\x03'\x04\x0c\n\n\n\x03\x07\t\x05\x12\x03'\r\x11\n\n\n\x03\x07\t\ - \x01\x12\x03'\x12*\n\n\n\x03\x07\t\x03\x12\x03'-2\nL\n\x02\x07\n\x12\x03\ - )\x040\x1aA\x20When\x20false,\x20`get_`\x20is\x20not\x20generated\x20eve\ - n\x20if\x20`syntax\x20=\x20\"proto2\"`\n\n\n\n\x03\x07\n\x02\x12\x03%\ - \x07#\n\n\n\x03\x07\n\x04\x12\x03)\x04\x0c\n\n\n\x03\x07\n\x05\x12\x03)\ - \r\x11\n\n\n\x03\x07\n\x01\x12\x03)\x12'\n\n\n\x03\x07\n\x03\x12\x03)*/\ - \n2\n\x02\x07\x0b\x12\x03+\x04,\x1a'\x20Use\x20`bytes::Bytes`\x20for\x20\ - `bytes`\x20fields\n\n\n\n\x03\x07\x0b\x02\x12\x03%\x07#\n\n\n\x03\x07\ - \x0b\x04\x12\x03+\x04\x0c\n\n\n\x03\x07\x0b\x05\x12\x03+\r\x11\n\n\n\x03\ - \x07\x0b\x01\x12\x03+\x12#\n\n\n\x03\x07\x0b\x03\x12\x03+&+\n3\n\x02\x07\ - \x0c\x12\x03-\x047\x1a(\x20Use\x20`bytes::Bytes`\x20for\x20`string`\x20f\ - ields\n\n\n\n\x03\x07\x0c\x02\x12\x03%\x07#\n\n\n\x03\x07\x0c\x04\x12\ - \x03-\x04\x0c\n\n\n\x03\x07\x0c\x05\x12\x03-\r\x11\n\n\n\x03\x07\x0c\x01\ - \x12\x03-\x12.\n\n\n\x03\x07\x0c\x03\x12\x03-16\ + \n\n\n\n\x03\x07\x07\x02\x12\x03\x1c\x07%\n\n\n\x03\x07\x07\x04\x12\x03\ + \x20\x04\x0c\n\n\n\x03\x07\x07\x05\x12\x03\x20\r\x11\n\n\n\x03\x07\x07\ + \x01\x12\x03\x20\x12!\n\n\n\x03\x07\x07\x03\x12\x03\x20$)\n2\n\x02\x07\ + \x08\x12\x03\"\x04&\x1a'\x20Use\x20`bytes::Bytes`\x20for\x20`bytes`\x20f\ + ields\n\n\n\n\x03\x07\x08\x02\x12\x03\x1c\x07%\n\n\n\x03\x07\x08\x04\x12\ + \x03\"\x04\x0c\n\n\n\x03\x07\x08\x05\x12\x03\"\r\x11\n\n\n\x03\x07\x08\ + \x01\x12\x03\"\x12\x1d\n\n\n\x03\x07\x08\x03\x12\x03\"\x20%\n3\n\x02\x07\ + \t\x12\x03$\x041\x1a(\x20Use\x20`bytes::Bytes`\x20for\x20`string`\x20fie\ + lds\n\n\n\n\x03\x07\t\x02\x12\x03\x1c\x07%\n\n\n\x03\x07\t\x04\x12\x03$\ + \x04\x0c\n\n\n\x03\x07\t\x05\x12\x03$\r\x11\n\n\n\x03\x07\t\x01\x12\x03$\ + \x12(\n\n\n\x03\x07\t\x03\x12\x03$+0\n/\n\x02\x07\n\x12\x03&\x04-\x1a$\ + \x20Use\x20`Option`\x20for\x20`message`\x20fields.\n\n\n\n\x03\x07\n\x02\ + \x12\x03\x1c\x07%\n\n\n\x03\x07\n\x04\x12\x03&\x04\x0c\n\n\n\x03\x07\n\ + \x05\x12\x03&\r\x11\n\n\n\x03\x07\n\x01\x12\x03&\x12$\n\n\n\x03\x07\n\ + \x03\x12\x03&',\n\t\n\x01\x07\x12\x04)\04\x01\nP\n\x02\x07\x0b\x12\x03+\ + \x043\x1aE\x20When\x20false,\x20`get_`,\x20`set_`,\x20`mut_`\x20etc.\x20\ + accessors\x20are\x20not\x20generated\n\n\n\n\x03\x07\x0b\x02\x12\x03)\ + \x07#\n\n\n\x03\x07\x0b\x04\x12\x03+\x04\x0c\n\n\n\x03\x07\x0b\x05\x12\ + \x03+\r\x11\n\n\n\x03\x07\x0b\x01\x12\x03+\x12*\n\n\n\x03\x07\x0b\x03\ + \x12\x03+-2\nL\n\x02\x07\x0c\x12\x03-\x040\x1aA\x20When\x20false,\x20`ge\ + t_`\x20is\x20not\x20generated\x20even\x20if\x20`syntax\x20=\x20\"proto2\ + \"`\n\n\n\n\x03\x07\x0c\x02\x12\x03)\x07#\n\n\n\x03\x07\x0c\x04\x12\x03-\ + \x04\x0c\n\n\n\x03\x07\x0c\x05\x12\x03-\r\x11\n\n\n\x03\x07\x0c\x01\x12\ + \x03-\x12'\n\n\n\x03\x07\x0c\x03\x12\x03-*/\n2\n\x02\x07\r\x12\x03/\x04,\ + \x1a'\x20Use\x20`bytes::Bytes`\x20for\x20`bytes`\x20fields\n\n\n\n\x03\ + \x07\r\x02\x12\x03)\x07#\n\n\n\x03\x07\r\x04\x12\x03/\x04\x0c\n\n\n\x03\ + \x07\r\x05\x12\x03/\r\x11\n\n\n\x03\x07\r\x01\x12\x03/\x12#\n\n\n\x03\ + \x07\r\x03\x12\x03/&+\n3\n\x02\x07\x0e\x12\x031\x047\x1a(\x20Use\x20`byt\ + es::Bytes`\x20for\x20`string`\x20fields\n\n\n\n\x03\x07\x0e\x02\x12\x03)\ + \x07#\n\n\n\x03\x07\x0e\x04\x12\x031\x04\x0c\n\n\n\x03\x07\x0e\x05\x12\ + \x031\r\x11\n\n\n\x03\x07\x0e\x01\x12\x031\x12.\n\n\n\x03\x07\x0e\x03\ + \x12\x03116\n/\n\x02\x07\x0f\x12\x033\x043\x1a$\x20Use\x20`Option`\x20fo\ + r\x20`message`\x20fields.\n\n\n\n\x03\x07\x0f\x02\x12\x03)\x07#\n\n\n\ + \x03\x07\x0f\x04\x12\x033\x04\x0c\n\n\n\x03\x07\x0f\x05\x12\x033\r\x11\n\ + \n\n\x03\x07\x0f\x01\x12\x033\x12*\n\n\n\x03\x07\x0f\x03\x12\x033-2\ "; /// `FileDescriptorProto` object which was a source for this generated file diff --git a/test-crates/protobuf-codegen-protoc-test/src/v2/test_option_message_field.rs b/test-crates/protobuf-codegen-protoc-test/src/v2/test_option_message_field.rs new file mode 100644 index 000000000..8d199bf0e --- /dev/null +++ b/test-crates/protobuf-codegen-protoc-test/src/v2/test_option_message_field.rs @@ -0,0 +1,26 @@ +use protobuf::*; + +use super::test_option_message_field_file_option_pb::*; +use super::test_option_message_field_pb::*; + +#[test] +fn test_option_message_field_field_option() { + let msg = TestOptionMessageFieldFieldOption::default_instance(); + let _v: &Option = &msg.v; + let _p: &MessageField = &msg.p; + let _b: &Option> = &msg.b; +} + +#[test] +fn test_option_message_field_message_option() { + let msg = TestOptionMessageFieldMessageOption::default_instance(); + let _v: &Option = &msg.v; + let _vv: &Option = &msg.vv; +} + +#[test] +fn test_option_message_field_file_option() { + let msg = TestOptionMessageFieldFileOption::default_instance(); + let _v: &Option = &msg.v; + let _vv: &Option = &msg.vv; +} diff --git a/test-crates/protobuf-codegen-protoc-test/src/v2/test_option_message_field_file_option_pb.proto b/test-crates/protobuf-codegen-protoc-test/src/v2/test_option_message_field_file_option_pb.proto new file mode 100644 index 000000000..718f9344f --- /dev/null +++ b/test-crates/protobuf-codegen-protoc-test/src/v2/test_option_message_field_file_option_pb.proto @@ -0,0 +1,13 @@ +syntax = "proto2"; + +package test_option_message_field_file_option; + +import "test_option_message_field_pb.proto"; +import "rustproto.proto"; + +option (rustproto.option_for_message_all) = true; + +message TestOptionMessageFieldFileOption { + optional test_option_message_field.Msg v = 1; + optional test_option_message_field.Msg vv = 2; +} diff --git a/test-crates/protobuf-codegen-protoc-test/src/v2/test_option_message_field_pb.proto b/test-crates/protobuf-codegen-protoc-test/src/v2/test_option_message_field_pb.proto new file mode 100644 index 000000000..006c76de5 --- /dev/null +++ b/test-crates/protobuf-codegen-protoc-test/src/v2/test_option_message_field_pb.proto @@ -0,0 +1,23 @@ +syntax = "proto2"; + +package test_option_message_field; + +import "rustproto.proto"; + +message Msg { + optional int64 i = 1; +} + +message TestOptionMessageFieldFieldOption { + optional Msg v = 1 [(rustproto.option_for_message_field) = true]; + optional Msg p = 2 [(rustproto.option_for_message_field) = false]; + // option_for_message_field has no effect to other fields. + optional bytes b = 3 [(rustproto.option_for_message_field) = true]; +} + +message TestOptionMessageFieldMessageOption { + option (rustproto.option_for_message) = true; + + optional Msg v = 1; + optional Msg vv = 2; +} From e556498c8dd45601723cfd6007152bb2fc31e07a Mon Sep 17 00:00:00 2001 From: Neil Shen Date: Tue, 25 Oct 2022 22:40:03 +0800 Subject: [PATCH 2/3] Add benchmark for `option_for_message` Results in Intel(R) Xeon(R) CPU E5-2630 v4 @ 2.20GHz ``` test clone_and_drop_message_field ... bench: 148 ns/iter (+/- 24) test clone_and_drop_message_field_with_option ... bench: 36 ns/iter (+/- 5) ``` Signed-off-by: Neil Shen --- test-crates/perftest/misc/benches/vs.rs | 35 ++++++++++++++++++++ test-crates/perftest/misc/build.rs | 15 +++++++++ test-crates/perftest/misc/src/.gitignore | 1 + test-crates/perftest/misc/src/lib.rs | 2 ++ test-crates/perftest/misc/src/messages.proto | 24 ++++++++++++++ 5 files changed, 77 insertions(+) create mode 100644 test-crates/perftest/misc/benches/vs.rs create mode 100644 test-crates/perftest/misc/src/.gitignore create mode 100644 test-crates/perftest/misc/src/messages.proto diff --git a/test-crates/perftest/misc/benches/vs.rs b/test-crates/perftest/misc/benches/vs.rs new file mode 100644 index 000000000..4b14e4661 --- /dev/null +++ b/test-crates/perftest/misc/benches/vs.rs @@ -0,0 +1,35 @@ +// `cargo test --benches` and `#[feature(test)]` work only in nightly +#![cfg(rustc_nightly)] +#![feature(test)] + +extern crate test; + +use protobuf::MessageField; +use protobuf_perftest_misc::black_box; +use protobuf_perftest_misc::messages; + +#[bench] +fn clone_and_drop_message_field(b: &mut test::Bencher) { + let mut m = messages::TestMessageField::new(); + m.m1 = MessageField::some(messages::SimpleMessage::new()); + m.m2 = MessageField::some(messages::SimpleMessage::new()); + m.m3 = MessageField::some(messages::SimpleMessage::new()); + m.m4 = MessageField::some(messages::SimpleMessage::new()); + b.iter(|| { + let clone = black_box(m.clone()); + drop(clone); + }) +} + +#[bench] +fn clone_and_drop_message_field_with_option(b: &mut test::Bencher) { + let mut m = messages::TestMessageFieldWithOption::new(); + m.m1 = Some(messages::SimpleMessage::new()); + m.m2 = Some(messages::SimpleMessage::new()); + m.m3 = Some(messages::SimpleMessage::new()); + m.m4 = Some(messages::SimpleMessage::new()); + b.iter(|| { + let clone = black_box(m.clone()); + drop(clone); + }) +} diff --git a/test-crates/perftest/misc/build.rs b/test-crates/perftest/misc/build.rs index 61f68c752..7d3251045 100644 --- a/test-crates/perftest/misc/build.rs +++ b/test-crates/perftest/misc/build.rs @@ -2,6 +2,19 @@ use std::env; use std::io::Read; use std::process; +use protobuf_codegen::Codegen; +use protobuf_codegen::Customize; + +fn generate_protos() { + Codegen::new() + .pure() + .out_dir("src") + .input("src/messages.proto") + .includes(&["src", "../../proto"]) + .customize(Customize::default().gen_mod_rs(false)) + .run_from_script(); +} + // % rustc +stable --version // rustc 1.26.0 (a77568041 2018-05-07) // % rustc +beta --version @@ -38,5 +51,7 @@ fn export_rustc_cfg() { } fn main() { + generate_protos(); + export_rustc_cfg(); } diff --git a/test-crates/perftest/misc/src/.gitignore b/test-crates/perftest/misc/src/.gitignore new file mode 100644 index 000000000..71cf3a0c2 --- /dev/null +++ b/test-crates/perftest/misc/src/.gitignore @@ -0,0 +1 @@ +messages.rs diff --git a/test-crates/perftest/misc/src/lib.rs b/test-crates/perftest/misc/src/lib.rs index 9042726c6..5dd8448e2 100644 --- a/test-crates/perftest/misc/src/lib.rs +++ b/test-crates/perftest/misc/src/lib.rs @@ -13,3 +13,5 @@ pub fn black_box(v: T) -> T { pub fn black_box(v: T) -> T { std::hint::black_box(v) } + +pub mod messages; diff --git a/test-crates/perftest/misc/src/messages.proto b/test-crates/perftest/misc/src/messages.proto new file mode 100644 index 000000000..9a2561a97 --- /dev/null +++ b/test-crates/perftest/misc/src/messages.proto @@ -0,0 +1,24 @@ +syntax = "proto2"; + +import "rustproto.proto"; + +message SimpleMessage { + optional int64 i = 1; + optional uint64 u = 2; +} + +message TestMessageField { + optional SimpleMessage m1 = 1; + optional SimpleMessage m2 = 2; + optional SimpleMessage m3 = 3; + optional SimpleMessage m4 = 4; +} + +message TestMessageFieldWithOption { + option(rustproto.option_for_message) = true; + + optional SimpleMessage m1 = 1; + optional SimpleMessage m2 = 2; + optional SimpleMessage m3 = 3; + optional SimpleMessage m4 = 4; +} \ No newline at end of file From b151804cdd950eb95fa0ade1347b89b2881d002a Mon Sep 17 00:00:00 2001 From: Neil Shen Date: Thu, 27 Oct 2022 12:53:22 +0800 Subject: [PATCH 3/3] address linter warnings Signed-off-by: Neil Shen --- test-crates/perftest/misc/src/messages.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-crates/perftest/misc/src/messages.proto b/test-crates/perftest/misc/src/messages.proto index 9a2561a97..1dddd810b 100644 --- a/test-crates/perftest/misc/src/messages.proto +++ b/test-crates/perftest/misc/src/messages.proto @@ -21,4 +21,4 @@ message TestMessageFieldWithOption { optional SimpleMessage m2 = 2; optional SimpleMessage m3 = 3; optional SimpleMessage m4 = 4; -} \ No newline at end of file +}