From fc7e213f216ca91b40164a37611c0cab5633803a Mon Sep 17 00:00:00 2001 From: Martin Habovstiak Date: Thu, 15 Aug 2024 21:23:51 +0200 Subject: [PATCH] Add `bitcoin-io` -> `std` bridge This adds a reverse of the previous commit however it does not add convenience methods since user should generally prefer the macro instead. I had a clever idea to add a convenience conversion trait but that is blocked by Rust stabilizing overlapping *marker* trait impls. --- io/src/bridge.rs | 127 +++++++++++++++++++++++++++++++++++++++++++++++ io/src/lib.rs | 2 +- 2 files changed, 128 insertions(+), 1 deletion(-) diff --git a/io/src/bridge.rs b/io/src/bridge.rs index 45b0b8cb7..cba47e6bc 100644 --- a/io/src/bridge.rs +++ b/io/src/bridge.rs @@ -127,3 +127,130 @@ impl std::io::Write for FromStd { self.0.write_all(buf) } } + +/// A bridging wrapper providing the std traits for types that already implement our traits. +#[repr(transparent)] +pub struct ToStd(T); + +impl ToStd { + /// 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 std::io::Read for ToStd { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.0.read(buf).map_err(Into::into) + } + + #[inline] + fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> { + self.0.read_exact(buf).map_err(Into::into) + } +} + +impl std::io::BufRead for ToStd { + #[inline] + fn fill_buf(&mut self) -> std::io::Result<&[u8]> { + self.0.fill_buf().map_err(Into::into) + } + + #[inline] + fn consume(&mut self, amount: usize) { + self.0.consume(amount) + } +} + +impl std::io::Write for ToStd { + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.0.write(buf).map_err(Into::into) + } + + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + self.0.flush().map_err(Into::into) + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> { + self.0.write_all(buf).map_err(Into::into) + } +} + +// We also impl our traits so that mixing the calls is not annoying. + +impl super::Read for ToStd { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> super::Result { + self.0.read(buf) + } + + #[inline] + fn read_exact(&mut self, buf: &mut [u8]) -> super::Result<()> { + self.0.read_exact(buf) + } +} + +impl super::BufRead for ToStd { + #[inline] + fn fill_buf(&mut self) -> super::Result<&[u8]> { + self.0.fill_buf() + } + + #[inline] + fn consume(&mut self, amount: usize) { + self.0.consume(amount) + } +} + +impl super::Write for ToStd { + #[inline] + fn write(&mut self, buf: &[u8]) -> super::Result { + self.0.write(buf) + } + + #[inline] + fn flush(&mut self) -> super::Result<()> { + self.0.flush() + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> super::Result<()> { + self.0.write_all(buf) + } +} diff --git a/io/src/lib.rs b/io/src/lib.rs index 2bf1bfd47..581d73289 100644 --- a/io/src/lib.rs +++ b/io/src/lib.rs @@ -27,7 +27,7 @@ mod macros; mod bridge; #[cfg(feature = "std")] -pub use bridge::FromStd; +pub use bridge::{FromStd, ToStd}; #[cfg(all(not(feature = "std"), feature = "alloc"))] use alloc::vec::Vec;