use std::{ffi::CString, fmt::Debug, sync::Arc};
use crate::{receiver::RawReceiver, sender::RawSender};
#[derive(PartialEq, Eq)]
pub(crate) enum FrameDataDropGuard {
NullPtr,
Receiver(Option<Arc<RawReceiver>>),
Sender(Option<Arc<RawSender>>),
Box(Box<[u8]>),
CString(CString),
}
unsafe impl Send for FrameDataDropGuard {}
unsafe impl Sync for FrameDataDropGuard {}
impl Debug for FrameDataDropGuard {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NullPtr => write!(f, "NullPtr"),
Self::Receiver(recv) => f.debug_tuple("Receiver").field(recv).finish(),
Self::Sender(sender) => f.debug_tuple("Sender").field(sender).finish(),
Self::Box(data) => write!(f, "Box ({} bytes)", data.len()),
Self::CString(cstr) => write!(f, "CString ({})", cstr.to_string_lossy()),
}
}
}
impl Drop for FrameDataDropGuard {
fn drop(&mut self) {
match self {
Self::Receiver(Some(recv)) => {
panic!(
"Attempted to drop FrameDataDropGuard::Receiver, the frame was not freed correctly: {:?}",
recv
);
}
Self::Sender(Some(sender)) => {
panic!(
"Attempted to drop FrameDataDropGuard::Sender, the frame was not freed correctly: {:?}",
sender
);
}
_ => {}
}
}
}
impl FrameDataDropGuard {
pub fn new_boxed(size: usize) -> (FrameDataDropGuard, *mut u8) {
let mut buf = vec![0u8; size].into_boxed_slice();
let ptr = buf.as_mut_ptr();
(FrameDataDropGuard::Box(buf), ptr)
}
#[inline]
pub fn is_ffi_writable(&self) -> bool {
matches!(self, FrameDataDropGuard::NullPtr)
}
#[inline]
pub fn is_ffi_readable(&self) -> bool {
!matches!(self, FrameDataDropGuard::NullPtr)
}
#[inline]
pub fn is_allocated(&self) -> bool {
!matches!(self, FrameDataDropGuard::NullPtr)
}
#[inline]
pub fn is_from_sdk(&self) -> bool {
matches!(
self,
FrameDataDropGuard::Receiver(_) | FrameDataDropGuard::Sender(_)
)
}
#[inline]
pub fn is_mut(&self) -> bool {
matches!(
self,
FrameDataDropGuard::Box(_) | FrameDataDropGuard::CString(_)
)
}
pub fn reason_for_not_ffi_writable(&self) -> &'static str {
match self {
FrameDataDropGuard::NullPtr => {
panic!("Frame is ffi writable, but trying to get reason why not")
}
FrameDataDropGuard::Receiver(_) => "Already written by receiver",
FrameDataDropGuard::Sender(_) => "Already written by sender",
FrameDataDropGuard::Box(_) => "Data is Boxed, intended to be sent",
FrameDataDropGuard::CString(_) => "Data is CString, intended to be sent",
}
}
pub fn reason_for_not_ffi_readable(&self) -> &'static str {
match self {
FrameDataDropGuard::NullPtr => "Frame is not allocated",
_ => {
panic!("Frame is ffi readable, but trying to get reason why not")
}
}
}
pub fn update_from_sender(&mut self, sender: Arc<RawSender>) {
*self = FrameDataDropGuard::Sender(Some(sender));
}
pub fn update_from_receiver(&mut self, recv: Arc<RawReceiver>) {
*self = FrameDataDropGuard::Receiver(Some(recv));
}
pub unsafe fn drop_buffer(&mut self, raw: &mut impl RawBufferManagement) {
if let FrameDataDropGuard::Receiver(recv) = self
&& let Some(recv) = recv.take()
{
unsafe { raw.drop_with_recv(&recv) }
} else if let FrameDataDropGuard::Sender(sender) = self
&& let Some(sender) = sender.take()
{
unsafe { raw.drop_with_sender(&sender) };
}
*self = FrameDataDropGuard::NullPtr;
}
}
pub(crate) trait RawBufferManagement {
unsafe fn drop_with_recv(&mut self, recv: &Arc<RawReceiver>);
unsafe fn drop_with_sender(&mut self, sender: &Arc<RawSender>);
fn assert_unwritten(&self);
}