use crate::stable_with_metadata_of::WithMetadataOf;
use std::{
any::Any,
io::{Seek, Write},
};
#[cfg(target_os = "windows")]
use std::os::windows::{
fs::FileExt,
io::{AsHandle, AsRawHandle, AsRawSocket, AsSocket},
};
#[cfg(target_family = "unix")]
use std::os::{
fd::{AsFd, AsRawFd},
unix::fs::FileExt,
};
pub struct Writer<W: ?Sized> {
write: *mut dyn Write,
vtable: OptTable,
inner: W,
}
#[derive(Clone, Copy, Default)]
struct OptTable {
seek: Option<*mut dyn Seek>,
any: Option<*mut dyn Any>,
#[cfg(target_family = "unix")]
file_ext: Option<*mut dyn FileExt>,
#[cfg(target_family = "unix")]
as_fd: Option<*mut dyn AsFd>,
#[cfg(target_family = "unix")]
as_raw_fd: Option<*mut dyn AsRawFd>,
#[cfg(target_os = "windows")]
file_ext: Option<*mut dyn FileExt>,
#[cfg(target_os = "windows")]
as_handle: Option<*mut dyn AsHandle>,
#[cfg(target_os = "windows")]
as_raw_handle: Option<*mut dyn AsRawHandle>,
#[cfg(target_os = "windows")]
as_socket: Option<*mut dyn AsSocket>,
#[cfg(target_os = "windows")]
as_raw_socket: Option<*mut dyn AsRawSocket>,
}
pub struct WriterBox<'lt> {
inner: Box<dyn Write + 'lt>,
vtable: OptTable,
}
impl<W: Write> Writer<W> {
pub fn new(mut writer: W) -> Self {
let write = lifetime_erase_trait_vtable!((&mut writer): '_ as Write);
Writer {
inner: writer,
write,
vtable: OptTable::default(),
}
}
}
impl<W: ?Sized> Writer<W> {
pub fn get_ref(&self) -> &W {
&self.inner
}
pub fn get_mut(&mut self) -> &mut W {
&mut self.inner
}
pub fn as_mut(&mut self) -> WriterMut<'_> {
let Writer {
inner: _,
write: _,
vtable,
} = *self;
WriterMut {
inner: self.as_write_mut(),
vtable,
}
}
pub fn into_boxed<'lt>(self) -> WriterBox<'lt>
where
W: Sized + 'lt,
{
let Writer {
inner,
write,
vtable,
} = self;
let ptr = Box::into_raw(Box::new(inner));
let ptr = WithMetadataOf::with_metadata_of_on_stable(ptr, write);
let inner = unsafe { Box::from_raw(ptr) };
WriterBox { inner, vtable }
}
}
dyn_setter! {
impl<W> Writer<W> = self as that {
fn set_seek -> Seek = that.vtable.seek;
fn set_any -> Any = that.vtable.any;
}
}
#[cfg(target_family = "unix")]
dyn_setter! {
impl<W> Writer<W> = self as that {
fn set_file_ext -> FileExt = that.vtable.file_ext;
fn set_as_fd -> AsFd = that.vtable.as_fd;
fn set_as_raw_fd -> AsRawFd = that.vtable.as_raw_fd;
}
}
#[cfg(target_os = "windows")]
dyn_setter! {
impl<W> Writer<W> = self as that {
fn set_file_ext -> FileExt = that.vtable.file_ext;
fn set_as_handle -> AsHandle = that.vtable.as_handle;
fn set_as_raw_handle -> AsRawHandle = that.vtable.as_raw_handle;
fn set_as_socket -> AsSocket = that.vtable.as_socket;
fn set_as_raw_socket -> AsRawSocket = that.vtable.as_raw_socket;
}
}
impl<W: ?Sized> Writer<W> {
pub fn as_write(&self) -> &(dyn Write + '_) {
let ptr = &self.inner as *const W;
let local = WithMetadataOf::with_metadata_of_on_stable(ptr, self.write);
unsafe { &*local }
}
pub fn as_write_mut(&mut self) -> &mut (dyn Write + '_) {
let ptr = &mut self.inner as *mut W;
let local = WithMetadataOf::with_metadata_of_on_stable(ptr, self.write);
unsafe { &mut *local }
}
pub fn into_inner(self) -> W
where
W: Sized,
{
self.inner
}
}
dyn_getter! {
impl<W> Writer<W> = self as that {
unsafe const ptr: &that.inner as *const W;
unsafe mut ptr: &mut that.inner as *mut W;
} {
fn as_seek {
mut: fn as_seek_mut
} -> Seek = that.vtable.seek;
fn as_any {
mut: fn as_any_mut
} -> Any = that.vtable.any;
}
}
#[cfg(target_family = "unix")]
dyn_getter! {
impl<W> Writer<W> = self as that {
unsafe const ptr: &that.inner as *const W;
unsafe mut ptr: &mut that.inner as *mut W;
} {
fn as_file_ext -> FileExt = that.vtable.file_ext;
fn as_fd -> AsFd = that.vtable.as_fd;
fn as_raw_fd -> AsRawFd = that.vtable.as_raw_fd;
}
}
#[cfg(target_os = "windows")]
dyn_getter! {
impl<W> Writer<W> = self as that {
unsafe const ptr: &that.inner as *const W;
unsafe mut ptr: &mut that.inner as *mut W;
} {
fn as_file_ext -> FileExt = that.vtable.file_ext;
fn as_handle -> AsHandle = that.vtable.as_handle;
fn as_raw_handle -> AsRawHandle = that.vtable.as_raw_handle;
fn as_socket -> AsSocket = that.vtable.as_socket;
fn as_raw_socket -> AsRawSocket = that.vtable.as_raw_socket;
}
}
pub struct WriterMut<'lt> {
inner: &'lt mut dyn Write,
vtable: OptTable,
}
impl WriterMut<'_> {
pub fn as_write_mut(&mut self) -> &mut (dyn Write + '_) {
&mut *self.inner
}
}
dyn_getter! {
impl WriterMut<'_> = self as that {
unsafe const ptr: that.inner as *const dyn Write;
unsafe mut ptr: that.inner as *mut dyn Write;
} {
fn as_seek {
mut: fn as_seek_mut
} -> Seek = that.vtable.seek;
fn as_any {
mut: fn as_any_mut
} -> Any = that.vtable.any;
}
}
#[cfg(target_family = "unix")]
dyn_getter! {
impl WriterMut<'_> = self as that {
unsafe const ptr: that.inner as *const dyn Write;
unsafe mut ptr: that.inner as *mut dyn Write;
} {
fn as_file_ext -> FileExt = that.vtable.file_ext;
fn as_fd -> AsFd = that.vtable.as_fd;
fn as_raw_fd -> AsRawFd = that.vtable.as_raw_fd;
}
}
#[cfg(target_os = "windows")]
dyn_getter! {
impl WriterMut<'_> = self as that {
unsafe const ptr: that.inner as *const dyn Write;
unsafe mut ptr: that.inner as *mut dyn Write;
} {
fn as_file_ext -> FileExt = that.vtable.file_ext;
fn as_handle -> AsHandle = that.vtable.as_handle;
fn as_raw_handle -> AsRawHandle = that.vtable.as_raw_handle;
fn as_socket -> AsSocket = that.vtable.as_socket;
fn as_raw_socket -> AsRawSocket = that.vtable.as_raw_socket;
}
}
impl WriterBox<'_> {
pub fn as_mut(&mut self) -> WriterMut<'_> {
WriterMut {
vtable: self.vtable,
inner: self.as_read_mut(),
}
}
pub fn as_read_mut(&mut self) -> &mut (dyn Write + '_) {
&mut *self.inner
}
}
dyn_getter! {
impl WriterBox<'_> = self as that {
unsafe const ptr: that.inner.as_ref() as *const dyn Write;
unsafe mut ptr: that.inner.as_mut() as *mut dyn Write;
} {
fn as_seek {
mut: fn as_seek_mut
} -> Seek = that.vtable.seek;
fn as_any {
mut: fn as_any_mut
} -> Any = that.vtable.any;
}
}
#[cfg(target_family = "unix")]
dyn_getter! {
impl WriterBox<'_> = self as that {
unsafe const ptr: that.inner.as_ref() as *const dyn Write;
unsafe mut ptr: that.inner.as_mut() as *mut dyn Write;
} {
fn as_file_ext -> FileExt = that.vtable.file_ext;
fn as_fd -> AsFd = that.vtable.as_fd;
fn as_raw_fd -> AsRawFd = that.vtable.as_raw_fd;
}
}
#[cfg(target_os = "windows")]
dyn_getter! {
impl WriterBox<'_> = self as that {
unsafe const ptr: that.inner.as_ref() as *const dyn Write;
unsafe mut ptr: that.inner.as_mut() as *mut dyn Write;
} {
fn as_file_ext -> FileExt = that.vtable.file_ext;
fn as_handle -> AsHandle = that.vtable.as_handle;
fn as_raw_handle -> AsRawHandle = that.vtable.as_raw_handle;
fn as_socket -> AsSocket = that.vtable.as_socket;
fn as_raw_socket -> AsRawSocket = that.vtable.as_raw_socket;
}
}
impl<'lt, R> From<&'lt mut Writer<R>> for WriterMut<'lt> {
fn from(value: &'lt mut Writer<R>) -> Self {
value.as_mut()
}
}
impl<'lt, R: 'lt> From<Writer<R>> for WriterBox<'lt> {
fn from(value: Writer<R>) -> Self {
value.into_boxed()
}
}
impl<'lt> From<&'lt mut WriterBox<'_>> for WriterMut<'lt> {
fn from(value: &'lt mut WriterBox) -> Self {
value.as_mut()
}
}