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 {
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);
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 {
let arena_ref: &'msg Arena = std::mem::transmute(msg.get_arena(Private));
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(), )
}
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();
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<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>) {
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(),
));
}
}
}