This CL implements msg.<field>() and msg.<field_mut>() accessors for maps with primitive-typed keys and values for the UPB kernel only.
Support for the CPP runtime and non-scalar value types will be implemented in follow up CLs. PiperOrigin-RevId: 580453646pull/14684/head
parent
15eccf3ec4
commit
ac3f553073
14 changed files with 533 additions and 23 deletions
@ -0,0 +1,77 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google LLC. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
use crate::{ |
||||
__internal::Private, |
||||
__runtime::{Map, MapInner, MapValueType}, |
||||
}; |
||||
|
||||
#[derive(Clone, Copy)] |
||||
#[repr(transparent)] |
||||
pub struct MapView<'a, K: ?Sized, V: ?Sized> { |
||||
inner: Map<'a, K, V>, |
||||
} |
||||
|
||||
#[derive(Clone, Copy)] |
||||
#[repr(transparent)] |
||||
pub struct MapMut<'a, K: ?Sized, V: ?Sized> { |
||||
inner: Map<'a, K, V>, |
||||
} |
||||
|
||||
impl<'a, K: ?Sized, V: ?Sized> MapView<'a, K, V> { |
||||
pub fn from_inner(_private: Private, inner: MapInner<'a>) -> Self { |
||||
Self { inner: Map::<'a, K, V>::from_inner(_private, inner) } |
||||
} |
||||
|
||||
pub fn len(&self) -> usize { |
||||
self.inner.len() |
||||
} |
||||
|
||||
pub fn is_empty(&self) -> bool { |
||||
self.len() == 0 |
||||
} |
||||
} |
||||
|
||||
impl<'a, K: ?Sized, V: ?Sized> MapMut<'a, K, V> { |
||||
pub fn from_inner(_private: Private, inner: MapInner<'a>) -> Self { |
||||
Self { inner: Map::<'a, K, V>::from_inner(_private, inner) } |
||||
} |
||||
} |
||||
|
||||
macro_rules! impl_scalar_map_keys { |
||||
($(key_type $type:ty;)*) => { |
||||
$( |
||||
impl<'a, V: MapValueType> MapView<'a, $type, V> { |
||||
pub fn get(&self, key: $type) -> Option<V> { |
||||
self.inner.get(key) |
||||
} |
||||
} |
||||
|
||||
impl<'a, V: MapValueType> MapMut<'a, $type, V> { |
||||
pub fn insert(&mut self, key: $type, value: V) -> bool { |
||||
self.inner.insert(key, value) |
||||
} |
||||
|
||||
pub fn remove(&mut self, key: $type) -> Option<V> { |
||||
self.inner.remove(key) |
||||
} |
||||
|
||||
pub fn clear(&mut self) { |
||||
self.inner.clear() |
||||
} |
||||
} |
||||
)* |
||||
}; |
||||
} |
||||
|
||||
impl_scalar_map_keys!( |
||||
key_type i32; |
||||
key_type u32; |
||||
key_type i64; |
||||
key_type u64; |
||||
key_type bool; |
||||
); |
@ -0,0 +1,43 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google LLC. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
use googletest::prelude::*; |
||||
use map_unittest_proto::proto2_unittest::TestMap; |
||||
use paste::paste; |
||||
|
||||
macro_rules! generate_map_primitives_tests { |
||||
( |
||||
$(($k_type:ty, $v_type:ty, $k_field:ident, $v_field:ident)),* |
||||
) => { |
||||
paste! { $( |
||||
#[test] |
||||
fn [< test_map_ $k_field _ $v_field >]() { |
||||
let mut msg = TestMap::new(); |
||||
let k: $k_type = Default::default(); |
||||
let v: $v_type = Default::default(); |
||||
assert_that!(msg.[< map_ $k_field _ $v_field _mut>]().insert(k, v), eq(true)); |
||||
assert_that!(msg.[< map_ $k_field _ $v_field >]().len(), eq(1)); |
||||
} |
||||
)* } |
||||
}; |
||||
} |
||||
|
||||
generate_map_primitives_tests!( |
||||
(i32, i32, int32, int32), |
||||
(i64, i64, int64, int64), |
||||
(u32, u32, uint32, uint32), |
||||
(u64, u64, uint64, uint64), |
||||
(i32, i32, sint32, sint32), |
||||
(i64, i64, sint64, sint64), |
||||
(u32, u32, fixed32, fixed32), |
||||
(u64, u64, fixed64, fixed64), |
||||
(i32, i32, sfixed32, sfixed32), |
||||
(i64, i64, sfixed64, sfixed64), |
||||
(i32, f32, int32, float), |
||||
(i32, f64, int32, double), |
||||
(bool, bool, bool, bool) |
||||
); |
@ -0,0 +1,82 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google LLC. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#include "google/protobuf/compiler/rust/accessors/accessor_generator.h" |
||||
#include "google/protobuf/compiler/rust/context.h" |
||||
#include "google/protobuf/compiler/rust/naming.h" |
||||
#include "google/protobuf/descriptor.h" |
||||
#include "google/protobuf/descriptor.pb.h" |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace rust { |
||||
|
||||
void Map::InMsgImpl(Context<FieldDescriptor> field) const { |
||||
auto& key_type = *field.desc().message_type()->map_key(); |
||||
auto& value_type = *field.desc().message_type()->map_value(); |
||||
|
||||
field.Emit({{"field", field.desc().name()}, |
||||
{"Key", PrimitiveRsTypeName(key_type)}, |
||||
{"Value", PrimitiveRsTypeName(value_type)}, |
||||
{"getter_thunk", Thunk(field, "get")}, |
||||
{"getter_thunk_mut", Thunk(field, "get_mut")}, |
||||
{"getter", |
||||
[&] { |
||||
if (field.is_upb()) { |
||||
field.Emit({}, R"rs( |
||||
pub fn r#$field$(&self) -> $pb$::MapView<'_, $Key$, $Value$> { |
||||
let inner = unsafe { |
||||
$getter_thunk$(self.inner.msg) |
||||
}.map_or_else(|| unsafe {$pbr$::empty_map()}, |raw| { |
||||
$pbr$::MapInner{ raw, arena: &self.inner.arena } |
||||
}); |
||||
$pb$::MapView::from_inner($pbi$::Private, inner) |
||||
} |
||||
|
||||
pub fn r#$field$_mut(&mut self)
|
||||
-> $pb$::MapMut<'_, $Key$, $Value$> { |
||||
let raw = unsafe { |
||||
$getter_thunk_mut$(self.inner.msg, self.inner.arena.raw()) |
||||
}; |
||||
let inner = $pbr$::MapInner{ raw, arena: &self.inner.arena }; |
||||
$pb$::MapMut::from_inner($pbi$::Private, inner) |
||||
} |
||||
)rs"); |
||||
} |
||||
}}}, |
||||
R"rs( |
||||
$getter$ |
||||
)rs"); |
||||
} |
||||
|
||||
void Map::InExternC(Context<FieldDescriptor> field) const { |
||||
field.Emit( |
||||
{ |
||||
{"getter_thunk", Thunk(field, "get")}, |
||||
{"getter_thunk_mut", Thunk(field, "get_mut")}, |
||||
{"getter", |
||||
[&] { |
||||
if (field.is_upb()) { |
||||
field.Emit({}, R"rs( |
||||
fn $getter_thunk$(raw_msg: $pbi$::RawMessage)
|
||||
-> Option<$pbi$::RawMap>; |
||||
fn $getter_thunk_mut$(raw_msg: $pbi$::RawMessage, |
||||
arena: $pbi$::RawArena) -> $pbi$::RawMap; |
||||
)rs"); |
||||
} |
||||
}}, |
||||
}, |
||||
R"rs( |
||||
$getter$ |
||||
)rs"); |
||||
} |
||||
|
||||
} // namespace rust
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
Loading…
Reference in new issue