mirror of
https://github.com/protocolbuffers/protobuf
synced 2026-08-26 02:23:14 -04:00
This is just a slightly more Rust idiomatic way of being clear that you are knowingly using unsafe to soundly extend a lifetime. PiperOrigin-RevId: 926763735
416 lines
14 KiB
Rust
416 lines
14 KiB
Rust
// Protocol Buffers - Google's data interchange format
|
|
// Copyright 2026 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 super::*;
|
|
use crate::__internal::entity_tag::*;
|
|
use crate::__internal::{EntityType, Enum, Private, Singular};
|
|
use crate::extension::{ExtAccess, ExtClear, ExtGetMut, ExtHas};
|
|
use crate::{ExtensionId, IntoMut, IntoView, MessageViewInterop, Proxied};
|
|
use std::sync::LazyLock;
|
|
|
|
pub struct InnerExtensionId {
|
|
mini_table: &'static LazyLock<MiniTableExtensionInitPtr>,
|
|
}
|
|
|
|
impl InnerExtensionId {
|
|
pub const fn new(mini_table: &'static LazyLock<MiniTableExtensionInitPtr>) -> Self {
|
|
Self { mini_table }
|
|
}
|
|
|
|
pub fn mini_table(&self) -> RawMiniTableExtension {
|
|
self.mini_table.0
|
|
}
|
|
}
|
|
|
|
#[linkme::distributed_slice]
|
|
pub static EXTENSIONS: [LazyLock<MiniTableExtensionInitPtr>];
|
|
|
|
#[cfg(all(target_family = "unix", not(target_os = "macos")))]
|
|
core::arch::global_asm!(
|
|
r#"
|
|
.section linkme_EXTENSIONS,"awR",@progbits
|
|
.globl LINKME_SENTINEL_EXTENSIONS
|
|
LINKME_SENTINEL_EXTENSIONS:
|
|
.size LINKME_SENTINEL_EXTENSIONS, 0
|
|
|
|
.section linkm2_EXTENSIONS,"awR",@progbits
|
|
.globl LINKM2_SENTINEL_EXTENSIONS
|
|
LINKM2_SENTINEL_EXTENSIONS:
|
|
.size LINKM2_SENTINEL_EXTENSIONS, 0
|
|
"#
|
|
);
|
|
|
|
pub fn generated_extension_registry() -> RawExtensionRegistry {
|
|
static EXTENSIONS_REGISTRY: LazyLock<ExtensionRegistryInitPtr> = LazyLock::new(|| unsafe {
|
|
let registry = upb_ExtensionRegistry_New(THREAD_LOCAL_ARENA.with(|a| a.raw()));
|
|
for extension in EXTENSIONS {
|
|
upb_ExtensionRegistry_Add(registry, extension.0);
|
|
}
|
|
ExtensionRegistryInitPtr(registry)
|
|
});
|
|
EXTENSIONS_REGISTRY.0
|
|
}
|
|
|
|
impl<Msg: Message, T: Singular> ExtHas<Msg> for ExtensionId<Msg, T> {
|
|
fn has(&self, _private: Private, msg: impl AsView<Proxied = Msg>) -> bool {
|
|
// SAFETY:
|
|
// - `msg` is a valid message.
|
|
// - `mini_table` is the one associated with `self`.
|
|
unsafe {
|
|
upb_Message_HasExtension(
|
|
msg.as_view().get_ptr(Private).raw(),
|
|
self.inner.mini_table().as_ptr(),
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<Extendee: Message, V: Message> ExtAccess<Extendee, V, MessageTag>
|
|
for ExtensionId<Extendee, V>
|
|
{
|
|
fn get<'msg>(
|
|
&self,
|
|
_private: Private,
|
|
msg: impl IntoView<'msg, Proxied = Extendee>,
|
|
) -> View<'msg, V> {
|
|
let msg = msg.into_view();
|
|
let default_instance = <V as Proxied>::View::default();
|
|
let raw_msg = unsafe {
|
|
upb_Message_GetExtensionMessage(
|
|
msg.get_ptr(Private).raw(),
|
|
self.inner.mini_table().as_ptr(),
|
|
default_instance.get_ptr(Private).raw(),
|
|
)
|
|
};
|
|
unsafe {
|
|
<View<'msg, V>>::__unstable_wrap_raw_message_unchecked_lifetime(
|
|
raw_msg.as_ptr() as *const std::ffi::c_void
|
|
)
|
|
}
|
|
}
|
|
|
|
fn set(
|
|
&self,
|
|
_private: Private,
|
|
mut msg: impl AsMut<MutProxied = Extendee>,
|
|
value: impl IntoProxied<V>,
|
|
) {
|
|
let mut msg_mut = msg.as_mut();
|
|
|
|
let mut child = value.into_proxied(Private);
|
|
let child_ptr = child.get_ptr_mut(Private);
|
|
|
|
// Ensure child arena is fused into parent message
|
|
msg_mut.get_arena(Private).fuse(child.get_arena(Private));
|
|
|
|
unsafe {
|
|
assert!(upb_Message_SetExtensionMessage(
|
|
msg_mut.get_ptr_mut(Private).raw(),
|
|
self.inner.mini_table().as_ptr(),
|
|
child_ptr.raw(),
|
|
msg_mut.get_arena(Private).raw(),
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<Extendee: Message, V: Message> ExtGetMut<Extendee, V, MessageTag>
|
|
for ExtensionId<Extendee, V>
|
|
{
|
|
fn get_mut<'msg>(
|
|
&self,
|
|
_private: Private,
|
|
msg: impl IntoMut<'msg, MutProxied = Extendee>,
|
|
) -> Mut<'msg, V> {
|
|
let mut msg = msg.into_mut();
|
|
unsafe {
|
|
// SAFETY: The arena associated with a `Mut<'msg, _>` proxy lives for at least `'msg`.
|
|
// `UpbGetArena::get_arena` returns an `&Arena` tied to the local borrow of `msg`,
|
|
// but we can safely extend it back to `'msg` here because `msg` holds an `&'msg Arena`.
|
|
let arena_ref: &'msg Arena = &*(msg.get_arena(Private) as *const Arena);
|
|
|
|
// TODO: upb should have a GetOrCreateExtension operation instead of this dance.
|
|
let raw_msg = match upb_Message_HasExtension(
|
|
msg.get_ptr_mut(Private).raw(),
|
|
self.inner.mini_table().as_ptr(),
|
|
) {
|
|
true => {
|
|
upb_Message_GetExtensionMessage(
|
|
msg.get_ptr_mut(Private).raw(),
|
|
self.inner.mini_table().as_ptr(),
|
|
NonNull::dangling(), // Not used.
|
|
)
|
|
}
|
|
false => {
|
|
let raw_msg =
|
|
MessagePtr::<V>::new(arena_ref).expect("alloc should never fail").raw();
|
|
upb_Message_SetExtensionMessage(
|
|
msg.get_ptr_mut(Private).raw(),
|
|
self.inner.mini_table().as_ptr(),
|
|
raw_msg,
|
|
arena_ref.raw(),
|
|
);
|
|
raw_msg
|
|
}
|
|
};
|
|
V::from_message_mut(raw_msg, arena_ref)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<Extendee: Message, V: Singular> ExtAccess<Extendee, Repeated<V>, RepeatedTag>
|
|
for ExtensionId<Extendee, Repeated<V>>
|
|
where
|
|
V: EntityType + UpbTypeConversions<V::Tag>,
|
|
{
|
|
fn get<'msg>(
|
|
&self,
|
|
_private: Private,
|
|
msg: impl IntoView<'msg, Proxied = Extendee>,
|
|
) -> View<'msg, Repeated<V>> {
|
|
let msg = msg.into_view();
|
|
let raw_array = unsafe {
|
|
upb_Message_GetExtensionArray(
|
|
msg.get_ptr(Private).raw(),
|
|
self.inner.mini_table().as_ptr(),
|
|
)
|
|
};
|
|
unsafe {
|
|
IntoView::into_view(
|
|
raw_array.map_or_else(empty_array::<V>, |raw| RepeatedView::from_raw(Private, raw)),
|
|
)
|
|
}
|
|
}
|
|
|
|
fn set(
|
|
&self,
|
|
_private: Private,
|
|
mut msg: impl AsMut<MutProxied = Extendee>,
|
|
value: impl IntoProxied<Repeated<V>>,
|
|
) {
|
|
let value = value.into_proxied(Private);
|
|
let mut ext_mut = self.get_mut(msg.as_mut());
|
|
ext_mut.clear();
|
|
ext_mut.copy_from(unsafe { RepeatedView::from_raw(Private, value.inner(Private).raw()) });
|
|
}
|
|
}
|
|
|
|
impl<Extendee: Message, V> ExtGetMut<Extendee, Repeated<V>, RepeatedTag>
|
|
for ExtensionId<Extendee, Repeated<V>>
|
|
where
|
|
V: Singular + EntityType + UpbTypeConversions<V::Tag>,
|
|
{
|
|
fn get_mut<'msg>(
|
|
&self,
|
|
_private: Private,
|
|
msg: impl IntoMut<'msg, MutProxied = Extendee>,
|
|
) -> Mut<'msg, Repeated<V>> {
|
|
let mut msg = msg.into_mut();
|
|
|
|
// SAFETY: The arena associated with a `Mut<'msg, _>` proxy lives for at least `'msg`.
|
|
// `UpbGetArena::get_arena` returns an `&Arena` tied to the local borrow of `msg`,
|
|
// but we can safely extend it back to `'msg` here because `msg` holds an `&'msg Arena`.
|
|
let arena_ref: &'msg Arena = unsafe { &*(msg.get_arena(Private) as *const Arena) };
|
|
let raw_array = unsafe {
|
|
upb_Message_GetExtensionMutableArray(
|
|
msg.get_ptr_mut(Private).raw(),
|
|
self.inner.mini_table().as_ptr(),
|
|
)
|
|
};
|
|
let raw_array = raw_array.unwrap_or_else(|| unsafe {
|
|
let new_arr = upb_Array_New(arena_ref.raw(), V::upb_type());
|
|
let mut ptr = new_arr.as_ptr();
|
|
upb_Message_SetExtension(
|
|
msg.get_ptr_mut(Private).raw(),
|
|
self.inner.mini_table().as_ptr(),
|
|
&mut ptr as *mut _ as *const core::ffi::c_void,
|
|
arena_ref.raw(),
|
|
);
|
|
new_arr
|
|
});
|
|
unsafe {
|
|
RepeatedMut::from_inner(Private, InnerRepeatedMut::new(raw_array, arena_ref)).into_mut()
|
|
}
|
|
}
|
|
}
|
|
|
|
macro_rules! impl_upb_scalar_extension {
|
|
($($t:ty => [$get:ident, $set:ident]),* $(,)?) => {
|
|
$(
|
|
impl<Extendee: Message> ExtAccess<Extendee, $t, PrimitiveTag> for ExtensionId<Extendee, $t> {
|
|
fn get<'msg>(&self, _private: Private, msg: impl IntoView<'msg, Proxied = Extendee>) -> View<'msg, $t> {
|
|
let msg = msg.into_view();
|
|
unsafe {
|
|
$get(
|
|
msg.get_ptr(Private).raw(),
|
|
self.inner.mini_table().as_ptr(),
|
|
self.default.expect("scalar extensions must have a default value"),
|
|
)
|
|
}
|
|
}
|
|
|
|
fn set(&self, _private: Private, mut msg: impl AsMut<MutProxied = Extendee>, value: impl IntoProxied<$t>) {
|
|
let mut msg_mut = msg.as_mut();
|
|
unsafe {
|
|
assert!($set(
|
|
msg_mut.get_ptr_mut(Private).raw(),
|
|
self.inner.mini_table().as_ptr(),
|
|
value.into_proxied(Private),
|
|
msg_mut.get_arena(Private).raw(),
|
|
));
|
|
}
|
|
}
|
|
}
|
|
)*
|
|
};
|
|
}
|
|
|
|
impl_upb_scalar_extension!(
|
|
bool => [upb_Message_GetExtensionBool, upb_Message_SetExtensionBool],
|
|
f32 => [upb_Message_GetExtensionFloat, upb_Message_SetExtensionFloat],
|
|
f64 => [upb_Message_GetExtensionDouble, upb_Message_SetExtensionDouble],
|
|
i32 => [upb_Message_GetExtensionInt32, upb_Message_SetExtensionInt32],
|
|
i64 => [upb_Message_GetExtensionInt64, upb_Message_SetExtensionInt64],
|
|
u32 => [upb_Message_GetExtensionUInt32, upb_Message_SetExtensionUInt32],
|
|
u64 => [upb_Message_GetExtensionUInt64, upb_Message_SetExtensionUInt64],
|
|
);
|
|
|
|
impl<Extendee: Message> ExtAccess<Extendee, ProtoString, PrimitiveTag>
|
|
for ExtensionId<Extendee, ProtoString>
|
|
{
|
|
fn get<'msg>(
|
|
&self,
|
|
_private: Private,
|
|
msg: impl IntoView<'msg, Proxied = Extendee>,
|
|
) -> View<'msg, ProtoString> {
|
|
let msg = msg.into_view();
|
|
let upb_str_view = unsafe {
|
|
upb_Message_GetExtensionString(
|
|
msg.get_ptr(Private).raw(),
|
|
self.inner.mini_table().as_ptr(),
|
|
self.default.expect("string extensions must have a default value").into(),
|
|
)
|
|
};
|
|
unsafe { ProtoStr::from_utf8_unchecked(upb_str_view.as_ref()) }
|
|
}
|
|
|
|
fn set(
|
|
&self,
|
|
_private: Private,
|
|
mut msg: impl AsMut<MutProxied = Extendee>,
|
|
value: impl IntoProxied<ProtoString>,
|
|
) {
|
|
let s = value.into_proxied(Private);
|
|
let (view, arena) = s.into_inner(Private).into_raw_parts();
|
|
let mut msg_mut = msg.as_mut();
|
|
msg_mut.get_arena(Private).fuse(&arena);
|
|
unsafe {
|
|
assert!(upb_Message_SetExtensionString(
|
|
msg_mut.get_ptr_mut(Private).raw(),
|
|
self.inner.mini_table().as_ptr(),
|
|
view,
|
|
msg_mut.get_arena(Private).raw(),
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<Extendee: Message> ExtAccess<Extendee, ProtoBytes, PrimitiveTag>
|
|
for ExtensionId<Extendee, ProtoBytes>
|
|
{
|
|
fn get<'msg>(
|
|
&self,
|
|
_private: Private,
|
|
msg: impl IntoView<'msg, Proxied = Extendee>,
|
|
) -> View<'msg, ProtoBytes> {
|
|
let msg = msg.into_view();
|
|
let upb_str_view = unsafe {
|
|
upb_Message_GetExtensionString(
|
|
msg.get_ptr(Private).raw(),
|
|
self.inner.mini_table().as_ptr(),
|
|
self.default.expect("bytes extensions must have a default value").into(),
|
|
)
|
|
};
|
|
unsafe { upb_str_view.as_ref() }
|
|
}
|
|
|
|
fn set(
|
|
&self,
|
|
_private: Private,
|
|
mut msg: impl AsMut<MutProxied = Extendee>,
|
|
value: impl IntoProxied<ProtoBytes>,
|
|
) {
|
|
let s = value.into_proxied(Private);
|
|
let (view, arena) = s.into_inner(Private).into_raw_parts();
|
|
let mut msg_mut = msg.as_mut();
|
|
msg_mut.get_arena(Private).fuse(&arena);
|
|
unsafe {
|
|
assert!(upb_Message_SetExtensionString(
|
|
msg_mut.get_ptr_mut(Private).raw(),
|
|
self.inner.mini_table().as_ptr(),
|
|
view,
|
|
msg_mut.get_arena(Private).raw(),
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<Msg: Message, T: Proxied> ExtClear<Msg> for ExtensionId<Msg, T> {
|
|
fn clear(&self, _private: Private, mut msg: impl AsMut<MutProxied = Msg>) {
|
|
// SAFETY:
|
|
// - `msg` is a valid message.
|
|
// - `mini_table` is the one associated with `self`.
|
|
unsafe {
|
|
upb_Message_ClearExtension(
|
|
msg.as_mut().get_ptr_mut(Private).raw(),
|
|
self.inner.mini_table().as_ptr(),
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<Extendee: Message, E> ExtAccess<Extendee, E, EnumTag> for ExtensionId<Extendee, E>
|
|
where
|
|
E: Enum + Proxied + EntityType<Tag = EnumTag> + Copy,
|
|
for<'a> E: Proxied<View<'a> = E>,
|
|
for<'a> Extendee::MessageView<'a>: UpbGetMessagePtr,
|
|
i32: From<E>,
|
|
{
|
|
fn get<'msg>(
|
|
&self,
|
|
_private: Private,
|
|
msg: impl IntoView<'msg, Proxied = Extendee>,
|
|
) -> View<'msg, E> {
|
|
let msg = msg.into_view();
|
|
let default = self.default.expect("enum extensions must have a default value");
|
|
let val = unsafe {
|
|
upb_Message_GetExtensionInt32(
|
|
msg.get_ptr(Private).raw(),
|
|
self.inner.mini_table().as_ptr(),
|
|
i32::from(default),
|
|
)
|
|
};
|
|
E::try_from(val).unwrap_or(default)
|
|
}
|
|
|
|
fn set(
|
|
&self,
|
|
_private: Private,
|
|
mut msg: impl AsMut<MutProxied = Extendee>,
|
|
value: impl IntoProxied<E>,
|
|
) {
|
|
let mut msg_mut = msg.as_mut();
|
|
unsafe {
|
|
assert!(upb_Message_SetExtensionInt32(
|
|
msg_mut.get_ptr_mut(Private).raw(),
|
|
self.inner.mini_table().as_ptr(),
|
|
value.into_proxied(Private).into(),
|
|
msg_mut.get_arena(Private).raw(),
|
|
));
|
|
}
|
|
}
|
|
}
|