Skip to content

Commit a768523

Browse files
authored
Add more documentation about error messages. (#1356)
Add an example showing all the different interesting error messages we've seen from `Buffer`, along with ways to fix the errors, and add documentation pointing to the example.
1 parent 220e609 commit a768523

2 files changed

Lines changed: 174 additions & 22 deletions

File tree

examples/buffer_errors.rs

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
//! Fixing errors related to the `Buffer` trait.
2+
//!
3+
//! This example demonstrates some error messages that can come from using the
4+
//! `Buffer` trait and how to fix them.
5+
6+
fn main() {
7+
error_buffer_wrapper();
8+
error_retry_closure();
9+
error_retry_indirect_closure();
10+
error_empty_slice();
11+
error_array_by_value();
12+
}
13+
14+
fn error_buffer_wrapper() {
15+
use rustix::buffer::Buffer;
16+
17+
fn read<B: Buffer<u8>>(_: B) {}
18+
19+
// This is reduced from src/fs/inotify.rs line 177.
20+
struct Wrapper<'a>(&'a mut [u8]);
21+
impl<'a> Wrapper<'a> {
22+
fn read(&mut self) {
23+
// Ideally we'd write this, but it gets:
24+
// "cannot move out of `self` which is behind a mutable reference".
25+
/*
26+
read(self.0);
27+
*/
28+
29+
// The fix: add `&mut *`.
30+
read(&mut *self.0);
31+
}
32+
}
33+
let mut buf = vec![0_u8; 3];
34+
let mut wrapper = Wrapper(&mut buf);
35+
wrapper.read();
36+
}
37+
38+
fn error_retry_closure() {
39+
use rustix::buffer::Buffer;
40+
use rustix::io;
41+
use rustix::io::retry_on_intr;
42+
43+
fn b<B: Buffer<u8>>(_: B) -> io::Result<()> {
44+
Ok(())
45+
}
46+
47+
let mut event_buf = [0; 4];
48+
49+
// Ideally we'd write this, but it gets:
50+
// "cannot move out of `event_buf`, a captured variable in an `FnMut` closure".
51+
/*
52+
let event_buf_slice = event_buf.as_mut_slice();
53+
retry_on_intr(|| b(event_buf_slice)).unwrap();
54+
*/
55+
56+
// The fix: Add `&mut *`.
57+
let event_buf_slice = event_buf.as_mut_slice();
58+
retry_on_intr(|| b(&mut *event_buf_slice)).unwrap();
59+
}
60+
61+
fn error_retry_indirect_closure() {
62+
use rustix::buffer::Buffer;
63+
use rustix::io;
64+
let flag = true;
65+
66+
// This is reduced from the xattr crate, src/sys/linux_macos.rs line 119.
67+
68+
// Ideally we'd write this, but it gets:
69+
// "borrowed data escapes outside of closure".
70+
/*
71+
let func = if flag {
72+
f
73+
} else {
74+
g
75+
};
76+
let _vec = allocate_loop(|buf| func(buf)).unwrap();
77+
*/
78+
79+
// The fix: Move `func` to inside the closure.
80+
let _vec = allocate_loop(|buf| {
81+
let func = if flag { f } else { g };
82+
func(buf)
83+
})
84+
.unwrap();
85+
86+
fn allocate_loop<F: FnMut(&mut [u8]) -> io::Result<usize>>(mut f: F) -> io::Result<Vec<u8>> {
87+
let mut vec: Vec<u8> = Vec::new();
88+
loop {
89+
let ret = f(&mut [])?;
90+
vec.resize(ret, 0);
91+
92+
match f(&mut vec) {
93+
Ok(size) => {
94+
vec.truncate(size);
95+
vec.shrink_to_fit();
96+
return Ok(vec);
97+
}
98+
Err(err) => return Err(err),
99+
}
100+
}
101+
}
102+
fn f<B: Buffer<u8>>(_: B) -> Result<usize, io::Errno> {
103+
Ok(0)
104+
}
105+
fn g<B: Buffer<u8>>(_: B) -> Result<usize, io::Errno> {
106+
Ok(0)
107+
}
108+
}
109+
110+
fn error_empty_slice() {
111+
use rustix::buffer::Buffer;
112+
113+
fn read<B: Buffer<u8>>(_: B) {}
114+
115+
// Functions that take `&mut [u8]` can be passed `&mut []`, but with
116+
// `Buffer` passing `&mut []` gets:
117+
// "type annotations needed".
118+
/*
119+
read(&mut []);
120+
*/
121+
122+
// The fix: make the element type explicit.
123+
read(&mut [0_u8; 0]);
124+
}
125+
126+
fn error_array_by_value() {
127+
use rustix::buffer::Buffer;
128+
129+
fn read<B: Buffer<u8>>(b: B) -> B::Output {
130+
unsafe { b.assume_init(0) }
131+
}
132+
133+
// This code is erroneously attempts to pass a buffer by value, but it
134+
// confusingly gets two error messages:
135+
// "the trait bound `[{integer}; 3]: Buffer<u8>` is not satisfied", and
136+
// "the trait bound `[{integer}; 3]: buffer::private::Sealed<u8>` is not satisfied".
137+
/*
138+
let mut buf = [0, 0, 0];
139+
read(buf);
140+
*/
141+
142+
// The fix: pass the buffer by reference.
143+
let mut buf = [0, 0, 0];
144+
read(&mut buf);
145+
}

src/buffer.rs

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,35 @@ use core::slice;
5858
/// # }
5959
/// ```
6060
///
61-
/// If you see errors like "move occurs because `x` has type `&mut [u8]`,
62-
/// which does not implement the `Copy` trait", replace `x` with `&mut *x`.
61+
/// # Guide to error messages
62+
///
63+
/// Sometimes code using `Buffer` can encounter non-obvious error messages.
64+
/// Here are some we've encountered, along with ways to fix them.
65+
///
66+
/// If you see errors like
67+
/// "cannot move out of `self` which is behind a mutable reference"
68+
/// and
69+
/// "move occurs because `x` has type `&mut [u8]`, which does not implement the `Copy` trait",
70+
/// replace `x` with `&mut *x`. See `confusing_error_buffer_wrapper` in
71+
/// examples/buffer_errors.rs.
72+
///
73+
/// If you see errors like
74+
/// "type annotations needed"
75+
/// and
76+
/// "cannot infer type of the type parameter `Buf` declared on the function `read`",
77+
/// you may need to change a `&mut []` to `&mut [0_u8; 0]`. See
78+
/// `confusing_error_empty_slice` in examples/buffer_errors.rs.
79+
///
80+
/// If you see errors like
81+
/// "the trait bound `[MaybeUninit<u8>; 1]: Buffer<u8>` is not satisfied",
82+
/// add a `&mut` to pass the array by reference instead of by value. See
83+
/// `confusing_error_array_by_value` in examples/buffer_errors.rs.
84+
///
85+
/// If you see errors like
86+
/// "cannot move out of `x`, a captured variable in an `FnMut` closure",
87+
/// try replacing `x` with `&mut *x`, or, if that doesn't work, try moving
88+
/// a `let` into the closure body. See `confusing_error_retry_closure` and
89+
/// `confusing_error_retry_indirect_closure` in examples/buffer_errors.rs.
6390
pub trait Buffer<T>: private::Sealed<T> {}
6491

6592
// Implement `Buffer` for all the types that implement `Sealed`.
@@ -311,26 +338,6 @@ mod tests {
311338
];
312339
let _x: (&mut [u8], &mut [MaybeUninit<u8>]) = read(&input, &mut buf).unwrap();
313340
let _x: (&mut [u8], &mut [MaybeUninit<u8>]) = read(&input, &mut buf[..]).unwrap();
314-
315-
// This is reduced from src/fs/inotify.rs line 177.
316-
struct Wrapper<'a>(&'a mut [u8]);
317-
impl<'a> Wrapper<'a> {
318-
fn read(&mut self) {
319-
let input = std::fs::File::open("Cargo.toml").unwrap();
320-
321-
// Ideally we'd write this.
322-
//let _x: usize = read(&input, self.0).unwrap();
323-
// But we need to write this instead.
324-
let _x: usize = read(&input, &mut *self.0).unwrap();
325-
}
326-
}
327-
let mut buf = vec![0_u8; 3];
328-
let mut wrapper = Wrapper(&mut buf);
329-
wrapper.read();
330-
331-
// Why does this get two error messages?
332-
//let mut buf = [0, 0, 0];
333-
//let _x = read(&input, buf).unwrap();
334341
}
335342

336343
#[cfg(not(windows))]

0 commit comments

Comments
 (0)