diff --git a/io/src/bridge.rs b/io/src/bridge.rs new file mode 100644 index 000000000..45b0b8cb7 --- /dev/null +++ b/io/src/bridge.rs @@ -0,0 +1,129 @@ +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + +/// A bridging wrapper providing the IO traits for types that already implement `std` IO traits. +#[repr(transparent)] +pub struct FromStd(T); + +impl FromStd { + /// Wraps an IO type. + #[inline] + pub const fn new(inner: T) -> Self { Self(inner) } + + /// Returns the wrapped value. + #[inline] + pub fn into_inner(self) -> T { + self.0 + } + + /// Returns a reference to the wrapped value. + #[inline] + pub fn inner(&self) -> &T { + &self.0 + } + + /// Returns a mutable reference to the wrapped value. + #[inline] + pub fn inner_mut(&mut self) -> &mut T { + &mut self.0 + } + + /// Wraps a mutable reference to IO type. + #[inline] + pub fn new_mut(inner: &mut T) -> &mut Self { + // SAFETY: the type is repr(transparent) and the lifetimes match + unsafe { &mut *(inner as *mut _ as *mut Self) } + } + + /// Wraps a boxed IO type. + #[cfg(feature = "alloc")] + #[inline] + pub fn new_boxed(inner: Box) -> Box { + // SAFETY: the type is repr(transparent) and the pointer is created from Box + unsafe { Box::from_raw(Box::into_raw(inner) as *mut Self) } + } +} + +impl super::Read for FromStd { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> super::Result { + self.0.read(buf).map_err(Into::into) + } + + #[inline] + fn read_exact(&mut self, buf: &mut [u8]) -> super::Result<()> { + self.0.read_exact(buf).map_err(Into::into) + } +} + +impl super::BufRead for FromStd { + #[inline] + fn fill_buf(&mut self) -> super::Result<&[u8]> { + self.0.fill_buf().map_err(Into::into) + } + + #[inline] + fn consume(&mut self, amount: usize) { + self.0.consume(amount) + } +} + +impl super::Write for FromStd { + #[inline] + fn write(&mut self, buf: &[u8]) -> super::Result { + self.0.write(buf).map_err(Into::into) + } + + #[inline] + fn flush(&mut self) -> super::Result<()> { + self.0.flush().map_err(Into::into) + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> super::Result<()> { + self.0.write_all(buf).map_err(Into::into) + } +} + +// We also impl std traits so that mixing the calls is not annoying. + +impl std::io::Read for FromStd { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.0.read(buf) + } + + #[inline] + fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> { + self.0.read_exact(buf) + } +} + +impl std::io::BufRead for FromStd { + #[inline] + fn fill_buf(&mut self) -> std::io::Result<&[u8]> { + self.0.fill_buf() + } + + #[inline] + fn consume(&mut self, amount: usize) { + self.0.consume(amount) + } +} + +impl std::io::Write for FromStd { + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.0.write(buf) + } + + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + self.0.flush() + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> { + self.0.write_all(buf) + } +} diff --git a/io/src/lib.rs b/io/src/lib.rs index e7878625e..2bf1bfd47 100644 --- a/io/src/lib.rs +++ b/io/src/lib.rs @@ -23,6 +23,11 @@ extern crate alloc; mod error; mod macros; +#[cfg(feature = "std")] +mod bridge; + +#[cfg(feature = "std")] +pub use bridge::FromStd; #[cfg(all(not(feature = "std"), feature = "alloc"))] use alloc::vec::Vec; @@ -320,6 +325,24 @@ impl std::io::Write for Sink { #[inline] pub fn sink() -> Sink { Sink } +/// Wraps a `std` IO type to implement the traits from this crate. +/// +/// All methods are passed through converting the errors. +#[cfg(feature = "std")] +#[inline] +pub const fn from_std(std_io: T) -> FromStd { + FromStd::new(std_io) +} + +/// Wraps a mutable reference to `std` IO type to implement the traits from this crate. +/// +/// All methods are passed through converting the errors. +#[cfg(feature = "std")] +#[inline] +pub fn from_std_mut(std_io: &mut T) -> &mut FromStd { + FromStd::new_mut(std_io) +} + #[cfg(test)] mod tests { #[cfg(all(not(feature = "std"), feature = "alloc"))]