|
1 |
| -- Feature Name: read_all |
| 1 | +- Feature Name: read_exact and read_full |
2 | 2 | - Start Date: 2015-03-15
|
3 | 3 | - RFC PR: (leave this empty)
|
4 | 4 | - Rust Issue: (leave this empty)
|
5 | 5 |
|
6 | 6 | # Summary
|
7 | 7 |
|
8 | 8 | Rust's Write trait has write_all, which attempts to write an entire
|
9 |
| -buffer. This proposal adds read_all, which attempts to read a fixed |
10 |
| -number of bytes into a given buffer. |
| 9 | +buffer. This proposal adds two new methods, read_full and read_exact. |
| 10 | +read_full attempts to read a fixed number of bytes into a given |
| 11 | +buffer, and returns Ok(n) if it succeeds or in the event of EOF. |
| 12 | +read_exact attempts to read a fixed number of bytes into a given |
| 13 | +buffer, and returns Ok(n) if it succeeds and Err(ErrorKind::ShortRead) |
| 14 | +if it fails. |
11 | 15 |
|
12 | 16 | # Motivation
|
13 | 17 |
|
14 |
| -The new read_all method will allow programs to read from disk without |
15 |
| -having to write their own read loops. Most Rust programs which need |
16 |
| -to read from disk will prefer this to the plain read function. Many C |
17 |
| -programs have the same need, and solve it the same way (e.g. git has |
18 |
| -read_in_full). Here's one example of a Rust library doing this: |
| 18 | +The new read_exact method will allow programs to read from disk |
| 19 | +without having to write their own read loops to handle EINTR. Most |
| 20 | +Rust programs which need to read from disk will prefer this to the |
| 21 | +plain read function. Many C programs have the same need, and solve it |
| 22 | +the same way (e.g. git has read_in_full). Here's one example of a |
| 23 | +Rust library doing this: |
19 | 24 | https://github.com/BurntSushi/byteorder/blob/master/src/new.rs#L184
|
20 | 25 |
|
| 26 | +The read_full method is useful the common case of implementing |
| 27 | +buffered reads from a file or socket. In this case, a short read due |
| 28 | +to EOF is an expected outcome, and the caller must check the number of |
| 29 | +bytes returned. |
| 30 | + |
21 | 31 | # Detailed design
|
22 | 32 |
|
23 |
| -The read_all function will take a mutable, borrowed slice of u8 to |
| 33 | +The read_full function will take a mutable, borrowed slice of u8 to |
24 | 34 | read into, and will attempt to fill that entire slice with data.
|
25 | 35 |
|
26 | 36 | It will loop, calling read() once per iteration and attempting to read
|
27 | 37 | the remaining amount of data. If read returns EINTR, the loop will
|
28 | 38 | retry. If there are no more bytes to read (as signalled by a return
|
29 |
| -of Ok(0) from read()), a new error type, ErrorKind::ShortRead(usize), |
30 |
| -will be returned. ShortRead includes the number of bytes successfully |
31 |
| -read. In the event of another error, that error will be |
| 39 | +of Ok(0) from read()), the number of bytes read so far |
| 40 | +will be returned. In the event of another error, that error will be |
32 | 41 | returned. After a read call returns having successfully read some
|
33 | 42 | bytes, the total number of bytes read will be updated. If that total
|
34 |
| -is equal to the size of the buffer, read will return successfully. |
| 43 | +is equal to the size of the buffer, read_full will return successfully. |
| 44 | + |
| 45 | +The read_exact method can be implemented in terms of read_full. |
35 | 46 |
|
36 | 47 | # Drawbacks
|
37 | 48 |
|
38 | 49 | The major weakness of this API (shared with write_all) is that in the
|
39 | 50 | event of an error, there is no way to return the number of bytes that
|
40 |
| -were successfully read before the error. But since that is the design |
41 |
| -of write_all, it makes sense to mimic that design decision for read_all. |
| 51 | +were successfully read before the error. But returning that data |
| 52 | +would require a much more complicated return type, as well as |
| 53 | +requiring more work on the part of callers. |
42 | 54 |
|
43 | 55 | # Alternatives
|
44 | 56 |
|
45 | 57 | One alternative design would return some new kind of Result which
|
46 | 58 | could report the number of bytes sucessfully read before an error.
|
47 |
| -This would be inconsistent with write_all, but arguably more correct. |
48 |
| - |
49 |
| -If we wanted io::ErrorKind to be a smaller type, ErrorKind::ShortRead |
50 |
| -could be unparameterized. But this would reduce the information |
51 |
| -available to calleres. |
52 | 59 |
|
53 |
| -Finally, in the event of a short read, we could return Ok(number of |
54 |
| -bytes read before EOF) instead of an error. But then every user would |
55 |
| -have to check for this case. And it would be inconsistent with |
56 |
| -write_all. |
| 60 | +If we wanted one method instead of two, ErrorKind::ShortRead could be |
| 61 | +parameterized with the number of bytes read before EOF. But this |
| 62 | +would increase the size of ErrorKind. |
57 | 63 |
|
58 | 64 | Or we could leave this out, and let every Rust user write their own
|
59 |
| -read_all function -- like savages. |
| 65 | +read_full or read_exact function, or import a crate of stuff just for |
| 66 | +this one function. |
0 commit comments