Merge rust-bitcoin/rust-bitcoin#3176: Io improvements
56b19d0601
Add missing IO impls for `std` types (Martin Habovstiak)5e30c9f190
Use macro to implement our traits for `std` types (Martin Habovstiak)505ecd8a2e
Move `std` impl from `lib.rs` to `bridge.rs` (Martin Habovstiak)94768d3f70
Add `set_position` method to `Cursor` (Martin Habovstiak)fc7e213f21
Add `bitcoin-io` -> `std` bridge (Martin Habovstiak)54fdcb798b
Add `std` -> `bitcoin-io` bridge (Martin Habovstiak) Pull request description: This addresses significant API holes. Originally I wanted to add a commit that bumps the IO version but then I remembered we have #3162 which we most likely also want to merge and release. Closes #3174 Closes #3175 ACKs for top commit: apoelstra: ACK56b19d0601
successfully ran local tests tcharding: ACK56b19d0601
Tree-SHA512: 9b0934da8dfd962c916c74032d734583175c6016f514861e24a29179c15925389a506ccf1b784a1bf99bc22909b5e7dcaece5fb689bd32f21ca0112ee798eca5
This commit is contained in:
commit
c00faa0458
|
@ -23,4 +23,4 @@ all-features = true
|
|||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "deny" }
|
||||
unexpected_cfgs = { level = "deny", check-cfg = ['cfg(rust_v_1_72)', 'cfg(rust_v_1_73)', 'cfg(rust_v_1_75)', 'cfg(rust_v_1_78)'] }
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
fn main() {
|
||||
let rustc = std::env::var_os("RUSTC");
|
||||
let rustc = rustc.as_ref().map(std::path::Path::new).unwrap_or_else(|| "rustc".as_ref());
|
||||
let output = std::process::Command::new(rustc)
|
||||
.arg("--version")
|
||||
.output()
|
||||
.unwrap_or_else(|error| panic!("failed to run `{:?} --version`: {:?}", rustc, error));
|
||||
assert!(output.status.success(), "{:?} -- version returned non-zero exit code", rustc);
|
||||
let stdout = String::from_utf8(output.stdout).expect("rustc produced non-UTF-8 output");
|
||||
let version_prefix = "rustc ";
|
||||
if !stdout.starts_with(version_prefix) {
|
||||
panic!("unexpected rustc output: {}", stdout);
|
||||
}
|
||||
|
||||
let version = &stdout[version_prefix.len()..];
|
||||
let end = version.find(&[' ', '-'] as &[_]).unwrap_or(version.len());
|
||||
let version = &version[..end];
|
||||
let mut version_components = version.split('.');
|
||||
let major = version_components.next().unwrap();
|
||||
assert_eq!(major, "1", "unexpected Rust major version");
|
||||
let minor = version_components
|
||||
.next()
|
||||
.unwrap_or("0")
|
||||
.parse::<u64>()
|
||||
.expect("invalid Rust minor version");
|
||||
|
||||
let msrv = std::env::var("CARGO_PKG_RUST_VERSION").unwrap();
|
||||
let mut msrv = msrv.split(".");
|
||||
let msrv_major = msrv.next().unwrap();
|
||||
assert_eq!(msrv_major, "1", "unexpected Rust major version");
|
||||
let msrv_minor = msrv.next().unwrap().parse::<u64>().unwrap();
|
||||
|
||||
// print cfg for all interesting versions less than or equal to minor
|
||||
for version in msrv_minor..=minor {
|
||||
println!("cargo:rustc-cfg=rust_v_1_{}", version);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,541 @@
|
|||
#[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>(T);
|
||||
|
||||
impl<T> FromStd<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: std::io::Read> super::Read for FromStd<T> {
|
||||
#[inline]
|
||||
fn read(&mut self, buf: &mut [u8]) -> super::Result<usize> {
|
||||
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<T: std::io::BufRead> super::BufRead for FromStd<T> {
|
||||
#[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<T: std::io::Write> super::Write for FromStd<T> {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> super::Result<usize> {
|
||||
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<T: std::io::Read> std::io::Read for FromStd<T> {
|
||||
#[inline]
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
self.0.read(buf)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
|
||||
self.0.read_exact(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: std::io::BufRead> std::io::BufRead for FromStd<T> {
|
||||
#[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<T: std::io::Write> std::io::Write for FromStd<T> {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_our {
|
||||
(impl$(<$($gen:ident $(: $gent:path)?),*>)? Read for $std_type:ty $(where $($where:tt)*)?) => {
|
||||
impl$(<$($gen$(: $gent)?),*>)? super::Read for $std_type $(where $($where)*)? {
|
||||
#[inline]
|
||||
fn read(&mut self, buf: &mut [u8]) -> super::Result<usize> {
|
||||
std::io::Read::read(self, buf).map_err(Into::into)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_exact(&mut self, buf: &mut [u8]) -> super::Result<()> {
|
||||
std::io::Read::read_exact(self, buf).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(impl$(<$($gen:ident $(: $gent:path)?),*>)? BufRead for $std_type:ty $(where $($where:tt)*)?) => {
|
||||
impl$(<$($gen$(: $gent)?),*>)? super::BufRead for $std_type $(where $($where)*)? {
|
||||
#[inline]
|
||||
fn fill_buf(&mut self) -> super::Result<&[u8]> {
|
||||
std::io::BufRead::fill_buf(self).map_err(Into::into)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn consume(&mut self, amount: usize) {
|
||||
std::io::BufRead::consume(self, amount)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(impl$(<$($gen:ident $(: $gent:path)?),*>)? Write for $std_type:ty $(where $($where:tt)*)?) => {
|
||||
impl$(<$($gen$(: $gent)?),*>)? super::Write for $std_type $(where $($where)*)? {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> super::Result<usize> {
|
||||
std::io::Write::write(self, buf).map_err(Into::into)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn flush(&mut self) -> super::Result<()> {
|
||||
std::io::Write::flush(self).map_err(Into::into)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_all(&mut self, buf: &[u8]) -> super::Result<()> {
|
||||
std::io::Write::write_all(self, buf).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(rust_v_1_72)]
|
||||
impl_our! {
|
||||
impl<R: std::io::Read> Read for std::io::BufReader<R> where R: ?Sized
|
||||
}
|
||||
|
||||
#[cfg(not(rust_v_1_72))]
|
||||
impl_our! {
|
||||
impl<R: std::io::Read> Read for std::io::BufReader<R>
|
||||
}
|
||||
|
||||
#[cfg(rust_v_1_72)]
|
||||
impl_our! {
|
||||
impl<R: std::io::Read> BufRead for std::io::BufReader<R> where R: ?Sized
|
||||
}
|
||||
|
||||
#[cfg(not(rust_v_1_72))]
|
||||
impl_our! {
|
||||
impl<R: std::io::Read> BufRead for std::io::BufReader<R>
|
||||
}
|
||||
|
||||
impl std::io::Write for super::Sink {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { Ok(buf.len()) }
|
||||
|
||||
#[inline]
|
||||
fn write_all(&mut self, _: &[u8]) -> std::io::Result<()> { Ok(()) }
|
||||
|
||||
#[inline]
|
||||
fn flush(&mut self) -> std::io::Result<()> { Ok(()) }
|
||||
}
|
||||
|
||||
#[cfg(rust_v_1_72)]
|
||||
impl_our! {
|
||||
impl<W: std::io::Write> Write for std::io::BufWriter<W> where W: ?Sized
|
||||
}
|
||||
|
||||
#[cfg(not(rust_v_1_72))]
|
||||
impl_our! {
|
||||
impl<W: std::io::Write> Write for std::io::BufWriter<W>
|
||||
}
|
||||
|
||||
#[cfg(rust_v_1_72)]
|
||||
impl_our! {
|
||||
impl<W: std::io::Write> Write for std::io::LineWriter<W> where W: ?Sized
|
||||
}
|
||||
|
||||
#[cfg(not(rust_v_1_72))]
|
||||
impl_our! {
|
||||
impl<W: std::io::Write> Write for std::io::LineWriter<W>
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl<R: std::io::Read> Read for std::io::Take<R>
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl<R: std::io::BufRead> BufRead for std::io::Take<R>
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl<R1: std::io::Read, R2: std::io::Read> Read for std::io::Chain<R1, R2>
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl<R1: std::io::BufRead, R2: std::io::BufRead> BufRead for std::io::Chain<R1, R2>
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl<T: AsRef<[u8]>> Read for std::io::Cursor<T>
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl<T: AsRef<[u8]>> BufRead for std::io::Cursor<T>
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Write for std::io::Cursor<std::vec::Vec<u8>>
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Write for std::io::Cursor<&'_ mut std::vec::Vec<u8>>
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Write for std::io::Cursor<std::boxed::Box<[u8]>>
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Read for std::io::Empty
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl BufRead for std::io::Empty
|
||||
}
|
||||
|
||||
#[cfg(rust_v_1_73)]
|
||||
impl_our! {
|
||||
impl Write for std::io::Empty
|
||||
}
|
||||
|
||||
// No idea why &Empty impls Write but not Read + BufRead
|
||||
#[cfg(rust_v_1_73)]
|
||||
impl_our! {
|
||||
impl Write for &'_ std::io::Empty
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Read for std::io::Repeat
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Read for std::io::Stdin
|
||||
}
|
||||
|
||||
#[cfg(rust_v_1_78)]
|
||||
impl_our! {
|
||||
impl Read for &'_ std::io::Stdin
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Write for std::io::Stdout
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Write for &'_ std::io::Stdout
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Write for std::io::Stderr
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Write for &'_ std::io::Stderr
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Read for std::io::StdinLock<'_>
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl BufRead for std::io::StdinLock<'_>
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Read for std::fs::File
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Write for std::fs::File
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Read for &'_ std::fs::File
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Write for &'_ std::fs::File
|
||||
}
|
||||
|
||||
#[cfg(rust_v_1_73)]
|
||||
impl_our! {
|
||||
impl Read for std::sync::Arc<std::fs::File>
|
||||
}
|
||||
|
||||
#[cfg(rust_v_1_73)]
|
||||
impl_our! {
|
||||
impl Write for std::sync::Arc<std::fs::File>
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Read for std::net::TcpStream
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Write for std::net::TcpStream
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Read for &'_ std::net::TcpStream
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Write for &'_ std::net::TcpStream
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
impl_our! {
|
||||
impl Read for std::os::unix::net::UnixStream
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
impl_our! {
|
||||
impl Write for std::os::unix::net::UnixStream
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
impl_our! {
|
||||
impl Read for &'_ std::os::unix::net::UnixStream
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
impl_our! {
|
||||
impl Write for &'_ std::os::unix::net::UnixStream
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Read for std::process::ChildStderr
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Read for std::process::ChildStdout
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Write for std::process::ChildStdin
|
||||
}
|
||||
|
||||
// No ide why other &ChildStd* are not implemented
|
||||
impl_our! {
|
||||
impl Write for &'_ std::process::ChildStdin
|
||||
}
|
||||
|
||||
#[cfg(rust_v_1_75)]
|
||||
impl_our! {
|
||||
impl Read for std::collections::VecDeque<u8>
|
||||
}
|
||||
|
||||
#[cfg(rust_v_1_75)]
|
||||
impl_our! {
|
||||
impl BufRead for std::collections::VecDeque<u8>
|
||||
}
|
||||
|
||||
impl_our! {
|
||||
impl Write for std::collections::VecDeque<u8>
|
||||
}
|
|
@ -23,6 +23,11 @@ extern crate alloc;
|
|||
|
||||
mod error;
|
||||
mod macros;
|
||||
#[cfg(feature = "std")]
|
||||
mod bridge;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use bridge::{FromStd, ToStd};
|
||||
|
||||
#[cfg(all(not(feature = "std"), feature = "alloc"))]
|
||||
use alloc::vec::Vec;
|
||||
|
@ -158,12 +163,6 @@ impl Read for &[u8] {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<R: std::io::Read> Read for std::io::BufReader<R> {
|
||||
#[inline]
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> { Ok(std::io::Read::read(self, buf)?) }
|
||||
}
|
||||
|
||||
impl BufRead for &[u8] {
|
||||
#[inline]
|
||||
fn fill_buf(&mut self) -> Result<&[u8]> { Ok(self) }
|
||||
|
@ -173,15 +172,6 @@ impl BufRead for &[u8] {
|
|||
fn consume(&mut self, amount: usize) { *self = &self[amount..] }
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<R: std::io::Read> BufRead for std::io::BufReader<R> {
|
||||
#[inline]
|
||||
fn fill_buf(&mut self) -> Result<&[u8]> { Ok(std::io::BufRead::fill_buf(self)?) }
|
||||
|
||||
#[inline]
|
||||
fn consume(&mut self, amount: usize) { std::io::BufRead::consume(self, amount) }
|
||||
}
|
||||
|
||||
/// Wraps an in memory reader providing the `position` function.
|
||||
pub struct Cursor<T> {
|
||||
inner: T,
|
||||
|
@ -197,11 +187,28 @@ impl<T: AsRef<[u8]>> Cursor<T> {
|
|||
#[inline]
|
||||
pub fn position(&self) -> u64 { self.pos }
|
||||
|
||||
/// Sets the internal position.
|
||||
///
|
||||
/// This method allows seeking within the wrapped memory by setting the position.
|
||||
///
|
||||
/// Note that setting a position that is larger than the buffer length will cause reads to
|
||||
/// return no bytes (EOF).
|
||||
#[inline]
|
||||
pub fn set_position(&mut self, position: u64) {
|
||||
self.pos = position;
|
||||
}
|
||||
|
||||
/// Returns the inner buffer.
|
||||
///
|
||||
/// This is the whole wrapped buffer, including the bytes already read.
|
||||
#[inline]
|
||||
pub fn into_inner(self) -> T { self.inner }
|
||||
|
||||
/// Returns a reference to the inner buffer.
|
||||
///
|
||||
/// This is the whole wrapped buffer, including the bytes already read.
|
||||
#[inline]
|
||||
pub fn inner(&self) -> &T { &self.inner }
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]>> Read for Cursor<T> {
|
||||
|
@ -279,15 +286,6 @@ impl<'a> Write for &'a mut [u8] {
|
|||
fn flush(&mut self) -> Result<()> { Ok(()) }
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<W: std::io::Write> Write for std::io::BufWriter<W> {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize> { Ok(std::io::Write::write(self, buf)?) }
|
||||
|
||||
#[inline]
|
||||
fn flush(&mut self) -> Result<()> { Ok(std::io::Write::flush(self)?) }
|
||||
}
|
||||
|
||||
/// A sink to which all writes succeed. See [`std::io::Sink`] for more info.
|
||||
///
|
||||
/// Created using `io::sink()`.
|
||||
|
@ -304,22 +302,28 @@ impl Write for Sink {
|
|||
fn flush(&mut self) -> Result<()> { Ok(()) }
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::io::Write for Sink {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { Ok(buf.len()) }
|
||||
|
||||
#[inline]
|
||||
fn write_all(&mut self, _: &[u8]) -> std::io::Result<()> { Ok(()) }
|
||||
|
||||
#[inline]
|
||||
fn flush(&mut self) -> std::io::Result<()> { Ok(()) }
|
||||
}
|
||||
|
||||
/// Returns a sink to which all writes succeed. See [`std::io::sink`] for more info.
|
||||
#[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<T>(std_io: T) -> FromStd<T> {
|
||||
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<T>(std_io: &mut T) -> &mut FromStd<T> {
|
||||
FromStd::new_mut(std_io)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[cfg(all(not(feature = "std"), feature = "alloc"))]
|
||||
|
|
Loading…
Reference in New Issue