Use macro to implement our traits for `std` types

We want to implement the traits for more types which would be tedious
without a macro and it'd risk forgetting to forward some method since
they may be speialized. This also adds previously-forgotten
specializations. It also relaxes the implicit `Sized` bound on
`BufReader` and `BufWriter` in Rust versions above 1.72.
This commit is contained in:
Martin Habovstiak 2024-08-16 10:09:04 +02:00
parent 505ecd8a2e
commit 5e30c9f190
3 changed files with 110 additions and 15 deletions

View File

@ -23,4 +23,4 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs"]
[lints.rust] [lints.rust]
unexpected_cfgs = { level = "deny" } unexpected_cfgs = { level = "deny", check-cfg = ['cfg(rust_v_1_72)'] }

37
io/build.rs Normal file
View File

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

View File

@ -255,17 +255,73 @@ impl<T: super::Write> super::Write for ToStd<T> {
} }
} }
impl<R: std::io::Read> super::Read for std::io::BufReader<R> { macro_rules! impl_our {
#[inline] (impl$(<$($gen:ident $(: $gent:path)?),*>)? Read for $std_type:ty $(where $($where:tt)*)?) => {
fn read(&mut self, buf: &mut [u8]) -> super::Result<usize> { Ok(std::io::Read::read(self, buf)?) } 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)
}
}
};
} }
impl<R: std::io::Read> super::BufRead for std::io::BufReader<R> { #[cfg(rust_v_1_72)]
#[inline] impl_our! {
fn fill_buf(&mut self) -> super::Result<&[u8]> { Ok(std::io::BufRead::fill_buf(self)?) } impl<R: std::io::Read> Read for std::io::BufReader<R> where R: ?Sized
}
#[inline] #[cfg(not(rust_v_1_72))]
fn consume(&mut self, amount: usize) { std::io::BufRead::consume(self, amount) } 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 { impl std::io::Write for super::Sink {
@ -279,10 +335,12 @@ impl std::io::Write for super::Sink {
fn flush(&mut self) -> std::io::Result<()> { Ok(()) } fn flush(&mut self) -> std::io::Result<()> { Ok(()) }
} }
impl<W: std::io::Write> super::Write for std::io::BufWriter<W> { #[cfg(rust_v_1_72)]
#[inline] impl_our! {
fn write(&mut self, buf: &[u8]) -> super::Result<usize> { Ok(std::io::Write::write(self, buf)?) } impl<W: std::io::Write> Write for std::io::BufWriter<W> where W: ?Sized
}
#[inline]
fn flush(&mut self) -> super::Result<()> { Ok(std::io::Write::flush(self)?) } #[cfg(not(rust_v_1_72))]
impl_our! {
impl<W: std::io::Write> Write for std::io::BufWriter<W>
} }