-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
I/O splicing #160
Comments
The proposed DefaultSplice impl can't work for non-blocking file descriptors because it would drop data on the floor every time a I also don't understand why those methods are |
@the8472 Thanks for pointing those out. Those were just oversights and mistakes on my part. Some of it was leftovers from other stuff like where I was exploring specialization. Sorry for the confusion. I yanked the implementation of both built-in splicers out and clarified what they should do at a higher level - probably should've done that from the beginning. I also went through and removed a bunch of other crud left over from previous iterations in the RFC draft itself. Should all be fixed now. |
Can you sketch how it would construct a splicer that turns As a note, several of the motivating issues could be addressed in |
@the8472 I could see it done this way, after adding an extra
This requires zero specialization at all, and should avoid combinatorial explosion. Generics can expand to optimal code, and Hopefully, this explains my intuition.
The mention of non-blocking descriptors and such was in relation to libraries and frameworks like Tokio and async-std, not about the standard library's own use of them. It's intended to be a use case for this extensibility outside the standard library. |
Well, those weren't covered in your initial proposal. That suggests to me that there may be other missing pieces to make this work. Also note that
That would be a hypothetical
Well, the current implementation supports the optimizations even when it is non-empty by draining it first and only then doing the optimized transfer. Additionally I'm still not quite seeing how this would work on the type level. Which chain of Granted, the current implementation leans a lot on having access to internals of all the types as needed because they're all part of the standard library and a generic implementation might have to give up a bit here and there. But that kind of consideration needs to be included if you propose to existing Imo the API is complex enough that it makes sense to prototype it outside std, as happened with the io-lifetimes crate prototyping the |
@the8472 I'm focusing on the high level functionality here, since it's such a complex flow (and really, unavoidably so). I'll see about for now, prototyping this in an external crate, and then coming back once I've actually got something, since you seem to want details almost at the concrete code level before considering anything down that vein. |
Note that I'm not in charge of approving or rejecting ACPs. But I am familiar with those particular APIs. So as far as process goes you should only take my critique as advisory. For existing ACPs of this complexity we usually had a near complete API surface definition. An implementation is not required but that something like If it works and is ergonomic then it would seem like a useful abstraction to me that may have its place in the standard library as a common API between libraries.
If hypothetically specialization were stable and if we supported |
Proposal
Problem statement
std::io::copy
provides a way to do a complete copy, but blocks indefinitely until it's completed. There's no way to portably do partial copies within the standard library, and it's not extensible to other types.Motivation, use-cases
std::io::copy
, is very useful for quick and dirty copying from a readable to a writable. However, it does have some serious limitations:BufRead
. It's not extensible to other types, and more importantly, userland types can't optimize for each other, either.There's also a number of outstanding performance gaps:
Vec<u8>
orVecDeque<u8>
to a file or socket currently involves an intermediate copy, one that's very easily avoidable.VecDeque<u8>
itself only tries to copy one half at a time, when in many cases it could just use a single vectored write. This would make it a lot more viable as a general byte buffer when paired with a&[u8]
reader or&mut [u8]
writer.The RFC draft linked below goes into detail about potential use cases, including some sample code. It's admittedly a bit complex of a proposal.
Solution sketches
Option 1: a
Splicer
trait. This is the primary one due to concerns around whether adding the needed "type" field tostd::fs::File
(and possiblystd::net::TcpStream
) is possible, or if too many packages break due to someone transmuting between those and raw file descriptors somewhere in the dependency chain.Option 2:
splice_to
/splice_from
methods, preferred if adding those fields tostd::fs::File
/possiblystd::net::TcpStream
won't create compatibility concerns.And in either case,
std::io::copy
just splicing instead of a complicated copy in its loop, with the read → write copy fallback being moved to the default splicer.Links and related work
Drafted an RFC here that goes into much gorier detail: https://github.com/dead-claudia/rust-rfcs/blob/io-splice/text/0000-io-splice.md
Decided to file it here first rather than go straight into the RFC process. It's complex enough it'll probably go through an RFC anyways just because of all the cross-cutting concerns.
What happens now?
This issue is part of the libs-api team API change proposal process. Once this issue is filed the libs-api team will review open proposals in its weekly meeting. You should receive feedback within a week or two.
The text was updated successfully, but these errors were encountered: