use ipc_channel::ipc::IpcSharedMemory;
use serde::{de::Deserializer, de::Error, de::Visitor, ser::Serializer};
use serde::{Deserialize, Serialize};
use std::fmt;
use std::sync::atomic::{AtomicBool, Ordering};
thread_local! {
static IN_PROCSPAWN: AtomicBool = const { AtomicBool::new(false) };
}
struct ResetProcspawn(bool);
impl Drop for ResetProcspawn {
fn drop(&mut self) {
IN_PROCSPAWN.with(|in_procspawn| in_procspawn.swap(self.0, Ordering::Relaxed));
}
}
pub fn with_ipc_mode<F: FnOnce() -> R, R>(f: F) -> R {
let old = IN_PROCSPAWN.with(|in_procspawn| in_procspawn.swap(true, Ordering::Relaxed));
let _dropper = ResetProcspawn(old);
f()
}
pub fn in_ipc_mode() -> bool {
IN_PROCSPAWN.with(|in_procspawn| in_procspawn.load(Ordering::Relaxed))
}
pub struct Shmem {
shmem: IpcSharedMemory,
}
impl fmt::Debug for Shmem {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
struct ByteRepr<'a>(&'a Shmem);
impl<'a> fmt::Debug for ByteRepr<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "b\"")?;
for &byte in self.0.as_bytes() {
if (32..127).contains(&byte) {
write!(f, "{}", byte)?;
} else {
write!(f, "\\x{:02x}", byte)?;
}
}
write!(f, "b\"")?;
Ok(())
}
}
f.debug_tuple("Shmem").field(&ByteRepr(self)).finish()
}
}
impl Shmem {
pub fn from_bytes(bytes: &[u8]) -> Shmem {
Shmem {
shmem: IpcSharedMemory::from_bytes(bytes),
}
}
pub fn as_bytes(&self) -> &[u8] {
&self.shmem
}
}
impl std::ops::Deref for Shmem {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
&self.shmem
}
}
impl Serialize for Shmem {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if in_ipc_mode() {
self.shmem.serialize(serializer)
} else {
serializer.serialize_bytes(self.as_bytes())
}
}
}
struct ShmemVisitor;
impl<'de> Visitor<'de> for ShmemVisitor {
type Value = Shmem;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a borrowed byte array")
}
fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
where
E: Error,
{
Ok(Shmem {
shmem: IpcSharedMemory::from_bytes(v),
})
}
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: Error,
{
Ok(Shmem {
shmem: IpcSharedMemory::from_bytes(v.as_bytes()),
})
}
}
impl<'de> Deserialize<'de> for Shmem {
fn deserialize<D>(deserializer: D) -> Result<Shmem, D::Error>
where
D: Deserializer<'de>,
{
if in_ipc_mode() {
Ok(Shmem {
shmem: IpcSharedMemory::deserialize(deserializer)?,
})
} else {
deserializer.deserialize_bytes(ShmemVisitor)
}
}
}
#[cfg(feature = "json")]
pub use crate::json::Json;