| // 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) } |
| } |
| } |