use core::alloc::Layout;
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
use crate::{
arena::Arena,
containers::{Bytes, RepeatedField},
generated_code_only::Protobuf,
};
#[derive(Debug, Default)]
#[repr(C)]
pub(crate) struct Message(pub *mut Object);
unsafe impl Send for Message {}
unsafe impl Sync for Message {}
impl Message {
pub const fn new<T>(msg: &T) -> Self {
Message(msg as *const T as *mut T as *mut Object)
}
pub const fn null() -> Self {
Message(core::ptr::null_mut())
}
pub const fn is_null(&self) -> bool {
self.0.is_null()
}
pub const fn as_ref<T>(&self) -> &T {
debug_assert!(!self.0.is_null());
unsafe { &*(self.0 as *const T) }
}
pub fn as_mut<T>(&mut self) -> &mut T {
debug_assert!(!self.0.is_null());
unsafe { &mut *(self.0 as *mut T) }
}
}
#[repr(transparent)]
pub struct TypedMessage<T: Protobuf> {
msg: Message,
_marker: PhantomData<T>,
}
impl<T: Protobuf> core::fmt::Debug for TypedMessage<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "TypedMessage({:?})", self.deref())
}
}
impl<T: Protobuf> Deref for TypedMessage<T> {
type Target = T;
fn deref(&self) -> &T {
self.msg.as_ref()
}
}
impl<T: Protobuf> DerefMut for TypedMessage<T> {
fn deref_mut(&mut self) -> &mut T {
self.msg.as_mut()
}
}
impl<T: Protobuf> TypedMessage<T> {
pub fn new_in(arena: &mut Arena) -> Result<Self, crate::Error<core::alloc::LayoutError>> {
let obj = Object::create(core::mem::size_of::<T>() as u32, arena)?;
Ok(Self {
msg: Message(obj as *mut Object),
_marker: PhantomData,
})
}
pub const fn from_static(r: &'static T) -> Self {
Self {
msg: Message::new(r),
_marker: PhantomData,
}
}
pub const fn as_ref(&self) -> &T {
self.msg.as_ref()
}
pub fn as_mut(&mut self) -> &mut T {
self.msg.as_mut()
}
}
#[repr(transparent)]
pub struct OptionalMessage<T: Protobuf> {
msg: Message,
_marker: PhantomData<T>,
}
impl<T: Protobuf> Default for OptionalMessage<T> {
fn default() -> Self {
Self::none()
}
}
impl<T: Protobuf> core::fmt::Debug for OptionalMessage<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self.get() {
Some(msg) => write!(f, "Some({:?})", msg),
None => write!(f, "None"),
}
}
}
impl<T: Protobuf> OptionalMessage<T> {
pub const fn none() -> Self {
Self {
msg: Message::null(),
_marker: PhantomData,
}
}
pub const fn from_static(r: &'static T) -> Self {
Self {
msg: Message::new(r),
_marker: PhantomData,
}
}
pub const fn is_some(&self) -> bool {
!self.msg.is_null()
}
pub const fn is_none(&self) -> bool {
self.msg.is_null()
}
pub const fn get(&self) -> Option<&T> {
if self.msg.is_null() {
None
} else {
Some(self.msg.as_ref())
}
}
pub fn get_mut(&mut self) -> Option<&mut T> {
if self.msg.is_null() {
None
} else {
Some(self.msg.as_mut())
}
}
pub fn get_or_init(&mut self, arena: &mut Arena) -> Result<&mut T, crate::Error<core::alloc::LayoutError>> {
if self.msg.is_null() {
let obj = Object::create(core::mem::size_of::<T>() as u32, arena)?;
self.msg = Message(obj as *mut Object);
}
Ok(self.msg.as_mut())
}
pub fn clear(&mut self) {
self.msg = Message::null();
}
}
pub struct Object;
impl Object {
pub fn create(size: u32, arena: &mut Arena) -> Result<&'static mut Object, crate::Error<core::alloc::LayoutError>> {
unsafe {
let buffer = arena
.alloc_raw(Layout::from_size_align_unchecked(
size as usize,
core::mem::align_of::<u64>(),
))?
.as_ptr();
core::ptr::write_bytes(buffer, 0, size as usize);
Ok(&mut *(buffer as *mut Object))
}
}
pub const fn ref_at<T>(&self, offset: usize) -> &T {
let ptr = (self as *const Self as *const u8).wrapping_add(offset);
unsafe { &*(ptr as *const T) }
}
pub(crate) fn ref_mut<T>(&mut self, offset: u32) -> &mut T {
let ptr = (self as *mut Object as *mut u8).wrapping_add(offset as usize);
debug_assert!(ptr as usize % core::mem::align_of::<T>() == 0);
unsafe { &mut *(ptr as *mut T) }
}
pub const fn has_bit(&self, has_bit_idx: u8) -> bool {
let has_bit_word = has_bit_idx as usize / 32;
let has_bit_idx = has_bit_idx % 32;
(*self.ref_at::<u32>(has_bit_word * core::mem::size_of::<u32>())) & (1 << has_bit_idx) != 0
}
pub fn set_has_bit(&mut self, has_bit_idx: u32) {
let has_bit_word = has_bit_idx / 32;
let has_bit_idx = has_bit_idx % 32;
*self.ref_mut::<u32>(has_bit_word * 4) |= 1 << has_bit_idx;
}
pub fn clear_has_bit(&mut self, has_bit_idx: u32) {
let has_bit_word = has_bit_idx / 32;
let has_bit_idx = has_bit_idx % 32;
*self.ref_mut::<u32>(has_bit_word * 4) &= !(1 << has_bit_idx);
}
pub(crate) fn get<T: Copy>(&self, offset: usize) -> T {
*self.ref_at::<T>(offset)
}
pub(crate) fn get_slice<T>(&self, offset: usize) -> &[T] {
self.ref_at::<RepeatedField<T>>(offset).as_ref()
}
pub(crate) fn set<T>(&mut self, offset: u32, has_bit_idx: u32, val: T) -> &mut T {
self.set_has_bit(has_bit_idx);
let field = self.ref_mut::<T>(offset);
*field = val;
field
}
pub(crate) fn set_oneof<T>(
&mut self,
offset: u32,
discriminant_word_idx: u32,
field_number: u32,
val: T,
) -> &mut T {
*self.ref_mut::<u32>(discriminant_word_idx * 4) = field_number;
let field = self.ref_mut::<T>(offset);
*field = val;
field
}
pub(crate) fn add<T>(&mut self, offset: u32, val: T, arena: &mut Arena) -> Result<&mut T, crate::Error<core::alloc::LayoutError>> {
let field = self.ref_mut::<RepeatedField<T>>(offset);
field.push(val, arena)
}
pub(crate) fn bytes(&self, offset: usize) -> &[u8] {
self.ref_at::<Bytes>(offset).as_ref()
}
pub(crate) fn set_bytes(
&mut self,
offset: u32,
has_bit_idx: u32,
bytes: &[u8],
arena: &mut Arena,
) -> Result<&mut Bytes, crate::Error<core::alloc::LayoutError>> {
self.set_has_bit(has_bit_idx);
let field = self.ref_mut::<Bytes>(offset);
field.assign(bytes, arena)?;
Ok(field)
}
pub(crate) fn set_bytes_oneof(
&mut self,
offset: u32,
discriminant_word_idx: u32,
field_number: u32,
bytes: &[u8],
arena: &mut Arena,
) -> Result<&mut Bytes, crate::Error<core::alloc::LayoutError>> {
*self.ref_mut::<u32>(discriminant_word_idx * 4) = field_number;
let field = self.ref_mut::<Bytes>(offset);
field.assign(bytes, arena)?;
Ok(field)
}
pub(crate) fn add_bytes(&mut self, offset: u32, bytes: &[u8], arena: &mut Arena) -> Result<&mut Bytes, crate::Error<core::alloc::LayoutError>> {
let field = self.ref_mut::<RepeatedField<Bytes>>(offset);
let b = Bytes::from_slice(bytes, arena)?;
field.push(b, arena)
}
}