From e0337ad29ebe24d29711d21efff5bfb33149c143 Mon Sep 17 00:00:00 2001 From: Runze Wang Date: Fri, 24 Jul 2026 13:49:32 -0700 Subject: [PATCH] Inline hot methods on Map and in generated code These methods are one-to-three line wrappers delegating to underlying map implementations (upb/cpp_kernel). Without `#[inline]`, the compiler will not cross crate boundaries, resulting in many physical function call overheads for otherwise fully optimal code in hot loops on Map values. PiperOrigin-RevId: 953537646 --- rust/map.rs | 20 +++++++++++++++++++ .../protobuf/compiler/rust/accessors/map.cc | 6 ++++++ 2 files changed, 26 insertions(+) diff --git a/rust/map.rs b/rust/map.rs index 84c9400796..a9cc8b4eaf 100644 --- a/rust/map.rs +++ b/rust/map.rs @@ -87,24 +87,29 @@ unsafe impl Send for Map {} impl SealedInternal for Map {} impl Map { + #[inline] pub fn new() -> Self { V::map_new(Private) } + #[inline] pub fn as_mut(&mut self) -> MapMut<'_, K, V> { MapMut { inner: self.inner.as_mut(), _phantom: PhantomData } } + #[inline] pub fn as_view(&self) -> MapView<'_, K, V> { MapView { raw: self.inner.raw, _phantom: PhantomData } } #[doc(hidden)] + #[inline] pub fn from_inner(_: Private, inner: InnerMap) -> Self { Self { inner, _phantom: PhantomData } } #[doc(hidden)] + #[inline] pub fn as_raw(&self, _: Private) -> RawMap { self.inner.raw } @@ -210,6 +215,7 @@ impl<'msg, K: ?Sized, V: ?Sized> MapView<'msg, K, V> { } impl<'msg, K: MapKey, V: MapValue> MapView<'msg, K, V> { + #[inline] pub fn get<'a>(self, key: impl Into>) -> Option> where K: 'a, @@ -217,14 +223,17 @@ impl<'msg, K: MapKey, V: MapValue> MapView<'msg, K, V> { V::map_get(Private, self, key.into()) } + #[inline] pub fn len(self) -> usize { V::map_len(Private, self) } + #[inline] pub fn is_empty(self) -> bool { self.len() == 0 } + #[inline] pub fn contains_key<'a>(self, key: impl Into>) -> bool where K: 'a, @@ -361,14 +370,17 @@ impl<'msg, K: ?Sized, V: ?Sized> MapMut<'msg, K, V> { } impl<'msg, K: MapKey, V: MapValue> MapMut<'msg, K, V> { + #[inline] pub fn len(&self) -> usize { self.as_view().len() } + #[inline] pub fn is_empty(&self) -> bool { self.len() == 0 } + #[inline] pub fn contains_key<'a>(&self, key: impl Into>) -> bool where K: 'a, @@ -379,22 +391,27 @@ impl<'msg, K: MapKey, V: MapValue> MapMut<'msg, K, V> { /// Adds a key-value pair to the map. /// /// Returns `true` if the entry was newly inserted. + #[inline] pub fn insert<'a>(&mut self, key: impl Into>, value: impl IntoProxied) -> bool { V::map_insert(Private, self.as_mut(), key.into(), value) } + #[inline] pub fn remove<'a>(&mut self, key: impl Into>) -> bool { V::map_remove(Private, self.as_mut(), key.into()) } + #[inline] pub fn clear(&mut self) { V::map_clear(Private, self.as_mut()) } + #[inline] pub fn get<'a>(&self, key: impl Into>) -> Option> { V::map_get(Private, self.as_view(), key.into()) } + #[inline] pub fn get_mut<'a>(&mut self, key: impl Into>) -> Option> where V: Message, @@ -416,6 +433,7 @@ impl<'msg, K: MapKey, V: MapValue> MapMut<'msg, K, V> { /// Returns an iterator visiting all key-value pairs in arbitrary order. /// /// The iterator element type is `(View, View)`. + #[inline] pub fn iter(&self) -> MapIter<'_, K, V> { self.into_iter() } @@ -423,6 +441,7 @@ impl<'msg, K: MapKey, V: MapValue> MapMut<'msg, K, V> { /// Returns an iterator visiting all keys in arbitrary order. /// /// The iterator element type is `View`. + #[inline] pub fn keys(&self) -> impl Iterator> + '_ { self.as_view().keys() } @@ -430,6 +449,7 @@ impl<'msg, K: MapKey, V: MapValue> MapMut<'msg, K, V> { /// Returns an iterator visiting all values in arbitrary order. /// /// The iterator element type is `View`. + #[inline] pub fn values(&self) -> impl Iterator> + '_ { self.as_view().values() } diff --git a/src/google/protobuf/compiler/rust/accessors/map.cc b/src/google/protobuf/compiler/rust/accessors/map.cc index ec36d46281..7d8d8a7a76 100644 --- a/src/google/protobuf/compiler/rust/accessors/map.cc +++ b/src/google/protobuf/compiler/rust/accessors/map.cc @@ -55,6 +55,7 @@ void Map::InMsgImpl(Context& ctx, const FieldDescriptor& field, [&] { if (ctx.is_upb()) { ctx.Emit(R"rs( + #[inline] pub fn $field$($view_self$) -> $pb$::MapView<$view_lifetime$, $Key$, $Value$> { unsafe { @@ -68,6 +69,7 @@ void Map::InMsgImpl(Context& ctx, const FieldDescriptor& field, })rs"); } else { ctx.Emit({{"getter_thunk", ThunkName(ctx, field, "get")}}, R"rs( + #[inline] pub fn $field$($view_self$) -> $pb$::MapView<$view_lifetime$, $Key$, $Value$> { unsafe { @@ -84,6 +86,7 @@ void Map::InMsgImpl(Context& ctx, const FieldDescriptor& field, } if (ctx.is_upb()) { ctx.Emit({}, R"rs( + #[inline] pub fn $field$_mut(&mut self) -> $pb$::MapMut<'_, $Key$, $Value$> { unsafe { @@ -98,6 +101,7 @@ void Map::InMsgImpl(Context& ctx, const FieldDescriptor& field, } else { ctx.Emit({{"getter_mut_thunk", ThunkName(ctx, field, "get_mut")}}, R"rs( + #[inline] pub fn $field$_mut(&mut self) -> $pb$::MapMut<'_, $Key$, $Value$> { let inner = $pbr$::InnerMapMut::new( @@ -113,6 +117,7 @@ void Map::InMsgImpl(Context& ctx, const FieldDescriptor& field, } if (ctx.is_upb()) { ctx.Emit({}, R"rs( + #[inline] pub fn set_$raw_field_name$( &mut self, src: impl $pb$::IntoProxied<$pb$::Map<$Key$, $Value$>>) { @@ -127,6 +132,7 @@ void Map::InMsgImpl(Context& ctx, const FieldDescriptor& field, } else { ctx.Emit({{"move_setter_thunk", ThunkName(ctx, field, "set")}}, R"rs( + #[inline] pub fn set_$raw_field_name$( &mut self, src: impl $pb$::IntoProxied<$pb$::Map<$Key$, $Value$>>) {