preserves/implementations/rust/preserves/src/value/magic.rs

65 lines
2.0 KiB
Rust

#![doc(hidden)]
//! A horrifying hack to Serde-serialize [IOValue] instances to Preserves *as themselves*.
//!
//! Frankly I think this portion of the codebase might not survive for long. I can't think of a
//! better way of achieving this, but the drawbacks of having this functionality are *severe*.
//!
//! See <https://gitlab.com/preserves/preserves/-/issues/42>.
use super::repr::IOValue;
pub static MAGIC: &str = "$____Preserves_Serde_Magic";
struct IOValueVisitor;
impl<'de> serde::de::Visitor<'de> for IOValueVisitor {
type Value = IOValue;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "a magic encoding of an embedded Preserves Value")
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
let b = unsafe { Box::from_raw(v as *mut IOValue) };
Ok(*b)
}
}
#[inline(always)]
pub fn output_value<S: serde::Serializer>(serializer: S, v: IOValue) -> Result<S::Ok, S::Error> {
serializer.serialize_newtype_struct(MAGIC, &(Box::into_raw(Box::new(v)) as u64))
}
#[inline(always)]
pub fn input_value<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<IOValue, D::Error> {
deserializer.deserialize_newtype_struct(MAGIC, IOValueVisitor)
}
//---------------------------------------------------------------------------
#[inline]
pub fn receive_output_value<T: ?Sized>(name: &'static str, magic_value: &T) -> Option<IOValue> {
if name == MAGIC {
let b =
unsafe { Box::from_raw(*((magic_value as *const T) as *const u64) as *mut IOValue) };
let v: IOValue = *b;
Some(v)
} else {
None
}
}
#[inline]
pub fn transmit_input_value<F>(name: &'static str, f: F) -> Result<Option<u64>, crate::error::Error>
where
F: FnOnce() -> Result<IOValue, crate::error::Error>,
{
if name == MAGIC {
let b: Box<IOValue> = Box::new(f()?);
Ok(Some(Box::into_raw(b) as u64))
} else {
Ok(None)
}
}