diff --git a/proto/rustproto.proto b/proto/rustproto.proto index b9ca843c5..e96c3cd63 100644 --- a/proto/rustproto.proto +++ b/proto/rustproto.proto @@ -21,6 +21,8 @@ extend google.protobuf.FileOptions { optional bool tokio_bytes_for_string_all = 17012; // When false, `#[non_exhaustive]` is not generated for `oneof` fields. optional bool oneofs_non_exhaustive_all = 17013; + // When true, generate `BTreeMap` instead of `HashMap` for map fields. + optional bool btreemap_all = 17014; // When true, will only generate codes that works with lite runtime. optional bool lite_runtime_all = 17035; @@ -37,6 +39,8 @@ extend google.protobuf.MessageOptions { optional bool tokio_bytes_for_string = 17012; // When false, `#[non_exhaustive]` is not generated for `oneof` fields. optional bool oneofs_non_exhaustive = 17013; + // When true, generate `BTreeMap` instead of `HashMap` for map fields. + optional bool btreemap = 17014; } extend google.protobuf.FieldOptions { @@ -50,4 +54,6 @@ extend google.protobuf.FieldOptions { optional bool tokio_bytes_for_string_field = 17012; // When false, `#[non_exhaustive]` is not generated for `oneof` fields. optional bool oneofs_non_exhaustive_field = 17013; + // When true, generate `BTreeMap` instead of `HashMap` for map fields. + optional bool btreemap_field = 17014; } diff --git a/protobuf-codegen/src/customize/mod.rs b/protobuf-codegen/src/customize/mod.rs index bebb7658b..22cc7d550 100644 --- a/protobuf-codegen/src/customize/mod.rs +++ b/protobuf-codegen/src/customize/mod.rs @@ -111,6 +111,8 @@ pub struct Customize { /// Used internally to generate protos bundled in protobuf crate /// like `descriptor.proto` pub(crate) inside_protobuf: Option, + /// When true, protobuf maps are represented with `std::collections::BTreeMap` + pub(crate) btreemap: Option, } #[derive(Debug, thiserror::Error)] @@ -178,6 +180,14 @@ impl Customize { self } + /// Use btreemaps for maps representation + pub fn btreemaps(self, use_btreemaps: bool) -> Self { + Self { + btreemap: Some(use_btreemaps), + ..self + } + } + /// Update fields of self with fields defined in other customize pub fn update_with(&mut self, that: &Customize) { if let Some(v) = &that.before { @@ -204,6 +214,9 @@ impl Customize { if let Some(v) = that.inside_protobuf { self.inside_protobuf = Some(v); } + if let Some(v) = that.btreemap { + self.btreemap = Some(v); + } } /// Update unset fields of self with fields from other customize @@ -243,6 +256,8 @@ impl Customize { r.lite_runtime = Some(parse_bool(v)?); } else if n == "gen_mod_rs" { r.gen_mod_rs = Some(parse_bool(v)?); + } else if n == "btreemap" { + r.btreemap = Some(parse_bool(v)?); } else if n == "inside_protobuf" { r.inside_protobuf = Some(parse_bool(v)?); } else if n == "lite" { diff --git a/protobuf-codegen/src/customize/rustproto_proto.rs b/protobuf-codegen/src/customize/rustproto_proto.rs index e48303102..7a5ee1216 100644 --- a/protobuf-codegen/src/customize/rustproto_proto.rs +++ b/protobuf-codegen/src/customize/rustproto_proto.rs @@ -13,6 +13,7 @@ pub(crate) fn customize_from_rustproto_for_message(source: &MessageOptions) -> C let tokio_bytes = rustproto::exts::tokio_bytes.get(source); let tokio_bytes_for_string = rustproto::exts::tokio_bytes_for_string.get(source); let oneofs_non_exhaustive = rustproto::exts::oneofs_non_exhaustive.get(source); + let btreemap = rustproto::exts::btreemap.get(source); let lite_runtime = None; let gen_mod_rs = None; let inside_protobuf = None; @@ -26,6 +27,7 @@ pub(crate) fn customize_from_rustproto_for_message(source: &MessageOptions) -> C lite_runtime, gen_mod_rs, inside_protobuf, + btreemap, } } @@ -40,6 +42,7 @@ pub(crate) fn customize_from_rustproto_for_field(source: &FieldOptions) -> Custo 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 oneofs_non_exhaustive = rustproto::exts::oneofs_non_exhaustive_field.get(source); + let btreemap = rustproto::exts::btreemap_field.get(source); let lite_runtime = None; let gen_mod_rs = None; let inside_protobuf = None; @@ -53,6 +56,7 @@ pub(crate) fn customize_from_rustproto_for_field(source: &FieldOptions) -> Custo lite_runtime, gen_mod_rs, inside_protobuf, + btreemap, } } @@ -64,6 +68,7 @@ pub(crate) fn customize_from_rustproto_for_file(source: &FileOptions) -> Customi let tokio_bytes_for_string = rustproto::exts::tokio_bytes_for_string_all.get(source); let oneofs_non_exhaustive = rustproto::exts::oneofs_non_exhaustive_all.get(source); let lite_runtime = rustproto::exts::lite_runtime_all.get(source); + let btreemap = rustproto::exts::btreemap_all.get(source); let gen_mod_rs = None; let inside_protobuf = None; Customize { @@ -76,5 +81,6 @@ pub(crate) fn customize_from_rustproto_for_file(source: &FileOptions) -> Customi lite_runtime, inside_protobuf, gen_mod_rs, + btreemap, } } diff --git a/protobuf-codegen/src/gen/field/mod.rs b/protobuf-codegen/src/gen/field/mod.rs index 2ac0cdb2a..344aca2e2 100644 --- a/protobuf-codegen/src/gen/field/mod.rs +++ b/protobuf-codegen/src/gen/field/mod.rs @@ -302,6 +302,12 @@ impl<'a> FieldGen<'a> { pub(crate) fn full_storage_type(&self, reference: &FileAndMod) -> RustType { match self.kind { FieldKind::Repeated(ref repeated) => repeated.rust_type(reference), + FieldKind::Map(MapField { + ref key, ref value, .. + }) if self.customize.btreemap == Some(true) => RustType::BTreeMap( + Box::new(key.rust_storage_elem_type(reference)), + Box::new(value.rust_storage_elem_type(reference)), + ), FieldKind::Map(MapField { ref key, ref value, .. }) => RustType::HashMap( diff --git a/protobuf-codegen/src/gen/rust_types_values.rs b/protobuf-codegen/src/gen/rust_types_values.rs index c024192be..ee2f730cd 100644 --- a/protobuf-codegen/src/gen/rust_types_values.rs +++ b/protobuf-codegen/src/gen/rust_types_values.rs @@ -34,6 +34,7 @@ pub(crate) enum RustType { Bool, Vec(Box), HashMap(Box, Box), + BTreeMap(Box, Box), String, // [T], not &[T] Slice(Box), @@ -75,6 +76,11 @@ impl RustType { key.to_code(customize), value.to_code(customize) ), + RustType::BTreeMap(ref key, ref value) => format!( + "::std::collections::BTreeMap<{}, {}>", + key.to_code(customize), + value.to_code(customize) + ), RustType::String => format!("::std::string::String"), RustType::Slice(ref param) => format!("[{}]", param.to_code(customize)), RustType::Str => format!("str"), @@ -221,6 +227,7 @@ impl RustType { RustType::Bool => "false".to_owned(), RustType::Vec(..) => EXPR_VEC_NEW.to_owned(), RustType::HashMap(..) => "::std::collections::HashMap::new()".to_owned(), + RustType::BTreeMap(..) => "::std::collections::BTreeMap::new()".to_owned(), RustType::String => "::std::string::String::new()".to_owned(), RustType::Bytes => "::bytes::Bytes::new()".to_owned(), RustType::Chars => format!("{}::Chars::new()", protobuf_crate_path(customize)), @@ -266,7 +273,8 @@ impl RustType { | RustType::Chars | RustType::String | RustType::MessageField(..) - | RustType::HashMap(..) => format!("{}.clear()", v), + | RustType::HashMap(..) + | RustType::BTreeMap(..) => format!("{}.clear()", v), RustType::Bool | RustType::Float(..) | RustType::Int(..) diff --git a/protobuf-parse/src/proto/rustproto.proto b/protobuf-parse/src/proto/rustproto.proto index b9ca843c5..e96c3cd63 100644 --- a/protobuf-parse/src/proto/rustproto.proto +++ b/protobuf-parse/src/proto/rustproto.proto @@ -21,6 +21,8 @@ extend google.protobuf.FileOptions { optional bool tokio_bytes_for_string_all = 17012; // When false, `#[non_exhaustive]` is not generated for `oneof` fields. optional bool oneofs_non_exhaustive_all = 17013; + // When true, generate `BTreeMap` instead of `HashMap` for map fields. + optional bool btreemap_all = 17014; // When true, will only generate codes that works with lite runtime. optional bool lite_runtime_all = 17035; @@ -37,6 +39,8 @@ extend google.protobuf.MessageOptions { optional bool tokio_bytes_for_string = 17012; // When false, `#[non_exhaustive]` is not generated for `oneof` fields. optional bool oneofs_non_exhaustive = 17013; + // When true, generate `BTreeMap` instead of `HashMap` for map fields. + optional bool btreemap = 17014; } extend google.protobuf.FieldOptions { @@ -50,4 +54,6 @@ extend google.protobuf.FieldOptions { optional bool tokio_bytes_for_string_field = 17012; // When false, `#[non_exhaustive]` is not generated for `oneof` fields. optional bool oneofs_non_exhaustive_field = 17013; + // When true, generate `BTreeMap` instead of `HashMap` for map fields. + optional bool btreemap_field = 17014; } diff --git a/protobuf/src/rustproto.rs b/protobuf/src/rustproto.rs index 6f161b6d5..a403829d4 100644 --- a/protobuf/src/rustproto.rs +++ b/protobuf/src/rustproto.rs @@ -34,6 +34,8 @@ pub mod exts { pub const oneofs_non_exhaustive_all: crate::ext::ExtFieldOptional = crate::ext::ExtFieldOptional::new(17013, crate::descriptor::field_descriptor_proto::Type::TYPE_BOOL); + pub const btreemap_all: crate::ext::ExtFieldOptional = crate::ext::ExtFieldOptional::new(17014, 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); @@ -46,6 +48,8 @@ pub mod exts { pub const oneofs_non_exhaustive: crate::ext::ExtFieldOptional = crate::ext::ExtFieldOptional::new(17013, crate::descriptor::field_descriptor_proto::Type::TYPE_BOOL); + pub const btreemap: crate::ext::ExtFieldOptional = crate::ext::ExtFieldOptional::new(17014, 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); @@ -55,6 +59,8 @@ pub mod exts { 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 oneofs_non_exhaustive_field: crate::ext::ExtFieldOptional = crate::ext::ExtFieldOptional::new(17013, crate::descriptor::field_descriptor_proto::Type::TYPE_BOOL); + + pub const btreemap_field: crate::ext::ExtFieldOptional = crate::ext::ExtFieldOptional::new(17014, crate::descriptor::field_descriptor_proto::Type::TYPE_BOOL); } static file_descriptor_proto_data: &'static [u8] = b"\ @@ -67,102 +73,120 @@ static file_descriptor_proto_data: &'static [u8] = b"\ tes_for_string_all\x18\xf4\x84\x01\x20\x01(\x08\x12\x1c.google.protobuf.\ FileOptionsR\x16tokioBytesForStringAll:Y\n\x19oneofs_non_exhaustive_all\ \x18\xf5\x84\x01\x20\x01(\x08\x12\x1c.google.protobuf.FileOptionsR\x16on\ - eofsNonExhaustiveAll:H\n\x10lite_runtime_all\x18\x8b\x85\x01\x20\x01(\ - \x08\x12\x1c.google.protobuf.FileOptionsR\x0eliteRuntimeAll:P\n\x12gener\ - ate_accessors\x18\xec\x84\x01\x20\x01(\x08\x12\x1f.google.protobuf.Messa\ - geOptionsR\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.MessageOptionsR\x13tokioBytesF\ - orString:U\n\x15oneofs_non_exhaustive\x18\xf5\x84\x01\x20\x01(\x08\x12\ - \x1f.google.protobuf.MessageOptionsR\x13oneofsNonExhaustive:Y\n\x18gener\ - ate_accessors_field\x18\xec\x84\x01\x20\x01(\x08\x12\x1d.google.protobuf\ - .FieldOptionsR\x16generateAccessorsField:S\n\x15generate_getter_field\ - \x18\xed\x84\x01\x20\x01(\x08\x12\x1d.google.protobuf.FieldOptionsR\x13g\ - enerateGetterField:K\n\x11tokio_bytes_field\x18\xf3\x84\x01\x20\x01(\x08\ - \x12\x1d.google.protobuf.FieldOptionsR\x0ftokioBytesField:_\n\x1ctokio_b\ - ytes_for_string_field\x18\xf4\x84\x01\x20\x01(\x08\x12\x1d.google.protob\ - uf.FieldOptionsR\x18tokioBytesForStringField:^\n\x1boneofs_non_exhaustiv\ - e_field\x18\xf5\x84\x01\x20\x01(\x08\x12\x1d.google.protobuf.FieldOption\ - sR\x18oneofsNonExhaustiveFieldJ\xca\x12\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/m\ - aster/gogoproto/gogo.proto\n\x20for\x20the\x20original\x20idea\n2{\x20Ge\ - nerated\x20files\x20can\x20be\x20customized\x20using\x20this\x20proto\n\ - \x20or\x20using\x20`Customize`\x20struct\x20when\x20codegen\x20is\x20inv\ - oked\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\x20W\ - hen\x20false,\x20`get_`\x20is\x20not\x20generated\x20even\x20if\x20`synt\ - ax\x20=\x20\"proto2\"`\n\n\n\n\x03\x07\x01\x02\x12\x03\x0c\x07\"\n\n\n\ - \x03\x07\x01\x04\x12\x03\x10\x04\x0c\n\n\n\x03\x07\x01\x05\x12\x03\x10\r\ - \x11\n\n\n\x03\x07\x01\x01\x12\x03\x10\x12%\n\n\n\x03\x07\x01\x03\x12\ - \x03\x10(-\n2\n\x02\x07\x02\x12\x03\x12\x04*\x1a'\x20Use\x20`bytes::Byte\ - s`\x20for\x20`bytes`\x20fields\n\n\n\n\x03\x07\x02\x02\x12\x03\x0c\x07\"\ - \n\n\n\x03\x07\x02\x04\x12\x03\x12\x04\x0c\n\n\n\x03\x07\x02\x05\x12\x03\ - \x12\r\x11\n\n\n\x03\x07\x02\x01\x12\x03\x12\x12!\n\n\n\x03\x07\x02\x03\ - \x12\x03\x12$)\n3\n\x02\x07\x03\x12\x03\x14\x045\x1a(\x20Use\x20`bytes::\ - Bytes`\x20for\x20`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\nQ\n\x02\x07\x04\x12\x03\x16\x044\x1aF\x20When\ + eofsNonExhaustiveAll:A\n\x0cbtreemap_all\x18\xf6\x84\x01\x20\x01(\x08\ + \x12\x1c.google.protobuf.FileOptionsR\x0bbtreemapAll:H\n\x10lite_runtime\ + _all\x18\x8b\x85\x01\x20\x01(\x08\x12\x1c.google.protobuf.FileOptionsR\ + \x0eliteRuntimeAll:P\n\x12generate_accessors\x18\xec\x84\x01\x20\x01(\ + \x08\x12\x1f.google.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.p\ + rotobuf.MessageOptionsR\x13tokioBytesForString:U\n\x15oneofs_non_exhaust\ + ive\x18\xf5\x84\x01\x20\x01(\x08\x12\x1f.google.protobuf.MessageOptionsR\ + \x13oneofsNonExhaustive:=\n\x08btreemap\x18\xf6\x84\x01\x20\x01(\x08\x12\ + \x1f.google.protobuf.MessageOptionsR\x08btreemap:Y\n\x18generate_accesso\ + rs_field\x18\xec\x84\x01\x20\x01(\x08\x12\x1d.google.protobuf.FieldOptio\ + nsR\x16generateAccessorsField:S\n\x15generate_getter_field\x18\xed\x84\ + \x01\x20\x01(\x08\x12\x1d.google.protobuf.FieldOptionsR\x13generateGette\ + rField:K\n\x11tokio_bytes_field\x18\xf3\x84\x01\x20\x01(\x08\x12\x1d.goo\ + gle.protobuf.FieldOptionsR\x0ftokioBytesField:_\n\x1ctokio_bytes_for_str\ + ing_field\x18\xf4\x84\x01\x20\x01(\x08\x12\x1d.google.protobuf.FieldOpti\ + onsR\x18tokioBytesForStringField:^\n\x1boneofs_non_exhaustive_field\x18\ + \xf5\x84\x01\x20\x01(\x08\x12\x1d.google.protobuf.FieldOptionsR\x18oneof\ + sNonExhaustiveField:F\n\x0ebtreemap_field\x18\xf6\x84\x01\x20\x01(\x08\ + \x12\x1d.google.protobuf.FieldOptionsR\rbtreemapFieldJ\xf4\x15\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.c\ + om/gogo/protobuf/blob/master/gogoproto/gogo.proto\n\x20for\x20the\x20ori\ + ginal\x20idea\n2{\x20Generated\x20files\x20can\x20be\x20customized\x20us\ + ing\x20this\x20proto\n\x20or\x20using\x20`Customize`\x20struct\x20when\ + \x20codegen\x20is\x20invoked\x20programmatically.\n\n\t\n\x01\x07\x12\ + \x04\x0c\0\x1c\x01\nP\n\x02\x07\0\x12\x03\x0e\x041\x1aE\x20When\x20false\ + ,\x20`get_`,\x20`set_`,\x20`mut_`\x20etc.\x20accessors\x20are\x20not\x20\ + generated\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\x20g\ + enerated\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\x10\x04\x0c\n\n\ + \n\x03\x07\x01\x05\x12\x03\x10\r\x11\n\n\n\x03\x07\x01\x01\x12\x03\x10\ + \x12%\n\n\n\x03\x07\x01\x03\x12\x03\x10(-\n2\n\x02\x07\x02\x12\x03\x12\ + \x04*\x1a'\x20Use\x20`bytes::Bytes`\x20for\x20`bytes`\x20fields\n\n\n\n\ + \x03\x07\x02\x02\x12\x03\x0c\x07\"\n\n\n\x03\x07\x02\x04\x12\x03\x12\x04\ + \x0c\n\n\n\x03\x07\x02\x05\x12\x03\x12\r\x11\n\n\n\x03\x07\x02\x01\x12\ + \x03\x12\x12!\n\n\n\x03\x07\x02\x03\x12\x03\x12$)\n3\n\x02\x07\x03\x12\ + \x03\x14\x045\x1a(\x20Use\x20`bytes::Bytes`\x20for\x20`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\nQ\n\x02\x07\ + \x04\x12\x03\x16\x044\x1aF\x20When\x20false,\x20`#[non_exhaustive]`\x20i\ + s\x20not\x20generated\x20for\x20`oneof`\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.3\nP\n\x02\x07\x05\x12\x03\x18\x04'\ + \x1aE\x20When\x20true,\x20generate\x20`BTreeMap`\x20instead\x20of\x20`Ha\ + shMap`\x20for\x20map\x20fields.\n\n\n\n\x03\x07\x05\x02\x12\x03\x0c\x07\ + \"\n\n\n\x03\x07\x05\x04\x12\x03\x18\x04\x0c\n\n\n\x03\x07\x05\x05\x12\ + \x03\x18\r\x11\n\n\n\x03\x07\x05\x01\x12\x03\x18\x12\x1e\n\n\n\x03\x07\ + \x05\x03\x12\x03\x18!&\nN\n\x02\x07\x06\x12\x03\x1b\x04+\x1aC\x20When\ + \x20true,\x20will\x20only\x20generate\x20codes\x20that\x20works\x20with\ + \x20lite\x20runtime.\n\n\n\n\x03\x07\x06\x02\x12\x03\x0c\x07\"\n\n\n\x03\ + \x07\x06\x04\x12\x03\x1b\x04\x0c\n\n\n\x03\x07\x06\x05\x12\x03\x1b\r\x11\ + \n\n\n\x03\x07\x06\x01\x12\x03\x1b\x12\"\n\n\n\x03\x07\x06\x03\x12\x03\ + \x1b%*\n\t\n\x01\x07\x12\x04\x1e\0+\x01\nP\n\x02\x07\x07\x12\x03\x20\x04\ + -\x1aE\x20When\x20false,\x20`get_`,\x20`set_`,\x20`mut_`\x20etc.\x20acce\ + ssors\x20are\x20not\x20generated\n\n\n\n\x03\x07\x07\x02\x12\x03\x1e\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',\nL\n\x02\x07\x08\x12\x03\"\x04*\x1aA\x20When\x20false\ + ,\x20`get_`\x20is\x20not\x20generated\x20even\x20if\x20`syntax\x20=\x20\ + \"proto2\"`\n\n\n\n\x03\x07\x08\x02\x12\x03\x1e\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\"$)\n2\n\x02\ + \x07\t\x12\x03$\x04&\x1a'\x20Use\x20`bytes::Bytes`\x20for\x20`bytes`\x20\ + fields\n\n\n\n\x03\x07\t\x02\x12\x03\x1e\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\x1d\n\n\n\x03\x07\t\x03\x12\x03$\x20%\n3\n\x02\x07\n\x12\x03&\ + \x041\x1a(\x20Use\x20`bytes::Bytes`\x20for\x20`string`\x20fields\n\n\n\n\ + \x03\x07\n\x02\x12\x03\x1e\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&+0\nQ\n\x02\x07\x0b\x12\x03(\x040\x1aF\x20When\ \x20false,\x20`#[non_exhaustive]`\x20is\x20not\x20generated\x20for\x20`o\ - neof`\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.3\ - \nN\n\x02\x07\x05\x12\x03\x19\x04+\x1aC\x20When\x20true,\x20will\x20only\ - \x20generate\x20codes\x20that\x20works\x20with\x20lite\x20runtime.\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\x20g\ - enerated\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\x20\ - not\x20generated\x20even\x20if\x20`syntax\x20=\x20\"proto2\"`\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`\x20fields\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`\x20fields\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\nQ\n\x02\x07\n\x12\x03&\x040\x1aF\x20Wh\ - en\x20false,\x20`#[non_exhaustive]`\x20is\x20not\x20generated\x20for\x20\ - `oneof`\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`g\ - et_`,\x20`set_`,\x20`mut_`\x20etc.\x20accessors\x20are\x20not\x20generat\ - ed\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`get_`\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`bytes::Bytes`\x20for\x20`string`\x20f\ - ields\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\nQ\n\x02\x07\x0f\x12\x03\ - 3\x046\x1aF\x20When\x20false,\x20`#[non_exhaustive]`\x20is\x20not\x20gen\ - erated\x20for\x20`oneof`\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\x03\ - 305\ + neof`\x20fields.\n\n\n\n\x03\x07\x0b\x02\x12\x03\x1e\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(*/\nP\n\x02\x07\ + \x0c\x12\x03*\x04#\x1aE\x20When\x20true,\x20generate\x20`BTreeMap`\x20in\ + stead\x20of\x20`HashMap`\x20for\x20map\x20fields.\n\n\n\n\x03\x07\x0c\ + \x02\x12\x03\x1e\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\x1a\n\n\n\ + \x03\x07\x0c\x03\x12\x03*\x1d\"\n\t\n\x01\x07\x12\x04-\0:\x01\nP\n\x02\ + \x07\r\x12\x03/\x043\x1aE\x20When\x20false,\x20`get_`,\x20`set_`,\x20`mu\ + t_`\x20etc.\x20accessors\x20are\x20not\x20generated\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/-2\nL\n\x02\x07\x0e\x12\x031\x040\x1aA\x20When\x20false,\ + \x20`get_`\x20is\x20not\x20generated\x20even\x20if\x20`syntax\x20=\x20\"\ + proto2\"`\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\x031*/\n2\n\x02\x07\x0f\x12\ + \x033\x04,\x1a'\x20Use\x20`bytes::Bytes`\x20for\x20`bytes`\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&+\n3\n\x02\x07\x10\x12\x035\x047\ + \x1a(\x20Use\x20`bytes::Bytes`\x20for\x20`string`\x20fields\n\n\n\n\x03\ + \x07\x10\x02\x12\x03-\x07#\n\n\n\x03\x07\x10\x04\x12\x035\x04\x0c\n\n\n\ + \x03\x07\x10\x05\x12\x035\r\x11\n\n\n\x03\x07\x10\x01\x12\x035\x12.\n\n\ + \n\x03\x07\x10\x03\x12\x03516\nQ\n\x02\x07\x11\x12\x037\x046\x1aF\x20Whe\ + n\x20false,\x20`#[non_exhaustive]`\x20is\x20not\x20generated\x20for\x20`\ + oneof`\x20fields.\n\n\n\n\x03\x07\x11\x02\x12\x03-\x07#\n\n\n\x03\x07\ + \x11\x04\x12\x037\x04\x0c\n\n\n\x03\x07\x11\x05\x12\x037\r\x11\n\n\n\x03\ + \x07\x11\x01\x12\x037\x12-\n\n\n\x03\x07\x11\x03\x12\x03705\nP\n\x02\x07\ + \x12\x12\x039\x04)\x1aE\x20When\x20true,\x20generate\x20`BTreeMap`\x20in\ + stead\x20of\x20`HashMap`\x20for\x20map\x20fields.\n\n\n\n\x03\x07\x12\ + \x02\x12\x03-\x07#\n\n\n\x03\x07\x12\x04\x12\x039\x04\x0c\n\n\n\x03\x07\ + \x12\x05\x12\x039\r\x11\n\n\n\x03\x07\x12\x01\x12\x039\x12\x20\n\n\n\x03\ + \x07\x12\x03\x12\x039#(\ "; /// `FileDescriptorProto` object which was a source for this generated file diff --git a/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_map_simple.rs b/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_map_simple.rs index 5c7c901df..e0774954e 100644 --- a/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_map_simple.rs +++ b/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_map_simple.rs @@ -21,6 +21,24 @@ fn test_map() { test_serialize_deserialize_no_hex_with_dynamic(&map); } +#[test] +fn test_map_btree_map() { + let mut map = TestMapBTreeMap::new(); + let mut entry = TestMapEntry::new(); + entry.set_v(10); + + test_serialize_deserialize_with_dynamic("", &map); + + map.mut_m().insert("two".to_owned(), 2); + test_serialize_deserialize_with_dynamic("0a 07 0a 03 74 77 6f 10 02", &map); + + map.mut_m().insert("sixty six".to_owned(), 66); + // Insert map entry sub message + map.mut_mm().insert("map".to_owned(), entry); + // cannot (easily) test hex, because order is not specified + test_serialize_deserialize_no_hex_with_dynamic(&map); +} + #[test] fn test_map_negative_i32_value() { let mut map = TestMap::new(); diff --git a/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_map_simple_pb.proto b/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_map_simple_pb.proto index 2cdca3550..ccbf81032 100644 --- a/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_map_simple_pb.proto +++ b/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_map_simple_pb.proto @@ -13,6 +13,14 @@ message TestMap { map me = 3; } +message TestMapBTreeMap { + map m = 1; + map mm = 2; + // just check it compiles + map me = 3; + option (rustproto.btreemap) = true; +} + message TestMapEntry { optional int64 v = 1; } diff --git a/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_reflect_clear.rs b/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_reflect_clear.rs index 2e0affafa..971048655 100644 --- a/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_reflect_clear.rs +++ b/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_reflect_clear.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use protobuf::reflect::ReflectValueBox; use protobuf::MessageFull; @@ -7,7 +5,7 @@ use super::test_reflect_clear_pb::*; #[test] fn test_generated() { - let mut map = HashMap::new(); + let mut map = TestMessage::default().e().clone(); map.insert("key".to_string(), "value".to_string()); let mut msg = TestMessage::default(); @@ -45,7 +43,7 @@ fn test_dynamic() { let mut msg = msg_desc.new_instance(); - let mut map = HashMap::new(); + let mut map = TestMessage::default().e().clone(); map.insert("key".to_string(), "value".to_string()); a_field.set_singular_field(msg.as_mut(), 1.into()); diff --git a/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_reflect_map.rs b/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_reflect_map.rs index 25d48ab1d..7cb68dd16 100644 --- a/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_reflect_map.rs +++ b/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_reflect_map.rs @@ -1,11 +1,18 @@ +use std::collections::BTreeMap; +use std::collections::HashMap; + use protobuf::reflect::ReflectValueBox; use protobuf::MessageFull; use super::test_reflect_map_pb::TestMap; +use super::test_reflect_map_pb::TestMapBTreeMap; #[test] fn test_map() { let mut message = TestMap::new(); + // Check generated field type. + let _: &HashMap = &message.map_string_string; + message .map_string_string .insert("foo".to_owned(), "bar".to_owned()); @@ -29,3 +36,33 @@ fn test_map() { assert!(TestMap::descriptor().eq(&message, &*reflect_message)); } + +#[test] +fn test_map_btree_map() { + let mut message = TestMapBTreeMap::new(); + // Check generated field type. + let _: &BTreeMap = &message.map_string_string; + + message + .map_string_string + .insert("foo".to_owned(), "bar".to_owned()); + message.map_int32_bool.insert(1, true); + + let map_string_string = TestMapBTreeMap::descriptor() + .field_by_name("map_string_string") + .unwrap(); + let map_int32_bool = TestMapBTreeMap::descriptor() + .field_by_name("map_int32_bool") + .unwrap(); + + let mut reflect_message = TestMapBTreeMap::descriptor().new_instance(); + map_string_string.mut_map(&mut *reflect_message).insert( + ReflectValueBox::String("foo".to_owned()), + ReflectValueBox::String("bar".to_owned()), + ); + map_int32_bool + .mut_map(&mut *reflect_message) + .insert(ReflectValueBox::I32(1), ReflectValueBox::Bool(true)); + + assert!(TestMapBTreeMap::descriptor().eq(&message, &*reflect_message)); +} diff --git a/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_reflect_map_pb.proto b/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_reflect_map_pb.proto index 45e40b95d..927b76870 100644 --- a/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_reflect_map_pb.proto +++ b/test-crates/protobuf-codegen-protoc-test/src/common/v2/test_reflect_map_pb.proto @@ -7,3 +7,9 @@ message TestMap { map map_string_string = 1; map map_int32_bool = 2; } + +message TestMapBTreeMap { + map map_string_string = 1; + map map_int32_bool = 2; + option (rustproto.btreemap) = true; +}