From 5e30c9f1906bd801742d6e50a89ce62a6de9cdbe Mon Sep 17 00:00:00 2001 From: Martin Habovstiak Date: Fri, 16 Aug 2024 10:09:04 +0200 Subject: [PATCH] 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. --- io/Cargo.toml | 2 +- io/build.rs | 37 +++++++++++++++++++++ io/src/bridge.rs | 86 ++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 110 insertions(+), 15 deletions(-) create mode 100644 io/build.rs diff --git a/io/Cargo.toml b/io/Cargo.toml index 292e5022c..852e465c5 100644 --- a/io/Cargo.toml +++ b/io/Cargo.toml @@ -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)'] } diff --git a/io/build.rs b/io/build.rs new file mode 100644 index 000000000..2b741ca0d --- /dev/null +++ b/io/build.rs @@ -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::() + .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::().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); + } +} diff --git a/io/src/bridge.rs b/io/src/bridge.rs index 4ff12fed1..f54530b40 100644 --- a/io/src/bridge.rs +++ b/io/src/bridge.rs @@ -255,17 +255,73 @@ impl super::Write for ToStd { } } -impl super::Read for std::io::BufReader { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> super::Result { Ok(std::io::Read::read(self, 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 { + 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 { + 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 super::BufRead for std::io::BufReader { - #[inline] - fn fill_buf(&mut self) -> super::Result<&[u8]> { Ok(std::io::BufRead::fill_buf(self)?) } +#[cfg(rust_v_1_72)] +impl_our! { + impl Read for std::io::BufReader where R: ?Sized +} - #[inline] - fn consume(&mut self, amount: usize) { std::io::BufRead::consume(self, amount) } +#[cfg(not(rust_v_1_72))] +impl_our! { + impl Read for std::io::BufReader +} + +#[cfg(rust_v_1_72)] +impl_our! { + impl BufRead for std::io::BufReader where R: ?Sized +} + +#[cfg(not(rust_v_1_72))] +impl_our! { + impl BufRead for std::io::BufReader } 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(()) } } -impl super::Write for std::io::BufWriter { - #[inline] - fn write(&mut self, buf: &[u8]) -> super::Result { Ok(std::io::Write::write(self, buf)?) } - - #[inline] - fn flush(&mut self) -> super::Result<()> { Ok(std::io::Write::flush(self)?) } +#[cfg(rust_v_1_72)] +impl_our! { + impl Write for std::io::BufWriter where W: ?Sized +} + +#[cfg(not(rust_v_1_72))] +impl_our! { + impl Write for std::io::BufWriter }