use alloc::sync::Arc;
use core::{
fmt::Debug,
marker::PhantomData,
ops::{Deref, DerefMut},
};
use flatbuffers::InvalidFlatbuffer;
use iceoryx2_bb_flatbuffers::FlatbufferError;
use iceoryx2_bb_concurrency::atomic::AtomicUsize;
use iceoryx2_bb_concurrency::atomic::Ordering;
use iceoryx2_bb_elementary_traits::{iceoryx_send::IceoryxSend, zero_copy_send::ZeroCopySend};
use iceoryx2_cal::zero_copy_connection::ChannelId;
use iceoryx2_log::fail;
use crate::{
payload::number_of_elements,
port::{
SendError,
details::{chunk::ChunkMut, chunk_mut_shared_state::ChunkMutSharedState},
server::{INVALID_CONNECTION_ID, SharedServerState},
},
service::{self, marker::Flatbuffer},
};
pub struct ResponseMut<
Service: service::Service,
ResponsePayload: Debug + IceoryxSend + ?Sized,
ResponseHeader: Debug + ZeroCopySend,
> {
pub(crate) shared_state: ChunkMutSharedState<Service, SharedServerState<Service>>,
pub(crate) shared_loan_counter: Arc<AtomicUsize>,
pub(crate) chunk: ChunkMut,
pub(crate) channel_id: ChannelId,
pub(crate) connection_id: usize,
pub(crate) _response_payload: PhantomData<ResponsePayload>,
pub(crate) _response_header: PhantomData<ResponseHeader>,
}
unsafe impl<
Service: crate::service::Service,
ResponsePayload: Debug + IceoryxSend + ?Sized,
ResponseHeader: Debug + ZeroCopySend,
> Send for ResponseMut<Service, ResponsePayload, ResponseHeader>
where
Service::ArcThreadSafetyPolicy<SharedServerState<Service>>: Send + Sync,
{
}
impl<
Service: crate::service::Service,
ResponsePayload: Debug + IceoryxSend + ?Sized,
ResponseHeader: Debug + ZeroCopySend,
> Debug for ResponseMut<Service, ResponsePayload, ResponseHeader>
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"ResponseMut<{}, {}, {}> {{ chunk: {:?}, channel_id: {} }}",
core::any::type_name::<Service>(),
core::any::type_name::<ResponsePayload>(),
core::any::type_name::<ResponseHeader>(),
self.chunk,
self.channel_id.value()
)
}
}
impl<
Service: crate::service::Service,
ResponsePayload: Debug + IceoryxSend + ?Sized,
ResponseHeader: Debug + ZeroCopySend,
> Drop for ResponseMut<Service, ResponsePayload, ResponseHeader>
{
fn drop(&mut self) {
self.shared_loan_counter.fetch_sub(1, Ordering::Relaxed);
}
}
impl<
Service: crate::service::Service,
ResponsePayload: Debug + ZeroCopySend,
ResponseHeader: Debug + ZeroCopySend,
> Deref for ResponseMut<Service, ResponsePayload, ResponseHeader>
{
type Target = ResponsePayload;
fn deref(&self) -> &Self::Target {
unsafe { &*self.chunk.payload_ptr().cast() }
}
}
impl<
Service: crate::service::Service,
ResponsePayload: IceoryxSend + Debug + ZeroCopySend,
ResponseHeader: Debug + ZeroCopySend,
> Deref for ResponseMut<Service, [ResponsePayload], ResponseHeader>
{
type Target = [ResponsePayload];
fn deref(&self) -> &Self::Target {
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),
)
}
}
}
impl<
Service: crate::service::Service,
ResponsePayload: IceoryxSend + Debug + ZeroCopySend,
ResponseHeader: Debug + ZeroCopySend,
> DerefMut for ResponseMut<Service, ResponsePayload, ResponseHeader>
{
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.chunk.payload_mut_ptr().cast() }
}
}
impl<
Service: crate::service::Service,
ResponsePayload: IceoryxSend + Debug + ZeroCopySend,
ResponseHeader: Debug + ZeroCopySend,
> DerefMut for ResponseMut<Service, [ResponsePayload], ResponseHeader>
{
fn deref_mut(&mut self) -> &mut Self::Target {
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 + IceoryxSend + ?Sized,
ResponseHeader: Debug + ZeroCopySend,
> ResponseMut<Service, ResponsePayload, ResponseHeader>
{
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() }
}
pub fn send(self) -> Result<(), SendError> {
self.shared_state.call(|s| {
let msg = "Unable to send response";
fail!(from self, when s.update_connections(),
"{} since the connections could not be updated.", msg);
if self.connection_id != INVALID_CONNECTION_ID {
s.response_sender.deliver_offset_to_connection(
&self.chunk,
self.channel_id,
self.connection_id,
)?;
}
Ok(())
})
}
}
impl<
Service: crate::service::Service,
ResponsePayload: Debug + ZeroCopySend,
ResponseHeader: Debug + ZeroCopySend,
> ResponseMut<Service, ResponsePayload, ResponseHeader>
{
pub fn payload(&self) -> &ResponsePayload {
self.deref()
}
pub fn payload_mut(&mut self) -> &mut ResponsePayload {
&mut *self
}
}
impl<
Service: crate::service::Service,
ResponsePayload: Debug + ZeroCopySend,
ResponseHeader: Debug + ZeroCopySend,
> ResponseMut<Service, [ResponsePayload], ResponseHeader>
{
pub fn payload(&self) -> &[ResponsePayload] {
self.deref()
}
pub fn payload_mut(&mut self) -> &mut [ResponsePayload] {
&mut *self
}
}
impl<Service: crate::service::Service, ResponsePayload, ResponseHeader: Debug + ZeroCopySend>
ResponseMut<Service, Flatbuffer<ResponsePayload>, ResponseHeader>
{
pub fn payload_bytes(&self) -> &[u8] {
let payload_offset = self.header().payload_offset as usize;
let payload_ptr = self.chunk.payload_ptr();
let payload_len = self.header().number_of_elements as usize;
unsafe {
core::slice::from_raw_parts(
payload_ptr.add(payload_offset),
payload_len - payload_offset,
)
}
}
pub fn payload_root<'a>(
&'a self,
) -> Result<ResponsePayload::Inner, FlatbufferError<InvalidFlatbuffer>>
where
ResponsePayload: flatbuffers::Follow<'a> + flatbuffers::Verifiable,
{
Ok(flatbuffers::root::<ResponsePayload>(self.payload_bytes())?)
}
}