#![allow(unsafe_code)]
use std::mem::ManuallyDrop;
use crate::Frame;
pub struct OwnedMessage<T: 'static> {
value: ManuallyDrop<T>,
frame: ManuallyDrop<Box<Frame>>,
}
impl<T: 'static> Drop for OwnedMessage<T> {
fn drop(&mut self) {
unsafe {
ManuallyDrop::drop(&mut self.value);
ManuallyDrop::drop(&mut self.frame);
}
}
}
impl<T: 'static + facet::Facet<'static>> OwnedMessage<T> {
#[inline]
pub fn try_new<E>(
frame: Frame,
builder: impl FnOnce(&'static [u8]) -> Result<T, E>,
) -> Result<Self, E> {
let variance = T::SHAPE.computed_variance();
assert!(
variance.can_shrink(),
"OwnedMessage<T> requires T to be covariant (lifetime can shrink safely). Type {:?} has variance {:?}",
T::SHAPE.type_identifier,
variance
);
let frame = Box::new(frame);
let payload: &'static [u8] = unsafe {
let bytes = (*frame).payload_bytes();
std::slice::from_raw_parts(bytes.as_ptr(), bytes.len())
};
let value = builder(payload)?;
Ok(Self {
value: ManuallyDrop::new(value),
frame: ManuallyDrop::new(frame),
})
}
#[inline]
pub fn new(frame: Frame, builder: impl FnOnce(&'static [u8]) -> T) -> Self {
Self::try_new(frame, |payload| {
Ok::<_, std::convert::Infallible>(builder(payload))
})
.unwrap_or_else(|e: std::convert::Infallible| match e {})
}
}
impl<T: 'static> OwnedMessage<T> {
#[inline]
pub fn frame(&self) -> &Frame {
&self.frame
}
#[inline]
pub fn value(&self) -> &T {
&self.value
}
#[inline]
pub fn into_frame(mut self) -> Frame {
unsafe {
ManuallyDrop::drop(&mut self.value);
}
let frame = unsafe { ManuallyDrop::take(&mut self.frame) };
std::mem::forget(self);
*frame
}
}
impl<T: 'static> std::ops::Deref for OwnedMessage<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
&self.value
}
}
impl<T: 'static> AsRef<T> for OwnedMessage<T> {
#[inline]
fn as_ref(&self) -> &T {
&self.value
}
}
impl<T: 'static + std::fmt::Debug> std::fmt::Debug for OwnedMessage<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("OwnedMessage")
.field("value", &*self.value)
.finish_non_exhaustive()
}
}