use std::mem::{transmute, ManuallyDrop};
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
use crate::de::{Deserialize, SinkHandle};
struct NonuniqueBox<T: ?Sized> {
ptr: NonNull<T>,
}
impl<T> NonuniqueBox<T> {
pub fn new(value: T) -> Self {
NonuniqueBox::from(Box::new(value))
}
}
impl<T: ?Sized> From<Box<T>> for NonuniqueBox<T> {
fn from(boxed: Box<T>) -> Self {
let ptr = Box::into_raw(boxed);
let ptr = unsafe { NonNull::new_unchecked(ptr) };
NonuniqueBox { ptr }
}
}
impl<T: ?Sized> Deref for NonuniqueBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { self.ptr.as_ref() }
}
}
impl<T: ?Sized> DerefMut for NonuniqueBox<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.ptr.as_mut() }
}
}
impl<T: ?Sized> Drop for NonuniqueBox<T> {
fn drop(&mut self) {
let ptr = self.ptr.as_ptr();
let _ = unsafe { Box::from_raw(ptr) };
}
}
pub struct OwnedSink<T> {
storage: NonuniqueBox<Option<T>>,
sink: Option<ManuallyDrop<SinkHandle<'static>>>,
}
impl<T: Deserialize> OwnedSink<T> {
pub fn deserialize() -> OwnedSink<T> {
let mut storage = NonuniqueBox::new(None);
unsafe {
let ptr = transmute::<_, &mut Option<T>>(&mut *storage);
let sink = extend_lifetime!(T::deserialize_into(ptr), SinkHandle<'_>);
OwnedSink {
storage,
sink: Some(ManuallyDrop::new(extend_lifetime!(sink, SinkHandle<'_>))),
}
}
}
#[allow(clippy::should_implement_trait)]
pub fn borrow(&self) -> &SinkHandle<'_> {
unsafe { extend_lifetime!(self.sink.as_ref().unwrap(), &SinkHandle<'_>) }
}
#[allow(clippy::should_implement_trait)]
pub fn borrow_mut(&mut self) -> &mut SinkHandle<'_> {
unsafe { extend_lifetime!(self.sink.as_mut().unwrap(), &mut SinkHandle<'_>) }
}
pub fn take(&mut self) -> Option<T> {
self.storage.take()
}
}
impl<T> Drop for OwnedSink<T> {
fn drop(&mut self) {
unsafe {
if let Some(ref mut sink) = self.sink.take() {
ManuallyDrop::drop(sink);
}
}
}
}