use ipc_channel::ipc::IpcSharedMemory;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::cell::RefCell;
use std::ops::Deref;
thread_local! {
static SHMEM_FOR_SERIALIZATION: RefCell<Vec<IpcSharedMemory>> = const { RefCell::new(Vec::new()) };
static SHMEM_FOR_DESERIALIZATION: RefCell<Vec<Option<IpcSharedMemory>>> = const { RefCell::new(Vec::new()) };
}
#[derive(Clone, Debug, PartialEq)]
pub struct SharedMemory(IpcSharedMemory);
impl SharedMemory {
pub fn from_bytes(bytes: &[u8]) -> SharedMemory {
SharedMemory(IpcSharedMemory::from_bytes(bytes))
}
pub fn from_byte(byte: u8, length: usize) -> SharedMemory {
SharedMemory(IpcSharedMemory::from_byte(byte, length))
}
#[inline]
pub unsafe fn deref_mut(&mut self) -> &mut [u8] {
unsafe { self.0.deref_mut() }
}
pub fn take(self) -> Option<Vec<u8>> {
self.0.take()
}
}
impl Deref for SharedMemory {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.0
}
}
impl From<IpcSharedMemory> for SharedMemory {
fn from(shmem: IpcSharedMemory) -> Self {
SharedMemory(shmem)
}
}
impl From<SharedMemory> for IpcSharedMemory {
fn from(shmem: SharedMemory) -> Self {
shmem.0
}
}
impl Serialize for SharedMemory {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let index = SHMEM_FOR_SERIALIZATION.with(|regions| {
let mut regions = regions.borrow_mut();
let idx = regions.len();
regions.push(self.0.clone());
idx
});
index.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for SharedMemory {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let index: usize = Deserialize::deserialize(deserializer)?;
let shmem = SHMEM_FOR_DESERIALIZATION
.with(|regions| {
let mut regions = regions.borrow_mut();
regions
.get_mut(index)
.and_then(Option::take)
.ok_or_else(|| {
format!(
"shared memory region {index} not available \
(have {} regions)",
regions.len()
)
})
})
.map_err(serde::de::Error::custom)?;
Ok(SharedMemory(shmem))
}
}
pub fn clear_shmem_serialization_context() {
SHMEM_FOR_SERIALIZATION.with(|regions| {
regions.borrow_mut().clear();
});
}
pub fn take_shmems_for_send() -> Vec<IpcSharedMemory> {
SHMEM_FOR_SERIALIZATION.with(std::cell::RefCell::take)
}
pub fn set_shmems_for_recv(shmems: Vec<IpcSharedMemory>) {
SHMEM_FOR_DESERIALIZATION.with(|regions| {
*regions.borrow_mut() = shmems.into_iter().map(Some).collect();
});
}
pub fn clear_shmem_deserialization_context() {
SHMEM_FOR_DESERIALIZATION.with(|regions| {
regions.borrow_mut().clear();
});
}