use crate::stable_with_metadata_of::WithMetadataOf;
use std::{
any::Any,
io::{BufRead, Read, Seek},
};
#[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 Reader<R: ?Sized> {
read: *mut dyn Read,
vtable: OptTable,
inner: R,
}
#[derive(Clone, Copy, Default)]
struct OptTable {
seek: Option<*mut dyn Seek>,
buf: Option<*mut dyn BufRead>,
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 ReaderBox<'lt> {
inner: Box<dyn Read + 'lt>,
vtable: OptTable,
}
impl<R: Read> Reader<R> {
pub fn new(mut reader: R) -> Self {
let read = lifetime_erase_trait_vtable!((&mut reader): '_ as Read);
Reader {
inner: reader,
read,
vtable: OptTable::default(),
}
}
}
impl<R: ?Sized> Reader<R> {
pub fn get_ref(&self) -> &R {
&self.inner
}
pub fn get_mut(&mut self) -> &mut R {
&mut self.inner
}
pub fn as_mut(&mut self) -> ReaderMut<'_> {
let Reader {
inner: _,
read: _,
vtable,
} = *self;
ReaderMut {
inner: self.as_read_mut(),
vtable,
}
}
pub fn into_boxed<'lt>(self) -> ReaderBox<'lt>
where
R: Sized + 'lt,
{
let Reader {
inner,
read,
vtable,
} = self;
let ptr = Box::into_raw(Box::new(inner));
let ptr = WithMetadataOf::with_metadata_of_on_stable(ptr, read);
let inner = unsafe { Box::from_raw(ptr) };
ReaderBox { inner, vtable }
}
}
dyn_setter! {
impl<R> Reader<R> = self as that {
fn set_buf -> BufRead = that.vtable.buf;
fn set_seek -> Seek = that.vtable.seek;
fn set_any -> Any = that.vtable.any;
}
}
#[cfg(target_family = "unix")]
dyn_setter! {
impl<R> Reader<R> = 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<R> Reader<R> = 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<R: ?Sized> Reader<R> {
pub fn as_read(&self) -> &(dyn Read + '_) {
let ptr = &self.inner as *const R;
let local = WithMetadataOf::with_metadata_of_on_stable(ptr, self.read);
unsafe { &*local }
}
pub fn as_read_mut(&mut self) -> &mut (dyn Read + '_) {
let ptr = &mut self.inner as *mut R;
let local = WithMetadataOf::with_metadata_of_on_stable(ptr, self.read);
unsafe { &mut *local }
}
pub fn into_inner(self) -> R
where
R: Sized,
{
self.inner
}
}
dyn_getter! {
impl<R> Reader<R> = self as that {
unsafe const ptr: &that.inner as *const R;
unsafe mut ptr: &mut that.inner as *mut R;
} {
fn as_buf {
mut: fn as_buf_mut
} -> BufRead = that.vtable.buf;
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<R> Reader<R> = self as that {
unsafe const ptr: &that.inner as *const R;
unsafe mut ptr: &mut that.inner as *mut R;
} {
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<R> Reader<R> = self as that {
unsafe const ptr: &that.inner as *const R;
unsafe mut ptr: &mut that.inner as *mut R;
} {
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<R: Read> Read for Reader<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.inner.read(buf)
}
fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
self.inner.read_exact(buf)
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> std::io::Result<usize> {
self.inner.read_to_end(buf)
}
fn read_to_string(&mut self, buf: &mut String) -> std::io::Result<usize> {
self.inner.read_to_string(buf)
}
}
pub struct ReaderMut<'lt> {
inner: &'lt mut dyn Read,
vtable: OptTable,
}
impl ReaderMut<'_> {
pub fn as_read_mut(&mut self) -> &mut (dyn Read + '_) {
&mut *self.inner
}
}
dyn_getter! {
impl ReaderMut<'_> = self as that {
unsafe const ptr: that.inner as *const dyn Read;
unsafe mut ptr: that.inner as *mut dyn Read;
} {
fn as_buf {
mut: fn as_buf_mut
} -> BufRead = that.vtable.buf;
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 ReaderMut<'_> = self as that {
unsafe const ptr: that.inner as *const dyn Read;
unsafe mut ptr: that.inner as *mut dyn Read;
} {
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 ReaderMut<'_> = self as that {
unsafe const ptr: &that.inner as *const dyn Read;
unsafe mut ptr: &mut that.inner as *mut dyn Read;
} {
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 ReaderBox<'_> {
pub fn as_mut(&mut self) -> ReaderMut<'_> {
ReaderMut {
vtable: self.vtable,
inner: self.as_read_mut(),
}
}
pub fn as_read_mut(&mut self) -> &mut (dyn Read + '_) {
&mut *self.inner
}
}
dyn_getter! {
impl ReaderBox<'_> = self as that {
unsafe const ptr: that.inner.as_ref() as *const dyn Read;
unsafe mut ptr: that.inner.as_mut() as *mut dyn Read;
} {
fn as_buf {
mut: fn as_buf_mut
} -> BufRead = that.vtable.buf;
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 ReaderBox<'_> = self as that {
unsafe const ptr: that.inner.as_ref() as *const _;
unsafe mut ptr: that.inner.as_mut() as *mut _;
} {
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 ReaderBox<'_> = self as that {
unsafe const ptr: that.inner.as_ref() as *const dyn Read;
unsafe mut ptr: that.inner.as_mut() as *mut dyn Read;
} {
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 Reader<R>> for ReaderMut<'lt> {
fn from(value: &'lt mut Reader<R>) -> Self {
value.as_mut()
}
}
impl<'lt, R: 'lt> From<Reader<R>> for ReaderBox<'lt> {
fn from(value: Reader<R>) -> Self {
value.into_boxed()
}
}
impl<'lt> From<&'lt mut ReaderBox<'_>> for ReaderMut<'lt> {
fn from(value: &'lt mut ReaderBox<'_>) -> Self {
value.as_mut()
}
}