-
Notifications
You must be signed in to change notification settings - Fork 11
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
Crate redesign #23
Comments
After discussion with @ColinFinck it seems like trying an approach that could be expected to be included in In general, things in Goals
Let's discuss various design decisions one-by-one: Should the
|
Thanks for raising these questions. The goals sound fine and
Absolutely not! That would lead to many use cases employing
I would need to see the full implementation you have in mind before judging on your proposal here.
I agree that
I agree that this topic is up for a later discussion. In particular, it shouldn't be discussed before we have an actual use case. The crates I have in mind, which would benefit from "core::io::Read" and "core::io::Write", all don't need any async support. A minimal "core::io::Read" and "core::io::Write" should only ensure that its design doesn't prevent async support from being added later.
I share the same opinion as for async support on this matter: Without any immediate use case, it's not the right time to discuss vectored I/O now. Again, we should only make sure that vectored I/O can still be added later. |
Yes, it was supposed to be renamed but I didn't have the time to do it yet. Note that I was imprecise in that part and what actually needs to be passed is a buffer with
I intend for them to just have the internal errors wrapped in special error types but open to other possibilities if it turns out to be problematic.
It was not originally planned but since you brought it up I will consider it (but most likely it will be there). While I'm not a huge fan of it I guess I can see its usefulness and reasons why people like it.
The most obvious thing to do is to define
I had a hobby-maybe-serious-later program that would need that but I didn't have time to finish it. Anyway I feel like the current approach in
Agree, I don't see how what I have in mind would prevent good async support.
Here I'm not that confident that we can skip it without introducing similar problems My idea is that if you write a crate that uses |
The strategy can be: don't. What the caller more precisely wants to do is to construct a
Other than that some feedback on the library: Enabling The |
Thanks for feedback!
I'm thinking of something like this: struct ReadFuture<'a, R: Read> {
reader: R,
buffer: &'a mut OutSlice<u8>,
}
// without Pin for simplicity
impl<'a, R: Read> Future for ReadFuture<'a, R> {
type Output = Result<&'a mut [u8], R::Error>;
fn poll(&mut self) -> Poll<Self::Output> {
// API envisioned above
// it's a struct with position: usize and the slice
let mut buffer = self.buffer.as_buffer();
match self.reader.read(&mut buffer) {
// into_initialized returns same lifetime as the slice
Ok(_) => Ok(Poll::Ready(buffer.into_initialized())),
Err(AsyncError::WouldBlock) => Ok(Poll::WouldBlock),
Err(AsyncError::Other(error)) => Err(error),
}
}
} Do you see any problem with it?
Correct, I don't propose to do any registration. Am I missing something?
No, it isn't
How? If allocation is impossible, then |
This is how you can write a specific Future type, and indeed this is possible, but it can not be a trait method. Also note that returning
This integration is inherently impossible to do correctly without an outer event loop (read: OS, or interrupt controller) and also completely unnecessary for the basic read/write trait. |
Regarding async, I don't see why it should be integrated into a core::io::Read trait. It almost certainly needs to be a separate trait, as not every IO source can be read asynchronously, along with the other problems @HeroicKatora mentions. Besides, AsyncRead and friends aren't even in std yet, they live in the various async frameworks, or in the |
There is a conflict of interest here, which also becomes apparent in the custom wrapper for Case in point; the |
This refactors lot of stuff based on knowledge learned over past years and lot of thinking. Apart from obvious details like using `Infallible` or the `alloc` crate, this introduces the concept of maybe uninitialized buffers. Their actual initializedness is tracked as typestate or dynamically as needed. This should enable efficient bridging with `std` among other things. The code contains quite a bit of `unsafe` that needs better auditing and ther's still shitload of work to do but looks like this direction is good. Closes #23
This refactors lot of stuff based on knowledge learned over past years and lot of thinking. Apart from obvious details like using `Infallible` or the `alloc` crate, this introduces the concept of maybe uninitialized buffers. Their actual initializedness is tracked as typestate or dynamically as needed. This should enable efficient bridging with `std` among other things. The code contains quite a bit of `unsafe` that needs better auditing and ther's still shitload of work to do but looks like this direction is good. Closes #23
Oh, WTF, I thought I replied to this. Anyway, I finally found some time to write something and made a not-entirely-finished PR to show the changes. Agree to initially skip Some other things from @HeroicKatora I'd like to address:
Actually, what I proposed above is very similar to that RFC! The only difference was lack of additional field. I dislike the fact that people who may want to use
I don't see any problem with these. It's a cleaner design than having
Well, I did reconsider the third field and decided to make it generic. :) TODOs before release:
|
Rust language made a lot of progress since this crate was created and it'd be great if this crate caught up.
Specifically:
MaybeUninit<[u8]>
is the right way of dealing with possibly uninitialized buffersstd
async
is becoming very popularstd
design and anything that copies it has several limitations that this crate could attempt to solve (by not trying hard to followstd
design):Read
is safe and takes&mut [u8]
. We already haveunsafe
version but it seems that having a safeRead
withread
taking some special, safe type is a better approach. It avoids many issues, including forgetting to specialize the implementation and having moreunsafe
than necessary.read
does. Even weirdly, some vectored impls (e.g. TLS) make programs slower, not faster. While it might be a better design if the impls were fixed, it could be fundamentally impossible. (Not sure.) The resulting design should somehow take this into account.AsyncRead
andAsyncWrite
traits don't exist instd
and there was confusion where they belong. Previously, the design even didn't use such traits which was quite a footgun. We can do better by encodingPending
in the return type, but this needs to be researched to work correctly withInterrupted
.Read
andWrite
traits don't have a way to self-describe their implementor which makes declaring errors that contain this information complicated.Rough proposal:
Of course,
dyn
is sketchy and ideally we don't want it.The text was updated successfully, but these errors were encountered: