diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 23201f9fc5c94..38d066a696755 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -1,6 +1,9 @@ #[cfg(test)] mod tests; +mod arc; +mod rc; + use crate::alloc::Allocator; use crate::cmp; use crate::fmt; diff --git a/library/std/src/io/impls/arc.rs b/library/std/src/io/impls/arc.rs new file mode 100644 index 0000000000000..de111379f0324 --- /dev/null +++ b/library/std/src/io/impls/arc.rs @@ -0,0 +1,114 @@ +//! Forwarding implementations for Arc + +use crate::fmt; +use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write}; +use alloc::sync::Arc; + +/// Enables forwarding `Read` through an `Arc` +/// +/// This only applies for types such as `File` or `TcpStream` that implement Read +/// on `&T`. The reason is that `Read` normally requires `&mut self`, but mutation +/// through an `Arc` is not generally allowed because the value in the `Arc` may be +/// shared. +#[stable(feature = "io_delegation_rc", since = "1.60.0")] +impl Read for Arc +where + for<'a> &'a T: Read, +{ + #[inline] + fn read(&mut self, buf: &mut [u8]) -> io::Result { + (self as &T).read(buf) + } + + #[inline] + fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + (self as &T).read_buf(buf) + } + + #[inline] + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + (self as &T).read_vectored(bufs) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + (self as &T).is_read_vectored() + } + + #[inline] + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + (self as &T).read_to_end(buf) + } + + #[inline] + fn read_to_string(&mut self, buf: &mut String) -> io::Result { + (self as &T).read_to_string(buf) + } + + #[inline] + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + (self as &T).read_exact(buf) + } +} +/// Enables forwarding `Write` through an `Arc` +/// +/// This only applies for types such as `File` or `TcpStream` that implement Write +/// on `&T`. The reason is that `Write` normally requires `&mut self`, but mutation +/// through an `Arc` is not generally allowed because the value in the `Arc` may be +/// shared. +#[stable(feature = "io_delegation_rc", since = "1.60.0")] +impl Write for Arc +where + for<'a> &'a T: Write, +{ + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + (self as &T).write(buf) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + (self as &T).write_vectored(bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + (self as &T).is_write_vectored() + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + (self as &T).flush() + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + (self as &T).write_all(buf) + } + + #[inline] + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { + (self as &T).write_fmt(fmt) + } +} +/// Enables forwarding `Seek` through an `Arc` +/// +/// This only applies for types such as `File` or `TcpStream` that implement Seek +/// on `&T`. The reason is that `Seek` normally requires `&mut self`, but mutation +/// through an `Arc` is not generally allowed because the value in the `Arc` may be +/// shared. +#[stable(feature = "io_delegation_rc", since = "1.60.0")] +impl Seek for Arc +where + for<'a> &'a T: Seek, +{ + #[inline] + fn seek(&mut self, pos: SeekFrom) -> io::Result { + (self as &T).seek(pos) + } + + #[inline] + fn stream_position(&mut self) -> io::Result { + (self as &T).stream_position() + } +} diff --git a/library/std/src/io/impls/rc.rs b/library/std/src/io/impls/rc.rs new file mode 100644 index 0000000000000..df67ab8522248 --- /dev/null +++ b/library/std/src/io/impls/rc.rs @@ -0,0 +1,114 @@ +//! Forwarding implementations for Rc + +use crate::fmt; +use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write}; +use alloc::rc::Rc; + +/// Enables forwarding `Read` through an `Rc` +/// +/// This only applies for types such as `File` or `TcpStream` that implement Read +/// on `&T`. The reason is that `Read` normally requires `&mut self`, but mutation +/// through an `Rc` is not generally allowed because the value in the `Rc` may be +/// shared. +#[stable(feature = "io_delegation_rc", since = "1.60.0")] +impl Read for Rc +where + for<'a> &'a T: Read, +{ + #[inline] + fn read(&mut self, buf: &mut [u8]) -> io::Result { + (self as &T).read(buf) + } + + #[inline] + fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + (self as &T).read_buf(buf) + } + + #[inline] + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + (self as &T).read_vectored(bufs) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + (self as &T).is_read_vectored() + } + + #[inline] + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + (self as &T).read_to_end(buf) + } + + #[inline] + fn read_to_string(&mut self, buf: &mut String) -> io::Result { + (self as &T).read_to_string(buf) + } + + #[inline] + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + (self as &T).read_exact(buf) + } +} +/// Enables forwarding `Write` through an `Rc` +/// +/// This only applies for types such as `File` or `TcpStream` that implement Write +/// on `&T`. The reason is that `Write` normally requires `&mut self`, but mutation +/// through an `Rc` is not generally allowed because the value in the `Rc` may be +/// shared. +#[stable(feature = "io_delegation_rc", since = "1.60.0")] +impl Write for Rc +where + for<'a> &'a T: Write, +{ + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + (self as &T).write(buf) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + (self as &T).write_vectored(bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + (self as &T).is_write_vectored() + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + (self as &T).flush() + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + (self as &T).write_all(buf) + } + + #[inline] + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { + (self as &T).write_fmt(fmt) + } +} +/// Enables forwarding `Seek` through an `Rc` +/// +/// This only applies for types such as `File` or `TcpStream` that implement Seek +/// on `&T`. The reason is that `Seek` normally requires `&mut self`, but mutation +/// through an `Rc` is not generally allowed because the value in the `Rc` may be +/// shared. +#[stable(feature = "io_delegation_rc", since = "1.60.0")] +impl Seek for Rc +where + for<'a> &'a T: Seek, +{ + #[inline] + fn seek(&mut self, pos: SeekFrom) -> io::Result { + (self as &T).seek(pos) + } + + #[inline] + fn stream_position(&mut self) -> io::Result { + (self as &T).stream_position() + } +} diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index ea49bfe3421d1..cc6b5d4cae8e7 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -602,3 +602,55 @@ fn bench_take_read_buf(b: &mut test::Bencher) { [255; 128].take(64).read_buf(&mut rbuf).unwrap(); }); } + +#[test] +fn forward_arc() { + // Tests forwarding of Read, Write, and Seek through an Arc when &T implements the trait. + + use crate::fs::File; + use crate::io::SeekFrom; + use crate::net::TcpStream; + use crate::sync::Arc; + + // This test is wrapped in a closure to make sure it typechecks + // but we do not run it. + let _ = || { + let stream = TcpStream::connect("localhost:8080").unwrap(); + let mut stream = Arc::new(stream); + let mut buffer = [0; 4]; + stream.read(&mut buffer).unwrap(); + stream.write(&buffer).unwrap(); + }; + + let _ = || { + let file = File::open("foo").unwrap(); + let mut file = Arc::new(file); + file.seek(SeekFrom::Start(10)).unwrap(); + }; +} + +#[test] +fn forward_rc() { + // Tests forwarding of Read, Write, and Seek through an Arc when &T implements the trait. + + use crate::fs::File; + use crate::io::SeekFrom; + use crate::net::TcpStream; + use crate::rc::Rc; + + // This test is wrapped in a closure to make sure it typechecks + // but we do not run it. + let _ = || { + let stream = TcpStream::connect("localhost:8080").unwrap(); + let mut stream = Rc::new(stream); + let mut buffer = [0; 4]; + stream.read(&mut buffer).unwrap(); + stream.write(&buffer).unwrap(); + }; + + let _ = || { + let file = File::open("foo").unwrap(); + let mut file = Rc::new(file); + file.seek(SeekFrom::Start(10)).unwrap(); + }; +}