// 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, } impl InnerExtensionId { pub const fn new(mini_table: &'static LazyLock) -> Self { Self { mini_table } } pub fn mini_table(&self) -> RawMiniTableExtension { self.mini_table.0 } } #[linkme::distributed_slice] pub static EXTENSIONS: [LazyLock]; #[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 = 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 ExtHas for ExtensionId { fn has(&self, _private: Private, msg: impl AsView) -> 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 ExtAccess for ExtensionId { fn get<'msg>( &self, _private: Private, msg: impl IntoView<'msg, Proxied = Extendee>, ) -> View<'msg, V> { let msg = msg.into_view(); let default_instance = ::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 { >::__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, value: impl IntoProxied, ) { 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 ExtGetMut for ExtensionId { 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 = std::mem::transmute(msg.get_arena(Private)); // 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::::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 ExtAccess, RepeatedTag> for ExtensionId> where V: EntityType + UpbTypeConversions, { fn get<'msg>( &self, _private: Private, msg: impl IntoView<'msg, Proxied = Extendee>, ) -> View<'msg, Repeated> { 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::, |raw| RepeatedView::from_raw(Private, raw)), ) } } fn set( &self, _private: Private, mut msg: impl AsMut, value: impl IntoProxied>, ) { 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 ExtGetMut, RepeatedTag> for ExtensionId> where V: Singular + EntityType + UpbTypeConversions, { fn get_mut<'msg>( &self, _private: Private, msg: impl IntoMut<'msg, MutProxied = Extendee>, ) -> Mut<'msg, Repeated> { let mut msg = msg.into_mut(); let arena_ref: &'msg Arena = unsafe { std::mem::transmute(msg.get_arena(Private)) }; 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 ExtAccess for ExtensionId { 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, 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 ExtAccess for ExtensionId { 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, value: impl IntoProxied, ) { 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 ExtAccess for ExtensionId { 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, value: impl IntoProxied, ) { 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 ExtClear for ExtensionId { fn clear(&self, _private: Private, mut msg: impl AsMut) { // 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 ExtAccess for ExtensionId where E: Enum + Proxied + EntityType + Copy, for<'a> E: Proxied = E>, for<'a> Extendee::MessageView<'a>: UpbGetMessagePtr, i32: From, { 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, value: impl IntoProxied, ) { 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(), )); } } }