extern crate alloc;
use flatbuffers::{FlatBufferBuilder, WIPOffset};
use iceoryx2_bb_concurrency::atomic::{AtomicUsize, Ordering};
use iceoryx2_bb_elementary_traits::{iceoryx_send::IceoryxSend, zero_copy_send::ZeroCopySend};
use iceoryx2_bb_flatbuffers::ResizableMemory;
use iceoryx2_cal::{shared_memory::ShmPointer, zero_copy_connection::ChannelId};
use iceoryx2_log::fail;
use crate::{
payload::number_of_elements,
port::{
LoanError,
details::{chunk::ChunkMut, chunk_mut_shared_state::ChunkMutSharedState},
server::SharedServerState,
},
response_mut::ResponseMut,
service::{self, marker::Flatbuffer},
};
use alloc::sync::Arc;
use core::marker::PhantomData;
use core::{fmt::Debug, mem::MaybeUninit};
pub type FlatbufferMemory<Service> =
ResizableMemory<ShmPointer, ChunkMutSharedState<Service, SharedServerState<Service>>>;
pub struct ResponseMutUninit<
Service: service::Service,
ResponsePayload: Debug + IceoryxSend + ?Sized,
ResponseHeader: Debug + ZeroCopySend,
> {
shared_state: ChunkMutSharedState<Service, SharedServerState<Service>>,
shared_loan_counter: Arc<AtomicUsize>,
chunk: ChunkMut,
channel_id: ChannelId,
connection_id: usize,
flatbuffer_builder: Option<FlatBufferBuilder<'static, FlatbufferMemory<Service>>>,
assume_init_was_called: bool,
_response_payload: PhantomData<ResponsePayload>,
_response_header: PhantomData<ResponseHeader>,
}
unsafe impl<
Service: crate::service::Service,
ResponsePayload: Debug + IceoryxSend + ?Sized,
ResponseHeader: Debug + ZeroCopySend,
> Send for ResponseMutUninit<Service, ResponsePayload, ResponseHeader>
where
Service::ArcThreadSafetyPolicy<SharedServerState<Service>>: Send + Sync,
{
}
impl<
Service: crate::service::Service,
ResponsePayload: Debug + IceoryxSend + ?Sized,
ResponseHeader: Debug + ZeroCopySend,
> Drop for ResponseMutUninit<Service, ResponsePayload, ResponseHeader>
{
fn drop(&mut self) {
if !self.assume_init_was_called {
self.shared_loan_counter.fetch_sub(1, Ordering::Relaxed);
}
}
}
impl<
Service: crate::service::Service,
ResponsePayload: Debug + IceoryxSend + ?Sized,
ResponseHeader: Debug + ZeroCopySend,
> Debug for ResponseMutUninit<Service, ResponsePayload, ResponseHeader>
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"ResponseMut {{ shared_loan_counter: {:?}, chunk: {:?}, channel_id: {:?}, connection_id: {} }}",
self.shared_loan_counter.load(Ordering::Relaxed),
self.chunk,
self.channel_id,
self.connection_id
)
}
}
impl<Service: crate::service::Service, ResponsePayload, ResponseHeader: Debug + ZeroCopySend>
ResponseMutUninit<Service, Flatbuffer<ResponsePayload>, ResponseHeader>
{
pub(crate) fn new_flatbuffer(
shared_state: &Service::ArcThreadSafetyPolicy<SharedServerState<Service>>,
chunk: ChunkMut,
shared_loan_counter: &Arc<AtomicUsize>,
channel_id: ChannelId,
connection_id: usize,
) -> Result<Self, LoanError> {
let shared_state = fail!(from "ResponseMutUninit::new_flatbuffer()",
when ChunkMutSharedState::new(shared_state, &chunk),
with LoanError::InternalFailure,
"Unable to create the response since the underlying shared state could not be initialized.");
let mut new_self = Self {
flatbuffer_builder: None,
shared_state,
chunk,
channel_id,
assume_init_was_called: false,
shared_loan_counter: shared_loan_counter.clone(),
connection_id,
_response_header: PhantomData,
_response_payload: PhantomData,
};
new_self.flatbuffer_builder = Some(FlatBufferBuilder::new_in(
new_self.__internal_create_resizable_memory(),
));
Ok(new_self)
}
pub fn flatbuffer_builder(
&mut self,
) -> &mut FlatBufferBuilder<'static, FlatbufferMemory<Service>> {
self.flatbuffer_builder
.as_mut()
.expect("Flatbuffer builder is set when using Flatbuffer marker.")
}
pub fn assume_init(
mut self,
root: WIPOffset<ResponsePayload>,
) -> ResponseMut<Service, Flatbuffer<ResponsePayload>, ResponseHeader> {
self.flatbuffer_builder().finish(root, None);
let payload_ptr = self.flatbuffer_builder().finished_data().as_ptr();
self.__internal_finish_serialized(payload_ptr);
self.assume_init_was_called = true;
ResponseMut {
shared_loan_counter: self.shared_loan_counter.clone(),
shared_state: self.shared_state.clone(),
connection_id: self.connection_id,
chunk: self.chunk.clone(),
channel_id: self.channel_id,
_response_header: PhantomData,
_response_payload: PhantomData,
}
}
}
impl<
Service: crate::service::Service,
ResponsePayload: Debug + IceoryxSend + ?Sized,
ResponseHeader: Debug + ZeroCopySend,
> ResponseMutUninit<Service, ResponsePayload, ResponseHeader>
{
#[doc(hidden)]
pub fn __internal_available_payload_memory(&self) -> usize {
self.shared_state
.call(|s| -> Result<usize, ()> {
Ok(self.chunk.size - s.response_sender.message_type_details.all_headers_len())
})
.expect("Always returns ok.")
}
#[doc(hidden)]
pub fn __internal_create_resizable_memory(&self) -> FlatbufferMemory<Service> {
self.shared_state.create_resizable_memory(&self.chunk)
}
#[doc(hidden)]
pub fn __internal_finish_serialized(&mut self, payload_ptr: *const u8) {
let memory_structure = self.shared_state.memory_structure(payload_ptr);
self.chunk = memory_structure.chunk;
let header = unsafe {
&mut *self
.chunk
.header_mut_ptr()
.cast::<crate::service::header::request_response::ResponseHeader>()
};
header.number_of_elements = memory_structure.payload_size;
header.payload_offset = memory_structure.payload_offset;
}
}
impl<
Service: crate::service::Service,
ResponsePayload: Debug + IceoryxSend + ZeroCopySend + ?Sized,
ResponseHeader: Debug + ZeroCopySend,
> ResponseMutUninit<Service, ResponsePayload, ResponseHeader>
{
pub(crate) fn new(
shared_state: &Service::ArcThreadSafetyPolicy<SharedServerState<Service>>,
chunk: ChunkMut,
shared_loan_counter: &Arc<AtomicUsize>,
channel_id: ChannelId,
connection_id: usize,
) -> Result<Self, LoanError> {
let shared_state = fail!(from "ResponseMutUninit::new()",
when ChunkMutSharedState::new(shared_state, &chunk),
with LoanError::InternalFailure,
"Unable to create the response since the underlying shared state could not be initialized.");
Ok(Self {
shared_state,
shared_loan_counter: shared_loan_counter.clone(),
chunk: chunk.clone(),
channel_id,
connection_id,
assume_init_was_called: false,
flatbuffer_builder: None,
_response_payload: PhantomData,
_response_header: PhantomData,
})
}
pub fn header(&self) -> &service::header::request_response::ResponseHeader {
unsafe { &*self.chunk.header_ptr().cast() }
}
pub fn user_header(&self) -> &ResponseHeader {
unsafe { &*self.chunk.user_header_ptr().cast() }
}
pub fn user_header_mut(&mut self) -> &mut ResponseHeader {
unsafe { &mut *self.chunk.user_header_mut_ptr().cast() }
}
}
impl<
Service: crate::service::Service,
ResponsePayload: Debug + ZeroCopySend,
ResponseHeader: Debug + ZeroCopySend,
> ResponseMutUninit<Service, ResponsePayload, ResponseHeader>
{
pub fn payload(&self) -> &ResponsePayload {
unsafe { &*self.chunk.payload_ptr().cast() }
}
pub fn payload_mut(&mut self) -> &mut ResponsePayload {
unsafe { &mut *self.chunk.payload_mut_ptr().cast() }
}
}
impl<
Service: crate::service::Service,
ResponsePayload: Debug + ZeroCopySend,
ResponseHeader: Debug + ZeroCopySend,
> ResponseMutUninit<Service, [ResponsePayload], ResponseHeader>
{
pub fn payload(&self) -> &[ResponsePayload] {
let payload_size = self.shared_state.payload_size();
unsafe {
&*core::ptr::slice_from_raw_parts(
self.chunk.payload_ptr().cast(),
number_of_elements::<ResponsePayload, _>(self.header(), payload_size),
)
}
}
pub fn payload_mut(&mut self) -> &mut [ResponsePayload] {
let payload_size = self.shared_state.payload_size();
unsafe {
&mut *core::ptr::slice_from_raw_parts_mut(
self.chunk.payload_mut_ptr().cast(),
number_of_elements::<ResponsePayload, _>(self.header(), payload_size),
)
}
}
}
impl<
Service: crate::service::Service,
ResponsePayload: Debug + ZeroCopySend,
ResponseHeader: Debug + ZeroCopySend,
> ResponseMutUninit<Service, MaybeUninit<ResponsePayload>, ResponseHeader>
{
pub fn write_payload(
mut self,
value: ResponsePayload,
) -> ResponseMut<Service, ResponsePayload, ResponseHeader> {
self.payload_mut().write(value);
unsafe { self.assume_init() }
}
pub unsafe fn assume_init(mut self) -> ResponseMut<Service, ResponsePayload, ResponseHeader> {
self.assume_init_was_called = true;
ResponseMut {
shared_state: self.shared_state.clone(),
shared_loan_counter: self.shared_loan_counter.clone(),
channel_id: self.channel_id,
chunk: self.chunk.clone(),
connection_id: self.connection_id,
_response_header: PhantomData,
_response_payload: PhantomData,
}
}
}
impl<
Service: crate::service::Service,
ResponsePayload: Debug + ZeroCopySend,
ResponseHeader: Debug + ZeroCopySend,
> ResponseMutUninit<Service, [MaybeUninit<ResponsePayload>], ResponseHeader>
{
pub unsafe fn assume_init(mut self) -> ResponseMut<Service, [ResponsePayload], ResponseHeader> {
self.assume_init_was_called = true;
ResponseMut {
shared_state: self.shared_state.clone(),
shared_loan_counter: self.shared_loan_counter.clone(),
channel_id: self.channel_id,
chunk: self.chunk.clone(),
connection_id: self.connection_id,
_response_header: PhantomData,
_response_payload: PhantomData,
}
}
pub fn write_from_fn<F: FnMut(usize) -> ResponsePayload>(
mut self,
mut initializer: F,
) -> ResponseMut<Service, [ResponsePayload], ResponseHeader> {
for (i, element) in self.payload_mut().iter_mut().enumerate() {
element.write(initializer(i));
}
unsafe { self.assume_init() }
}
}
impl<
Service: crate::service::Service,
ResponsePayload: Debug + Copy + ZeroCopySend,
ResponseHeader: Debug + ZeroCopySend,
> ResponseMutUninit<Service, [MaybeUninit<ResponsePayload>], ResponseHeader>
{
pub fn write_from_slice(
mut self,
value: &[ResponsePayload],
) -> ResponseMut<Service, [ResponsePayload], ResponseHeader> {
self.payload_mut().copy_from_slice(unsafe {
core::mem::transmute::<&[ResponsePayload], &[MaybeUninit<ResponsePayload>]>(value)
});
unsafe { self.assume_init() }
}
}