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.
This commit is contained in:
Martin Habovstiak 2024-08-15 21:23:51 +02:00
parent 54fdcb798b
commit fc7e213f21
2 changed files with 128 additions and 1 deletions

View File

@ -127,3 +127,130 @@ impl<T: std::io::Write> std::io::Write for FromStd<T> {
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>(T);
impl<T> ToStd<T> {
/// 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<T>) -> Box<Self> {
// 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<T: super::Read> std::io::Read for ToStd<T> {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
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<T: super::BufRead> std::io::BufRead for ToStd<T> {
#[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<T: super::Write> std::io::Write for ToStd<T> {
#[inline]
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
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<T: super::Read> super::Read for ToStd<T> {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> super::Result<usize> {
self.0.read(buf)
}
#[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> super::Result<()> {
self.0.read_exact(buf)
}
}
impl<T: super::BufRead> super::BufRead for ToStd<T> {
#[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<T: super::Write> super::Write for ToStd<T> {
#[inline]
fn write(&mut self, buf: &[u8]) -> super::Result<usize> {
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)
}
}

View File

@ -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;