use super::*;
use crate::Enum;
pub trait UpbTypeConversions<Tag>: Proxied {
fn upb_type() -> upb::CType;
fn to_message_value(val: View<'_, Self>) -> upb_MessageValue;
unsafe fn into_message_value_fuse_if_required(
raw_arena: RawArena,
val: Self,
) -> upb_MessageValue;
unsafe fn from_message_value<'msg>(msg_val: upb_MessageValue) -> View<'msg, Self>;
#[allow(unused_variables)]
unsafe fn from_message_mut<'msg>(raw: RawMessage, arena: &'msg Arena) -> Mut<'msg, Self>
where
Self: Message,
{
panic!("mut_from_message_value is only implemented for messages.")
}
unsafe fn copy_repeated(src: RawArray, dest: RawArray, arena: RawArena);
}
impl<T> UpbTypeConversions<MessageTag> for T
where
Self: Message,
for<'a> View<'a, Self>: MessageViewInterop<'a>,
for<'a> Mut<'a, Self>: From<MessageMutInner<'a, Self>>,
{
fn upb_type() -> CType {
CType::Message
}
fn to_message_value(val: View<'_, Self>) -> upb_MessageValue {
upb_MessageValue { msg_val: Some(val.get_ptr(Private).raw()) }
}
unsafe fn into_message_value_fuse_if_required(
raw_parent_arena: RawArena,
mut val: Self,
) -> upb_MessageValue {
let parent_arena =
std::mem::ManuallyDrop::new(unsafe { Arena::from_raw(raw_parent_arena) });
parent_arena.fuse(val.get_arena(Private));
upb_MessageValue { msg_val: Some(val.get_ptr(Private).raw()) }
}
unsafe fn from_message_value<'msg>(msg: upb_MessageValue) -> View<'msg, Self> {
unsafe {
let raw = msg.msg_val.expect("expected present message value in map");
View::<Self>::__unstable_wrap_raw_message_unchecked_lifetime(
raw.as_ptr() as *const std::ffi::c_void
)
}
}
unsafe fn from_message_mut<'msg>(msg: RawMessage, arena: &'msg Arena) -> Mut<'msg, Self> {
unsafe { MessageMutInner::<'msg, Self>::wrap_raw(msg, arena).into() }
}
unsafe fn copy_repeated(src: RawArray, dest: RawArray, arena: RawArena) {
unsafe {
let size = upb_Array_Size(src);
if !upb_Array_Resize(dest, size, arena) {
panic!("upb_Array_Resize failed (alloc should be infallible)");
}
for i in 0..size {
let src_msg =
upb_Array_Get(src, i).msg_val.expect("upb_Array* element should not be NULL");
let cloned_msg = upb_Message_DeepClone(src_msg, Self::mini_table(), arena)
.expect("upb_Message_DeepClone failed (alloc should be infallible)");
upb_Array_Set(dest, i, upb_MessageValue { msg_val: Some(cloned_msg) });
}
}
}
}
impl<T> UpbTypeConversions<EnumTag> for T
where
Self: Enum,
{
fn upb_type() -> CType {
CType::Enum
}
fn to_message_value(val: View<'_, Self>) -> upb_MessageValue {
upb_MessageValue { int32_val: val.into() }
}
unsafe fn into_message_value_fuse_if_required(
_raw_parent_arena: RawArena,
val: Self,
) -> upb_MessageValue {
upb_MessageValue { int32_val: val.into() }
}
unsafe fn from_message_value<'msg>(val: upb_MessageValue) -> View<'msg, Self> {
let result = Self::try_from(unsafe { val.int32_val });
std::debug_assert!(result.is_ok());
unsafe { result.unwrap_unchecked() }
}
unsafe fn copy_repeated(src: RawArray, dest: RawArray, arena: RawArena) {
unsafe {
<i32 as UpbTypeConversions<PrimitiveTag>>::copy_repeated(src, dest, arena);
}
}
}
macro_rules! impl_upb_type_conversions_for_scalars {
($($t:ty, $ufield:ident, $upb_tag:expr, $zero_val:literal;)*) => {
$(
impl UpbTypeConversions<PrimitiveTag> for $t {
#[inline(always)]
fn upb_type() -> upb::CType {
$upb_tag
}
#[inline(always)]
fn to_message_value(val: View<'_, $t>) -> upb_MessageValue {
upb_MessageValue { $ufield: val }
}
#[inline(always)]
unsafe fn into_message_value_fuse_if_required(_: RawArena, val: $t) -> upb_MessageValue {
<Self as UpbTypeConversions<PrimitiveTag>>::to_message_value(val)
}
#[inline(always)]
unsafe fn from_message_value<'msg>(msg: upb_MessageValue) -> View<'msg, $t> {
unsafe { msg.$ufield }
}
#[inline(always)]
unsafe fn copy_repeated(src: RawArray, dest: RawArray, arena: RawArena) {
unsafe {
let len = upb_Array_Size(src);
if (!upb_Array_Resize(dest, len, arena)) {
panic!("upb_Array_Resize failed (alloc should be infallible)");
}
ptr::copy_nonoverlapping(
upb_Array_DataPtr(src).cast::<u8>(),
upb_Array_MutableDataPtr(dest).cast::<u8>(),
size_of::<$t>() * len);
}
}
}
)*
};
}
impl_upb_type_conversions_for_scalars!(
f32, float_val, upb::CType::Float, 0f32;
f64, double_val, upb::CType::Double, 0f64;
i32, int32_val, upb::CType::Int32, 0i32;
u32, uint32_val, upb::CType::UInt32, 0u32;
i64, int64_val, upb::CType::Int64, 0i64;
u64, uint64_val, upb::CType::UInt64, 0u64;
bool, bool_val, upb::CType::Bool, false;
);
impl UpbTypeConversions<PrimitiveTag> for ProtoBytes {
fn upb_type() -> upb::CType {
upb::CType::Bytes
}
fn to_message_value(val: View<'_, ProtoBytes>) -> upb_MessageValue {
upb_MessageValue { str_val: val.into() }
}
unsafe fn into_message_value_fuse_if_required(
raw_parent_arena: RawArena,
val: ProtoBytes,
) -> upb_MessageValue {
let parent_arena = ManuallyDrop::new(unsafe { Arena::from_raw(raw_parent_arena) });
let (view, arena) = val.inner.into_raw_parts();
parent_arena.fuse(&arena);
upb_MessageValue { str_val: view }
}
unsafe fn from_message_value<'msg>(msg: upb_MessageValue) -> View<'msg, ProtoBytes> {
let _ = unsafe { msg.str_val.as_ref() };
unsafe { msg.str_val.as_ref() }
}
unsafe fn copy_repeated(src: RawArray, dest: RawArray, arena: RawArena) {
unsafe {
copy_repeated_bytes(src, dest, arena);
}
}
}
impl UpbTypeConversions<PrimitiveTag> for ProtoString {
fn upb_type() -> upb::CType {
upb::CType::String
}
fn to_message_value(val: View<'_, ProtoString>) -> upb_MessageValue {
upb_MessageValue { str_val: val.as_bytes().into() }
}
unsafe fn into_message_value_fuse_if_required(
raw_arena: RawArena,
val: ProtoString,
) -> upb_MessageValue {
unsafe {
<ProtoBytes as UpbTypeConversions<PrimitiveTag>>::into_message_value_fuse_if_required(
raw_arena,
val.into(),
)
}
}
unsafe fn from_message_value<'msg>(msg: upb_MessageValue) -> View<'msg, ProtoString> {
ProtoStr::from_utf8_unchecked(unsafe { msg.str_val.as_ref() })
}
unsafe fn copy_repeated(src: RawArray, dest: RawArray, arena: RawArena) {
unsafe {
copy_repeated_bytes(src, dest, arena);
}
}
}
unsafe fn copy_repeated_bytes(src: RawArray, dest: RawArray, arena: RawArena) {
unsafe {
let len = upb_Array_Size(src);
let arena = ManuallyDrop::new(Arena::from_raw(arena));
if !upb_Array_Resize(dest, len, arena.raw()) {
panic!("upb_Array_Resize failed (alloc should be infallible)");
}
let src_ptrs: &[PtrAndLen] = slice::from_raw_parts(upb_Array_DataPtr(src).cast(), len);
let dest_ptrs: &mut [PtrAndLen] =
slice::from_raw_parts_mut(upb_Array_MutableDataPtr(dest).cast(), len);
for (src_ptr, dest_ptr) in src_ptrs.iter().zip(dest_ptrs) {
*dest_ptr = arena.copy_slice_in(src_ptr.as_ref()).unwrap().into();
}
}
}