-
Couldn't load subscription status.
- Fork 24
Description
Proposal
Problem statement
There's an inconsistency in the standard library at present: Arc<File> implements Read and Write, whereas Arc<T> for several other Read+Write types do not. In some cases (such as for [u8]), it isn't correct to do so (see links below). But for several others, such as TcpStream and UnixStream, it would be correct.
This proposal stands for the general proposition that, when &T implements Read and Write, and when it would be correct for Arc<T> to implement Read and Write, we should implement Read and Write on Arc<T>. It also stands for the specific proposal to implement Read and Write on Arc<TcpStream> and Arc<UnixStream>.
(See also prior discussions at rust-lang/rust#53835 and rust-lang/rust#94744. I'm opening this ACP because I was asked to at #134190.)
(This is my first ACP; please let me know if I've done it wrong.)
Motivating examples or use cases
This is roughly the use case I have, though others exist:
fn split_stream<T>(stream: T) -> (Box<dyn Read>, Box<dyn Write>)
where T: 'static,
Arc<T>: Read + Write
{
let arc = Arc::new(stream);
(Box::new(arc.clone()), Box::new(arc))
}
// This will work fine:
fn split_file(f:File) -> (Box<dyn Read>, Box<dyn Write>) {
split_stream(f)
// This will fail:
fn split_tcp(f:TcpStream) -> (Box<dyn Read>, Box<dyn Write>) {
split_stream(f)
}
(This is only one possible motivation. Prior discussion suggests that implementing Read and Write on Arc<T>, where it is correct to do so, would be useful in general for reasons of consistency.)
Solution sketch
See PR at rust-lang/rust#134190.
At first glance, this could possibly be extended to these types, though I don't know if there is a reason to do so:
Arc<Stdout>Arc<Stderr>Arc<PipeWriter>Arc<PipeReader>Arc<ChildStdin>Arc<ChildStdout>Arc<Empty>Arc<Sink>
Alternatives
There are numerous other workarounds that work for the motivating example, without changes to the library.
- We can tell the user to use
try_clone(), at the cost of using an extra fd, and creating a fallible API. - We can tell the user to define a wrapper type that implements
Read + WriteonNewType(Arc<T>), specifically for the cases where it is safe to do so. This requires a certain amount of boilerplate. - We can tell the user to define a wrapper type that implements
Read + WriteonNewtype(Arc<Mutex<T>>)for arbitrary T implementingRead + Write. This requires a certain amount of boilerplate, and prevents simultaneous reads and writes.
Within the standard library, there are other approaches for solving the motivating problem.
- The standard library could implement its own version of Tokio's
split_owned, returning a separate ReadHalf and WriteHalf for each current duplex Read+Write type it provides. This might be desirable for other reasons (such as performance), but is orthogonal to this proposal. - The standard library could deprecate and eventually remove the
ReadandWriteimplementations for&Twhenever it is not correct for them to apply toArc<T>. If it did so, it would then be safe to provide a blanketimpl<T> Read for Arc<T> where &T:Read . - The standard library could add a ReadByRef trait (and by analogy a WriteByRef trait) for those types where
&Timplements Read and it is correct to implement Read forArc<T>. It could then provide a blanketimpl<T:ReadByRef> Read for Arc<T>.
Nonetheless, by analogy to the fact that Arc<File> currently implements Read and Write, I think that this approach would probably be the simplest and least controversial approach.
Links and related work
Prior discussions of impl {Read,Write} for Arc<T> where &T: {Read,Write}:
- Provide Read and Write access through Arc<T> if &T: Read/Write rust#53835
- Add
Read,WriteandSeekimpls forArc<T>where appropriate rust#94744
Existing implementation of impl Read,Write for Arc<File>:
- Add
Read,WriteandSeekimpls forArc<File>where appropriate rust#94748 - (See Add
Read,WriteandSeekimpls forArc<File>where appropriate rust#94748 (comment) for a suggestion that this should be extended to other types.)
Proposed implementation for Arc<TcpStream>, Arc<UnixStream>