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 + Write
onNewType(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 + Write
onNewtype(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
Read
andWrite
implementations for&T
whenever 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
&T
implements 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
,Write
andSeek
impls forArc<T>
where appropriate rust#94744
Existing implementation of impl Read,Write for Arc<File>
:
- Add
Read
,Write
andSeek
impls forArc<File>
where appropriate rust#94748 - (See Add
Read
,Write
andSeek
impls 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>