blob: 3f0f9ed0630b36d41abad36823798bdea517853f [file] [log] [blame]
// Protocol Buffers - Google's data interchange format
// Copyright 2025 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::sys::{
message::array as sys_array, message::map as sys_map, message::message as sys_msg,
mini_table::mini_table as sys_mt,
};
use super::StringView;
use super::{Arena, AssociatedMiniTable};
use core::marker::PhantomData;
use paste::paste;
pub type RawMessage = sys_msg::RawMessage;
#[derive(Debug)]
pub struct MessagePtr<T> {
raw: RawMessage,
_phantom: PhantomData<T>,
}
impl<T> Copy for MessagePtr<T> {}
impl<T> Clone for MessagePtr<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> MessagePtr<T> {
pub fn raw(&self) -> RawMessage {
self.raw
}
}
macro_rules! scalar_accessors {
( $ty:ty, $rust_ty_name:ident, $upb_ty_name:ident) => {
paste! {
impl<T: AssociatedMiniTable> MessagePtr<T> {
/// # Safety
/// - `self` must be legally dereferenceable.
/// - The field at `index` must be a $ty field.
pub unsafe fn [< get_ $rust_ty_name _at_index >] (self, index: u32, default_value: $ty) -> $ty {
let f = unsafe { sys_mt::upb_MiniTable_GetFieldByIndex(T::mini_table(), index) };
unsafe { sys_msg::[< upb_Message_Get $upb_ty_name >](self.raw, f, default_value) }
}
/// # Safety
/// - `self` must be legally dereferenceable to a mutable message.
/// - The field at `index` must be a $ty field.
pub unsafe fn [< set_base_field_ $rust_ty_name _at_index >] (self, index: u32, value: $ty) {
let f = unsafe { sys_mt::upb_MiniTable_GetFieldByIndex(T::mini_table(), index) };
unsafe { sys_msg::[< upb_Message_SetBaseField $upb_ty_name >](self.raw, f, value) }
}
}
}
};
}
scalar_accessors!(bool, bool, Bool);
scalar_accessors!(i32, i32, Int32);
scalar_accessors!(i64, i64, Int64);
scalar_accessors!(u32, u32, UInt32);
scalar_accessors!(u64, u64, UInt64);
scalar_accessors!(f32, f32, Float);
scalar_accessors!(f64, f64, Double);
scalar_accessors!(StringView, string, String);
impl<T: AssociatedMiniTable> MessagePtr<T> {
/// Constructs a new mutable message pointer.
/// Will only return None if arena allocation fails.
pub fn new(arena: &Arena) -> Option<MessagePtr<T>> {
let raw = unsafe { sys_msg::upb_Message_New(T::mini_table(), arena.raw()) };
raw.map(|raw| MessagePtr { raw, _phantom: PhantomData })
}
/// # Safety
/// - `raw` must be a dereferenceable message pointer of message associated with `T::mini_table()`.
pub unsafe fn wrap(raw: RawMessage) -> MessagePtr<T> {
MessagePtr { raw, _phantom: PhantomData }
}
/// # Safety
/// - `self` must be legally dereferenceable to a mutable message.
pub unsafe fn clear(self) {
unsafe { sys_msg::upb_Message_Clear(self.raw, T::mini_table()) }
}
/// Copies the contents of `src` to `self`, using `arena` for allocations.
/// `arena` should be the one associated with `self`.
/// # Safety
/// - `self` must be legally dereferenceable to a mutable message.
pub unsafe fn deep_copy(self, src: Self, arena: &Arena) -> bool {
unsafe { sys_msg::upb_Message_DeepCopy(self.raw, src.raw, T::mini_table(), arena.raw()) }
}
/// Returns a pointer to a mutable message which is a clone of `self` on `arena`.
/// # Safety
/// - `self` must be legally dereferenceable.
pub unsafe fn deep_clone(self, arena: &Arena) -> Option<MessagePtr<T>> {
let raw = unsafe { sys_msg::upb_Message_DeepClone(self.raw, T::mini_table(), arena.raw()) };
raw.map(|raw| MessagePtr { raw, _phantom: PhantomData })
}
/// # Safety
/// - `self` must be legally dereferenceable.
/// - `index` must be within bounds of `T::mini_table()`.
pub unsafe fn clear_field_at_index(self, index: u32) {
let f = unsafe { sys_mt::upb_MiniTable_GetFieldByIndex(T::mini_table(), index) };
unsafe { sys_msg::upb_Message_ClearBaseField(self.raw, f) }
}
/// # Safety
/// - `self` must be legally dereferenceable.
/// - `index` must be within bounds of `T::mini_table()`.
pub unsafe fn has_field_at_index(self, index: u32) -> bool {
let f = unsafe { sys_mt::upb_MiniTable_GetFieldByIndex(T::mini_table(), index) };
unsafe { sys_msg::upb_Message_HasBaseField(self.raw, f) }
}
/// Returns a constant message pointer, or None if the field is not present.
///
/// # Safety
/// - `self` must be legally dereferenceable.
/// - The field at `index` must be a message field of type `ChildT`.
pub unsafe fn get_message_at_index<ChildT>(self, index: u32) -> Option<MessagePtr<ChildT>> {
let f = unsafe { sys_mt::upb_MiniTable_GetFieldByIndex(T::mini_table(), index) };
let raw = unsafe { sys_msg::upb_Message_GetMessage(self.raw, f) };
raw.map(|raw| MessagePtr { raw, _phantom: PhantomData })
}
/// # Safety
/// - `self` must be legally dereferenceable.
/// - The field at `index` must be a message field of type `ChildT`.
/// - Caller must ensure that `value` outlives `self` (typically by being on the same arena).
pub unsafe fn set_base_field_message_at_index<ChildT>(
self,
index: u32,
value: MessagePtr<ChildT>,
) {
let f = unsafe { sys_mt::upb_MiniTable_GetFieldByIndex(T::mini_table(), index) };
unsafe { sys_msg::upb_Message_SetBaseFieldMessage(self.raw, f, value.raw) }
}
/// Returns a mutable message pointer, creating the field if it is not present.
///
/// # Safety
/// - `self` must be legally dereferenceable to a mutable message.
/// - The field at `index` must be a message field of type `ChildT`.
pub unsafe fn get_or_create_mutable_message_at_index<ChildT>(
self,
index: u32,
arena: &Arena,
) -> Option<MessagePtr<ChildT>> {
let f = unsafe { sys_mt::upb_MiniTable_GetFieldByIndex(T::mini_table(), index) };
let raw = unsafe {
sys_msg::upb_Message_GetOrCreateMutableMessage(
self.raw,
T::mini_table(),
f,
arena.raw(),
)
};
raw.map(|raw| MessagePtr { raw, _phantom: PhantomData })
}
/// Returns a constant pointer to an array. May return None if the repeated field is empty.
///
/// # Safety
/// - `self` must be legally dereferenceable.
/// - The field at `index` must be a repeated field.
pub unsafe fn get_array_at_index(self, index: u32) -> Option<sys_array::RawArray> {
let f = unsafe { sys_mt::upb_MiniTable_GetFieldByIndex(T::mini_table(), index) };
let raw = unsafe { sys_msg::upb_Message_GetArray(self.raw, f) };
raw
}
/// # Safety
/// - `self` must be legally dereferenceable.
/// - The field at `index` must be a repeated field.
/// - Caller must ensure that `value` outlives `self` (typically by being on the same arena).
pub unsafe fn set_array_at_index(self, index: u32, value: sys_array::RawArray) {
let f = unsafe { sys_mt::upb_MiniTable_GetFieldByIndex(T::mini_table(), index) };
let value_ptr: *const *const core::ffi::c_void =
&(value.as_ptr() as *const core::ffi::c_void);
unsafe {
sys_msg::upb_Message_SetBaseField(self.raw, f, value_ptr as *const core::ffi::c_void)
}
}
/// Returns a mutable pointer to an array. Will only return None if arena allocation fails.
///
/// # Safety
/// - `self` must be legally dereferenceable to a mutable message.
/// - The field at `index` must be a repeated field.
pub unsafe fn get_or_create_mutable_array_at_index(
self,
index: u32,
arena: &Arena,
) -> Option<sys_array::RawArray> {
let f = unsafe { sys_mt::upb_MiniTable_GetFieldByIndex(T::mini_table(), index) };
let raw = unsafe { sys_msg::upb_Message_GetOrCreateMutableArray(self.raw, f, arena.raw()) };
raw
}
/// Returns a constant pointer to a map. May return None if the map is empty.
///
/// # Safety
/// - `self` must be legally dereferenceable.
/// - The field at `index` must be a map.
pub unsafe fn get_map_at_index(self, index: u32) -> Option<sys_map::RawMap> {
let f = unsafe { sys_mt::upb_MiniTable_GetFieldByIndex(T::mini_table(), index) };
unsafe { sys_msg::upb_Message_GetMap(self.raw, f) }
}
/// # Safety
/// - `self` must be legally dereferenceable.
/// - The field at `index` must be a repeated field.
/// - Caller must ensure that `value` outlives `self` (typically by being on the same arena).
pub unsafe fn set_map_at_index(self, index: u32, value: sys_map::RawMap) {
let f = unsafe { sys_mt::upb_MiniTable_GetFieldByIndex(T::mini_table(), index) };
let value_ptr: *const *const core::ffi::c_void =
&(value.as_ptr() as *const core::ffi::c_void);
unsafe {
sys_msg::upb_Message_SetBaseField(self.raw, f, value_ptr as *const core::ffi::c_void)
}
}
/// Returns a mutable pointer to a map. Will only return None if arena allocation fails.
///
/// # Safety
/// - `self` must be legally dereferenceable to a mutable message.
/// - The field at `index` must be a map.
pub unsafe fn get_or_create_mutable_map_at_index(
self,
index: u32,
arena: &Arena,
) -> Option<sys_map::RawMap> {
unsafe {
let f = sys_mt::upb_MiniTable_GetFieldByIndex(T::mini_table(), index);
let map_entry_mini_table = sys_mt::upb_MiniTable_SubMessage(T::mini_table(), f);
sys_msg::upb_Message_GetOrCreateMutableMap(
self.raw,
map_entry_mini_table,
f,
arena.raw(),
)
}
}
/// Returns the number associated with the active field in a oneof, or 0 if the oneof is unset.
/// `index` can be the field number of any field in the oneof.
///
/// # Safety
/// - `self` must be legally dereferenceable.
/// - The field at `index` must be part of a oneof.
pub unsafe fn which_oneof_field_number_by_index(self, index: u32) -> u32 {
let f = unsafe { sys_mt::upb_MiniTable_GetFieldByIndex(T::mini_table(), index) };
unsafe { sys_msg::upb_Message_WhichOneofFieldNumber(self.raw, f) }
}
}