Skip to content

std::io::Read::read_to_end does not specialize for &[u8] or Take<&'a [u8]> #44819

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

Open
fulmicoton opened this issue Sep 25, 2017 · 5 comments
Open
Labels
A-io Area: `std::io`, `std::fs`, `std::net` and `std::path` C-enhancement Category: An issue proposing an enhancement or a PR with one. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Comments

@fulmicoton
Copy link

read_to_end currently includes some logic to do exponentially large .resize / .read operations.

For &[u8] or Take<&'a [u8]>, the problem is much simpler as we know the size that will be required :

v.extend_from_slice(&data);
let n = v.len();
data = &data[n..];

The manual implementation is typically between 3 and 5 times faster on my computer.

Assuming what seems a non-pathological case : no resize required, the Vec has a sufficient capacity to begin with, and running the following benchmark https://gist.github.com/fulmicoton/a1fb87c3f3578f118552917636c95933
yields the following result :

test tests::bench_read_manual ... bench:           9 ns/iter (+/- 1)
test tests::bench_read_std    ... bench:          35 ns/iter (+/- 6)
@fulmicoton
Copy link
Author

A simple solution would be to specialize .read_to_end for those types.

Alternatively, we could also expose a public trait similar in spirit to TrustedLen for iterators, and implement the specialization for this new trait. It seems a bit overkill to expose another Trait for this though.

Currently, libstd does not enable on the #![feature(specialization)] feature.
Other crates of rust (liballoc for instance), already enable it. Is there a case against doing it yet?

@sfackler
Copy link
Member

No, there's no reason we can't enable specialization in libstd.

I don't think specialization is required for the &[u8] case though.

@fulmicoton
Copy link
Author

@sfackler By which you mean it is not used / not worth it?

@sfackler
Copy link
Member

No - you can just add a read_to_end implementation in the impl<'a> Read for &'a [u8] { ... }.

@fulmicoton
Copy link
Author

Oh yes that is true :)

@TimNN TimNN added C-enhancement Category: An issue proposing an enhancement or a PR with one. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels Sep 26, 2017
kennytm added a commit to kennytm/rust that referenced this issue Oct 8, 2017
Add read_to_end implementation to &[u8]'s Read impl

The default impl for read_to_end does a bunch of bookkeeping
that isn't necessary for slices and is about 4 times slower
on my machine.

The following benchmark takes about 30 ns before this change and about 7 ns after:

```
#[bench]
fn bench_read_std(b: &mut Bencher) {
    let data = vec![0u8; 100];
    let mut v = Vec::with_capacity(200);
    b.iter(|| {
        let mut s = data.as_slice();
        v.clear();
        s.read_to_end(&mut v).unwrap();
    });
}
```

This solves the easy part of  rust-lang#44819 (I think extending this to `Take<&[u8]> `would require specialization)
@Enselic Enselic added T-libs Relevant to the library team, which will review and decide on the PR/issue. A-io Area: `std::io`, `std::fs`, `std::net` and `std::path` and removed T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels Sep 26, 2023
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` C-enhancement Category: An issue proposing an enhancement or a PR with one. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants