-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
std::io: migrate ReadBuf to BorrowedBuf/BorrowedCursor #97015
Conversation
Hey! It looks like you've submitted a new PR for the library teams! If this PR contains changes to any Examples of
|
(rust-highfive has picked a reviewer for you, use r? to override) |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
☔ The latest upstream changes (presumably #95770) made this pull request unmergeable. Please resolve the merge conflicts. |
Could you provide, in the PR description, a summary of the new resulting API, without the implementation details? That would be quite useful to skim through the changes 🙏 Here is my own take with a basic impl<'a> From<&'a mut [u8]> for BorrowBuf<'a> {
impl<'a> From<&'a mut [MaybeUninit<u8>]> for BorrowBuf<'a> {
impl<'a> BorrowBuf<'a> {
pub fn capacity(&self) -> usize {
pub fn len(&self) -> usize {
pub fn init_len(&self) -> usize {
pub fn filled(&self) -> &[u8] {
pub fn unfilled<'b>(&'b mut self) -> BorrowCursor<'a, 'b> {
pub fn clear(&mut self) -> &mut Self {
pub unsafe fn set_init(&mut self, n: usize) -> &mut Self {
impl<'a, 'b> BorrowCursor<'a, 'b> {
pub fn clone<'c>(&'c mut self) -> BorrowCursor<'a, 'c> {
pub fn capacity(&self) -> usize {
pub fn written(&self) -> usize {
pub fn init_ref(&self) -> &[u8] {
pub fn init_mut(&mut self) -> &mut [u8] {
pub fn uninit_mut(&mut self) -> &mut [MaybeUninit<u8>] {
pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {
pub unsafe fn advance(&mut self, n: usize) -> &mut Self {
pub fn ensure_init(&mut self) -> &mut Self {
pub unsafe fn set_init(&mut self, n: usize) -> &mut Self {
pub fn append(&mut self, buf: &[u8]) {
Finally, it could be envisioned to add
|
I like the idea of renaming the lifetimes to make them more explanatory, but I'm not sure about this scheme. IMO 'a is the lifetime of the underlying data and 'b is the lifetime of the buffer, but since buffer is such an overloaded term it could be interpreted to mean the underlying data or the BorrowBuf.
This seems reasonable though I'm not sure I've come across it explicitly, is it a documented pattern?
I personally find the reborrow terminology confusing - it seems very jargon-y and we don't use it anywhere in std. I was pretty unhappy with clone because the signature is not the same as a regular clone, but when using the method the reason is nearly always that you want to clone the cursor (i.e., you just want two cursors) rather than because you want to alter the lifetime (that is just a side-effect due to the borrow checker). Again, the r for reborrow idiom is not currently used in std. Is it common? Is it a convention we should encourage in std?
It is not currently possible to get access to the BorrowBuf from the cursor and I that is a feature not a bug. It constrains callees to having write-only access to the buffer.
Likewise, the buffer has read-only access to the buffer (and API for initialisation), the way to get access to the initialised part of the buffer is to get a buffer. This is key to having smaller (hopefully clearer) APIs. |
So the drawback of this approach is that it prevents using the style of:
I'm not sure of the relative value of being able to do this vs the temporaries issues when using the builder pattern. Are there guidelines we follow for this self -> Self vs &mut self -> &mut self trade-off? |
Making |
Sorry for the delay in my answer, @nrc, and thank you for taking my input into consideration 🙏 lifetime names (and position)
Ah interesting; I was seeing pub fn unfilled<'buf>(self: &'buf mut BorrowBuf<'data>) -> BorrowCursor<'buf, 'data>
[regarding the ordering of lifetime params]
Not that I know of, but having a choice of pattern be made consistently is useful, and this ordering is the most suitable one, since:
But just a very tiny nit, of course 🙂 clone or reborrow?
It's very uncommon indeed. But I think it being that uncommon plays a non-negligible role in its own demise, sort to speak: something is jargony if used rarely / only between the savy people. Things such as rust-lang/reference#788 or even this very recent post https://haibane-tenshi.github.io/rust-reborrowing hint at somewhere, in Rust, missing clearer documentation of reborrowing:
In the stdlib, there is one instance where this explicit reborrowing comes in play: impl<'orig> Pin<&'orig mut T> {
fn as_mut<'r>(self: &'r mut Pin<&'orig mut T>) -> Pin<&'r mut T>
and is indeed the reason for needing these pesky See also:
So what I think would benefit the language would be for the Rust book, or some other documentation to be more forthcoming about the reborrowing of With all that being said, if the word reborrow in and of itself, may be too scary for the stdlib to use,
owned or borrowed receiversIn a world with enough fn get_full_buffer<'data>(mut buf: BorrowBuf<'data>) -> &'data mut [u8] {
buf.clear();
let mut cursor = buf.unfilled_mut(); // `self`-based / consumes `buf`
cursor.ensure_init();
cursor.init_mut() // `self`-based
} With the current API, this function is impossible to write. To make it possible, some of the functions would have to become That being said, I've been looking more in detail into how to adapt your API exactly for this purpose, and the only way to achieve it would be with a revamp changing the very point of
I see 👍 in that case, we could consider exposing an extra getter to get that split: fn split_at_unfilled<'buf>(
self: &'buf mut BorrowBuf<'data>,
) -> (&'buf [u8], BorrowCursor<'buf, 'data>)
TL,DRThe API as it is now, seems fine to me ✅, although I'm still not 100% fond of the |
That's an interesting API idea I hadn't considered! Do you have use cases in mind for when one would need to access the filled and unfilled parts at the same time? |
And @rust-lang/libs-api I'd love some feedback for the naming of |
imho this api has the issue addressed in rust-lang/libs-team#65 -- it's missing a way to retrieve the original buffer reference -- admittedly that is less necessary with this API but imho is still quite useful. I suggest adding |
Summary: Added `fbcode` symlinks for `platform010` & `platform010-aarch64` and addressed the following fixes: * Account for stabilized [`#![feature(backtrace)]`](rust-lang/rust#99573) and [`#![feature(generic_associated_types)]`](rust-lang/rust#99573) * Account for removal of [`#![feature(result_into_ok_or_err)]`](rust-lang/rust#100604) * Account for migration of [`std::io::ReadBuf` to `std::io::BorrowBuf|BorrowCursor`](rust-lang/rust#97015) * Account for [`Error` trait move into core](rust-lang/rust#99917) * Account for `#[warn(non_camel_case_types)]` * Various function signature, lifetime requirement changes and lint fixes Reviewed By: zertosh Differential Revision: D40923615 fbshipit-source-id: f7ac2828d74edeae39aae517172207b0ee998a59
Summary: Added `fbcode` symlinks for `platform010` & `platform010-aarch64` and addressed the following fixes: * Account for stabilized [`#![feature(backtrace)]`](rust-lang/rust#99573) and [`#![feature(generic_associated_types)]`](rust-lang/rust#99573) * Account for removal of [`#![feature(result_into_ok_or_err)]`](rust-lang/rust#100604) * Account for migration of [`std::io::ReadBuf` to `std::io::BorrowBuf|BorrowCursor`](rust-lang/rust#97015) * Account for [`Error` trait move into core](rust-lang/rust#99917) * Account for `#[warn(non_camel_case_types)]` * Various function signature, lifetime requirement changes and lint fixes Reviewed By: zertosh Differential Revision: D40923615 fbshipit-source-id: f7ac2828d74edeae39aae517172207b0ee998a59
Summary: Added `fbcode` symlinks for `platform010` & `platform010-aarch64` and addressed the following fixes: * Account for stabilized [`#![feature(backtrace)]`](rust-lang/rust#99573) and [`#![feature(generic_associated_types)]`](rust-lang/rust#99573) * Account for removal of [`#![feature(result_into_ok_or_err)]`](rust-lang/rust#100604) * Account for migration of [`std::io::ReadBuf` to `std::io::BorrowBuf|BorrowCursor`](rust-lang/rust#97015) * Account for [`Error` trait move into core](rust-lang/rust#99917) * Account for `#[warn(non_camel_case_types)]` * Various function signature, lifetime requirement changes and lint fixes Reviewed By: zertosh Differential Revision: D40923615 fbshipit-source-id: f7ac2828d74edeae39aae517172207b0ee998a59
Summary: Added `fbcode` symlinks for `platform010` & `platform010-aarch64` and addressed the following fixes: * Account for stabilized [`#![feature(backtrace)]`](rust-lang/rust#99573) and [`#![feature(generic_associated_types)]`](rust-lang/rust#99573) * Account for removal of [`#![feature(result_into_ok_or_err)]`](rust-lang/rust#100604) * Account for migration of [`std::io::ReadBuf` to `std::io::BorrowBuf|BorrowCursor`](rust-lang/rust#97015) * Account for [`Error` trait move into core](rust-lang/rust#99917) * Account for `#[warn(non_camel_case_types)]` * Various function signature, lifetime requirement changes and lint fixes Reviewed By: zertosh Differential Revision: D40923615 fbshipit-source-id: f7ac2828d74edeae39aae517172207b0ee998a59
Summary: Added `fbcode` symlinks for `platform010` & `platform010-aarch64` and addressed the following fixes: * Account for stabilized [`#![feature(backtrace)]`](rust-lang/rust#99573) and [`#![feature(generic_associated_types)]`](rust-lang/rust#99573) * Account for removal of [`#![feature(result_into_ok_or_err)]`](rust-lang/rust#100604) * Account for migration of [`std::io::ReadBuf` to `std::io::BorrowBuf|BorrowCursor`](rust-lang/rust#97015) * Account for [`Error` trait move into core](rust-lang/rust#99917) * Account for `#[warn(non_camel_case_types)]` * Various function signature, lifetime requirement changes and lint fixes Reviewed By: zertosh Differential Revision: D40923615 fbshipit-source-id: f7ac2828d74edeae39aae517172207b0ee998a59
Summary: Added `fbcode` symlinks for `platform010` & `platform010-aarch64` and addressed the following fixes: * Account for stabilized [`#![feature(backtrace)]`](rust-lang/rust#99573) and [`#![feature(generic_associated_types)]`](rust-lang/rust#99573) * Account for removal of [`#![feature(result_into_ok_or_err)]`](rust-lang/rust#100604) * Account for migration of [`std::io::ReadBuf` to `std::io::BorrowBuf|BorrowCursor`](rust-lang/rust#97015) * Account for [`Error` trait move into core](rust-lang/rust#99917) * Account for `#[warn(non_camel_case_types)]` * Various function signature, lifetime requirement changes and lint fixes Reviewed By: zertosh Differential Revision: D40923615 fbshipit-source-id: f7ac2828d74edeae39aae517172207b0ee998a59
Summary: Added `fbcode` symlinks for `platform010` & `platform010-aarch64` and addressed the following fixes: * Account for stabilized [`#![feature(backtrace)]`](rust-lang/rust#99573) and [`#![feature(generic_associated_types)]`](rust-lang/rust#99573) * Account for removal of [`#![feature(result_into_ok_or_err)]`](rust-lang/rust#100604) * Account for migration of [`std::io::ReadBuf` to `std::io::BorrowBuf|BorrowCursor`](rust-lang/rust#97015) * Account for [`Error` trait move into core](rust-lang/rust#99917) * Account for `#[warn(non_camel_case_types)]` * Various function signature, lifetime requirement changes and lint fixes Reviewed By: zertosh Differential Revision: D40923615 fbshipit-source-id: f7ac2828d74edeae39aae517172207b0ee998a59
Summary: Added `fbcode` symlinks for `platform010` & `platform010-aarch64` and addressed the following fixes: * Account for stabilized [`#![feature(backtrace)]`](rust-lang/rust#99573) and [`#![feature(generic_associated_types)]`](rust-lang/rust#99573) * Account for removal of [`#![feature(result_into_ok_or_err)]`](rust-lang/rust#100604) * Account for migration of [`std::io::ReadBuf` to `std::io::BorrowBuf|BorrowCursor`](rust-lang/rust#97015) * Account for [`Error` trait move into core](rust-lang/rust#99917) * Account for `#[warn(non_camel_case_types)]` * Various function signature, lifetime requirement changes and lint fixes Reviewed By: zertosh Differential Revision: D40923615 fbshipit-source-id: f7ac2828d74edeae39aae517172207b0ee998a59
Summary: Added `fbcode` symlinks for `platform010` & `platform010-aarch64` and addressed the following fixes: * Account for stabilized [`#![feature(backtrace)]`](rust-lang/rust#99573) and [`#![feature(generic_associated_types)]`](rust-lang/rust#99573) * Account for removal of [`#![feature(result_into_ok_or_err)]`](rust-lang/rust#100604) * Account for migration of [`std::io::ReadBuf` to `std::io::BorrowBuf|BorrowCursor`](rust-lang/rust#97015) * Account for [`Error` trait move into core](rust-lang/rust#99917) * Account for `#[warn(non_camel_case_types)]` * Various function signature, lifetime requirement changes and lint fixes Reviewed By: zertosh Differential Revision: D40923615 fbshipit-source-id: f7ac2828d74edeae39aae517172207b0ee998a59
Summary: Added `fbcode` symlinks for `platform010` & `platform010-aarch64` and addressed the following fixes: * Account for stabilized [`#![feature(backtrace)]`](rust-lang/rust#99573) and [`#![feature(generic_associated_types)]`](rust-lang/rust#99573) * Account for removal of [`#![feature(result_into_ok_or_err)]`](rust-lang/rust#100604) * Account for migration of [`std::io::ReadBuf` to `std::io::BorrowBuf|BorrowCursor`](rust-lang/rust#97015) * Account for [`Error` trait move into core](rust-lang/rust#99917) * Account for `#[warn(non_camel_case_types)]` * Various function signature, lifetime requirement changes and lint fixes Reviewed By: zertosh Differential Revision: D40923615 fbshipit-source-id: f7ac2828d74edeae39aae517172207b0ee998a59
Summary: Added `fbcode` symlinks for `platform010` & `platform010-aarch64` and addressed the following fixes: * Account for stabilized [`#![feature(backtrace)]`](rust-lang/rust#99573) and [`#![feature(generic_associated_types)]`](rust-lang/rust#99573) * Account for removal of [`#![feature(result_into_ok_or_err)]`](rust-lang/rust#100604) * Account for migration of [`std::io::ReadBuf` to `std::io::BorrowBuf|BorrowCursor`](rust-lang/rust#97015) * Account for [`Error` trait move into core](rust-lang/rust#99917) * Account for `#[warn(non_camel_case_types)]` * Various function signature, lifetime requirement changes and lint fixes Test Plan: ``` cd ~/fbcode buckify_tp2 ./common/rust/tools/scripts/check_all.sh fbcode -- --local-only ``` Reviewed By: zertosh Differential Revision: D40923615 fbshipit-source-id: f7ac2828d74edeae39aae517172207b0ee998a59
Add back BorrowedBuf::filled_mut This is useful if you want to do some processing on the bytes while still using the BorrowedBuf. The API was removed in rust-lang#97015 with no explanation. The RFC also has it as part of its API, so this just seems like a mistake: [RFC](https://rust-lang.github.io/rfcs/2930-read-buf.html#:~:text=inline%5D%0A%20%20%20%20pub%20fn-,filled_mut,-(%26mut%20self)) ACP: rust-lang/libs-team#139
Add back BorrowedBuf::filled_mut This is useful if you want to do some processing on the bytes while still using the BorrowedBuf. The API was removed in rust-lang/rust#97015 with no explanation. The RFC also has it as part of its API, so this just seems like a mistake: [RFC](https://rust-lang.github.io/rfcs/2930-read-buf.html#:~:text=inline%5D%0A%20%20%20%20pub%20fn-,filled_mut,-(%26mut%20self)) ACP: rust-lang/libs-team#139
Add back BorrowedBuf::filled_mut This is useful if you want to do some processing on the bytes while still using the BorrowedBuf. The API was removed in rust-lang/rust#97015 with no explanation. The RFC also has it as part of its API, so this just seems like a mistake: [RFC](https://rust-lang.github.io/rfcs/2930-read-buf.html#:~:text=inline%5D%0A%20%20%20%20pub%20fn-,filled_mut,-(%26mut%20self)) ACP: rust-lang/libs-team#139
Add back BorrowedBuf::filled_mut This is useful if you want to do some processing on the bytes while still using the BorrowedBuf. The API was removed in rust-lang/rust#97015 with no explanation. The RFC also has it as part of its API, so this just seems like a mistake: [RFC](https://rust-lang.github.io/rfcs/2930-read-buf.html#:~:text=inline%5D%0A%20%20%20%20pub%20fn-,filled_mut,-(%26mut%20self)) ACP: rust-lang/libs-team#139
Add back BorrowedBuf::filled_mut This is useful if you want to do some processing on the bytes while still using the BorrowedBuf. The API was removed in rust-lang/rust#97015 with no explanation. The RFC also has it as part of its API, so this just seems like a mistake: [RFC](https://rust-lang.github.io/rfcs/2930-read-buf.html#:~:text=inline%5D%0A%20%20%20%20pub%20fn-,filled_mut,-(%26mut%20self)) ACP: rust-lang/libs-team#139
|
||
rbuf.add_filled(8); | ||
assert_eq!(rbuf.init_len(), 8); | ||
assert_eq!(rbuf.unfilled().init_ref().len(), 8); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nrc This creates a slice to uninitialized memory (set_init
is called without actually initializing things). Under the rules as written in the reference, this is UB, albeit there are discussions going on whether we really want this to be UB.
Is that deliberate?
This PR replaces
ReadBuf
(used by theRead::read_buf
family of methods) withBorrowBuf
andBorrowCursor
.The general idea is to split
ReadBuf
because its API is large and confusing.BorrowBuf
represents a borrowed buffer which is mostly read-only and (other than for construction) deals only with filled vs unfilled segments. aBorrowCursor
is a mostly write-only view of the unfilled part of aBorrowBuf
which distinguishes between initialized and uninitialized segments. ForRead::read_buf
, the caller would create aBorrowBuf
, then pass aBorrowCursor
toread_buf
.In addition to the major API split, I've made the following smaller changes:
written
method)As well as simplifying the API (IMO), this approach has the following advantages:
read_buf
could swap out theReadBuf
.read_buf
cannot write into the filled part of the buffer, we prevent the filled part shrinking or changing which could cause underflow for the caller or unexpected behaviour.Outline
TODO
Migrate non-unix libs and testsNamingBorrowBuf
orBorrowedBuf
orSliceBuf
? (We might want an owned equivalent for the async IO traits)Should we rename the.readbuf
module? We might keep the name indicate it includes both the buf and cursor variations and someday the owned version too. Or we could change it. It is not publicly exposed, so it is not that importantread_buf
method: we read into the cursor now, so the_buf
suffix is a bit weird.Documentationcc #78485, #94741
supersedes: #95770, #93359
fixes #93305