Skip to content
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

Tracking Issue for RFC 2930 (read-buf) #78485

Open
1 of 5 tasks
nikomatsakis opened this issue Oct 28, 2020 · 42 comments
Open
1 of 5 tasks

Tracking Issue for RFC 2930 (read-buf) #78485

nikomatsakis opened this issue Oct 28, 2020 · 42 comments
Assignees
Labels
A-io Area: std::io, std::fs, std::net and std::path B-RFC-approved Feature: Approved by a merged RFC but not yet implemented. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. Libs-Tracked Libs issues that are tracked on the team's project board. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Oct 28, 2020

This is a tracking issue for the RFC "2930" (rust-lang/rfcs#2930).
The feature gate for the issue is #![feature(read_buf)].

About tracking issues

Tracking issues are used to record the overall progress of implementation.
They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions.
A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature.
Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.

Steps

Unresolved Questions

Implementation history

@nikomatsakis nikomatsakis added B-RFC-approved Feature: Approved by a merged RFC but not yet implemented. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. labels Oct 28, 2020
@nikomatsakis
Copy link
Contributor Author

( cc @rust-lang/libs )

@beepster4096
Copy link
Contributor

I'm interested in working on this.

@rustbot claim

@KodrAus KodrAus added the Libs-Tracked Libs issues that are tracked on the team's project board. label Nov 6, 2020
@beepster4096
Copy link
Contributor

beepster4096 commented Nov 8, 2020

I am slightly confused by the API of ReadBufs. What return type should methods like initialized have: &[u8] or &[IoSlice]? If its the former, how do you know which slices are initialized/filled? If it's the latter, what happens if a slice is partially initialized/filled?

edit: probably I should ask this on zulip instead of github

@sfackler
Copy link
Member

sfackler commented Nov 8, 2020

It would return &[IoSliceMut], and only include the slices that are fully initialized.

@programmerjake
Copy link
Member

It would return &[IoSliceMut], and only include the slices that are fully initialized.

I would have expected it to return (&[IoSliceMut], &[u8]) where it is some number of fully initialized buffers and the initialized portion of the partially initialized buffer.

@sfackler
Copy link
Member

sfackler commented Nov 8, 2020

Sure, that makes sense.

@sfackler
Copy link
Member

sfackler commented Dec 5, 2020

@drmeepster are you still working on this?

@beepster4096
Copy link
Contributor

Yeah, I am. Although I'm currently working on #79607 because I needed it for this.

@beepster4096
Copy link
Contributor

Okay, I can continue working on this now that we have MaybeUninit::write_slice

@sunshowers
Copy link
Contributor

I have a PR to add an inner_mut method to Tokio's implementation of ReadBuf: tokio-rs/tokio#3443. As far as I can tell it's a valid use case that there's no other way to do short of pointer arithmetic, so it may make sense to have this be in upstream Rust's ReadBuf as well.

@erickt
Copy link
Contributor

erickt commented Apr 28, 2021

Have we considered extending ReadBuf to be generic on the type, rather than be constrained to u8? I'm guessing much of ReadBuf is generic over the type.

This came up because I'm looking into fixing some UB in rayon, which is passing around uninitialized &mut [T] in its collect iterator. I think the main thing making rayon use this over a &mut Vec<T> is that it wants to split the output buffer across threads, but there's no safe way to do this without initializing the slice. I'd like to replace this with a safe abstraction that's probably quite similar to the design proposed for ReadBuf (plus a split_at method), so I thought maybe there are other people potentially interested in this functionality.

Going further, it would also be interesting to see if we could rewrite Vec to sit upon ReadBuf.

@djc
Copy link
Contributor

djc commented Apr 28, 2021

@Amanieu
Copy link
Member

Amanieu commented Apr 28, 2021

Note that we now have a spare_capacity_mut method on Vec which gives you a &mut [MaybeUninit<T>] for the uninitialized part of a vector.

@ChayimFriedman2
Copy link
Contributor

Currently, if you Write::write() into BorrowedCursor more space than it can hold, it panics like if you call append(). I'd expect that it write only part of the data for write() and err with ErrorKind::WriteZero for write_all(), like impl Write for &mut [u8] does.

@Pr0methean
Copy link

Pr0methean commented Apr 24, 2023

Could we please have a shared interface trait for Seek::stream_position and BorrowedBuf::len? That would help in adapting library crates such as zip_next to use a BorrowedBuf (which would make it possible to read back one compressed file while writing another without loading the whole file into memory).

@CAD97
Copy link
Contributor

CAD97 commented Jul 7, 2023

I just want to note that while rustc_must_implement_one_of is a prerequisite to stabilizing Read::read_buf, BorrowedBuf/BorrowedCursor are separately useful even without the existence of Read::read_buf, so could be stabilized separately. I happen to be writing some unsafe APIs which could be made meaningfully safer with the use of BorrowedCursor.

@jmillikin
Copy link
Contributor

I'm interested in BorrowedBuf and BorrowedCursor for use in no_std environments. Would it be possible to move them into core and stabilize them separately from the new std::io::{Read,Write} functionality?

The current implementation of those types has no dependency on std, and I'd be happy to send out the PRs if the Rust folks are willing to review them.

fmease added a commit to fmease/rust that referenced this issue Nov 8, 2023
…nic, r=dtolnay

Don't panic in `<BorrowedCursor as io::Write>::write`

Instead of panicking if the BorrowedCursor does not have enough capacity for the whole buffer, just return a short write, [like `<&mut [u8] as io::Write>::write` does](https://doc.rust-lang.org/src/std/io/impls.rs.html#349).

(cc `@ChayimFriedman2` rust-lang#78485 (comment))

(I'm not sure if this needs an ACP? since it's not changing the "API", just what the function does)
bors added a commit to rust-lang-ci/rust that referenced this issue Nov 8, 2023
…c, r=dtolnay

Don't panic in `<BorrowedCursor as io::Write>::write`

Instead of panicking if the BorrowedCursor does not have enough capacity for the whole buffer, just return a short write, [like `<&mut [u8] as io::Write>::write` does](https://doc.rust-lang.org/src/std/io/impls.rs.html#349).

(cc `@ChayimFriedman2` rust-lang#78485 (comment))

(I'm not sure if this needs an ACP? since it's not changing the "API", just what the function does)
github-actions bot pushed a commit to rust-lang/miri that referenced this issue Nov 15, 2023
Don't panic in `<BorrowedCursor as io::Write>::write`

Instead of panicking if the BorrowedCursor does not have enough capacity for the whole buffer, just return a short write, [like `<&mut [u8] as io::Write>::write` does](https://doc.rust-lang.org/src/std/io/impls.rs.html#349).

(cc `@ChayimFriedman2` rust-lang/rust#78485 (comment))

(I'm not sure if this needs an ACP? since it's not changing the "API", just what the function does)
@the8472
Copy link
Member

the8472 commented Nov 23, 2023

The BorrowedCursor documentation could use some polish. It says some slightly contradictory or misleading things. The docs start with

A writeable view of the unfilled portion of a BorrowedBuf.

but the very next paragraph:

Provides access to the initialized and uninitialized parts of the underlying BorrowedBuf.

Looking at the actual implementations makes it obvious that they mostly pass-through and grab slices from the underlying BorrowedBuf and totally ignore the write position (start). The write position is only relevant for written().

@tgross35
Copy link
Contributor

Does core_io_borrowed_buf really need to be a separate feature gate, or could it be rolled into read_buf? Bit confusing that the BorrowedBuf/BorrowedCursor docs all point to #117693 rather than this issue, assuming the same types are designed to work in core.

Also related to @the8472's comment, docs need examples.

lnicola pushed a commit to lnicola/rust-analyzer that referenced this issue Apr 7, 2024
Don't panic in `<BorrowedCursor as io::Write>::write`

Instead of panicking if the BorrowedCursor does not have enough capacity for the whole buffer, just return a short write, [like `<&mut [u8] as io::Write>::write` does](https://doc.rust-lang.org/src/std/io/impls.rs.html#349).

(cc `@ChayimFriedman2` rust-lang/rust#78485 (comment))

(I'm not sure if this needs an ACP? since it's not changing the "API", just what the function does)
@a1phyr
Copy link
Contributor

a1phyr commented Apr 9, 2024

There is something "fun" with read_buf as it is defined today, but I am not sure it was done on purpose: unlike read, it is possible to return both data and an error.
This is possible because the cursor keeps tracks of the read bytes itself, so returning an error is not incompatible with reading bytes.

I don't know if this is expected and it is probably useful, but it might be surprising if some implementations start doing that.

In fact, read_buf_exact documents that it has such a behavior:

If this function returns an error, all bytes read will be appended to cursor.

Something more problematic is that it is impossible to write a correct read implementation on top of read_buf (either the written bytes or the error would have to be discarded).

@ChrisDenton
Copy link
Contributor

Tbh, I think read is in the wrong here. For example, I/O reads very much depends on the behaviour of the underlying OS which we have no control over. Currently we are indeed forced to discard any OS errors if any bytes are read.

RalfJung pushed a commit to RalfJung/rust-analyzer that referenced this issue Apr 27, 2024
Don't panic in `<BorrowedCursor as io::Write>::write`

Instead of panicking if the BorrowedCursor does not have enough capacity for the whole buffer, just return a short write, [like `<&mut [u8] as io::Write>::write` does](https://doc.rust-lang.org/src/std/io/impls.rs.html#349).

(cc `@ChayimFriedman2` rust-lang/rust#78485 (comment))

(I'm not sure if this needs an ACP? since it's not changing the "API", just what the function does)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-io Area: std::io, std::fs, std::net and std::path B-RFC-approved Feature: Approved by a merged RFC but not yet implemented. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. Libs-Tracked Libs issues that are tracked on the team's project board. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests