core/io/io_slice.rs
1use crate::fmt;
2use crate::mem::take;
3use crate::ops::{Deref, DerefMut};
4
5cfg_select! {
6 any(
7 target_family = "unix",
8 target_os = "hermit",
9 target_os = "solid_asp3",
10 target_os = "trusty",
11 target_os = "wasi"
12 ) => {
13 #[path = "io_slice/repr_iovec.rs"]
14 mod repr;
15 }
16 target_os = "windows" => {
17 #[path = "io_slice/repr_windows.rs"]
18 mod repr;
19 }
20 target_os = "uefi" => {
21 #[path = "io_slice/repr_uefi.rs"]
22 mod repr;
23 }
24 _ => {
25 #[path = "io_slice/repr_generic.rs"]
26 mod repr;
27 }
28}
29
30/// A buffer type used with `Read::read_vectored`.
31///
32/// It is semantically a wrapper around a `&mut [u8]`, but is guaranteed to be
33/// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on
34/// Windows.
35#[stable(feature = "iovec", since = "1.36.0")]
36#[repr(transparent)]
37pub struct IoSliceMut<'a>(repr::IoSliceMut<'a>);
38
39#[stable(feature = "iovec_send_sync", since = "1.44.0")]
40unsafe impl<'a> Send for IoSliceMut<'a> {}
41
42#[stable(feature = "iovec_send_sync", since = "1.44.0")]
43unsafe impl<'a> Sync for IoSliceMut<'a> {}
44
45#[stable(feature = "iovec", since = "1.36.0")]
46impl<'a> fmt::Debug for IoSliceMut<'a> {
47 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
48 fmt::Debug::fmt(self.0.as_slice(), fmt)
49 }
50}
51
52impl<'a> IoSliceMut<'a> {
53 /// Creates a new `IoSliceMut` wrapping a byte slice.
54 ///
55 /// # Panics
56 ///
57 /// Panics on Windows if the slice is larger than 4GB.
58 #[stable(feature = "iovec", since = "1.36.0")]
59 #[rustc_const_unstable(feature = "io_slice_const", issue = "146459")]
60 #[inline]
61 pub const fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
62 IoSliceMut(repr::IoSliceMut::new(buf))
63 }
64
65 /// Advance the internal cursor of the slice.
66 ///
67 /// Also see [`IoSliceMut::advance_slices`] to advance the cursors of
68 /// multiple buffers.
69 ///
70 /// # Panics
71 ///
72 /// Panics when trying to advance beyond the end of the slice.
73 ///
74 /// # Examples
75 ///
76 /// ```
77 /// use std::io::IoSliceMut;
78 /// use std::ops::Deref;
79 ///
80 /// let mut data = [1; 8];
81 /// let mut buf = IoSliceMut::new(&mut data);
82 ///
83 /// // Mark 3 bytes as read.
84 /// buf.advance(3);
85 /// assert_eq!(buf.deref(), [1; 5].as_ref());
86 /// ```
87 #[stable(feature = "io_slice_advance", since = "1.81.0")]
88 #[rustc_const_unstable(feature = "io_slice_const", issue = "146459")]
89 #[inline]
90 pub const fn advance(&mut self, n: usize) {
91 self.0.advance(n)
92 }
93
94 /// Advance a slice of slices.
95 ///
96 /// Shrinks the slice to remove any `IoSliceMut`s that are fully advanced over.
97 /// If the cursor ends up in the middle of an `IoSliceMut`, it is modified
98 /// to start at that cursor.
99 ///
100 /// For example, if we have a slice of two 8-byte `IoSliceMut`s, and we advance by 10 bytes,
101 /// the result will only include the second `IoSliceMut`, advanced by 2 bytes.
102 ///
103 /// # Panics
104 ///
105 /// Panics when trying to advance beyond the end of the slices.
106 ///
107 /// # Examples
108 ///
109 /// ```
110 /// use std::io::IoSliceMut;
111 /// use std::ops::Deref;
112 ///
113 /// let mut buf1 = [1; 8];
114 /// let mut buf2 = [2; 16];
115 /// let mut buf3 = [3; 8];
116 /// let mut bufs = &mut [
117 /// IoSliceMut::new(&mut buf1),
118 /// IoSliceMut::new(&mut buf2),
119 /// IoSliceMut::new(&mut buf3),
120 /// ][..];
121 ///
122 /// // Mark 10 bytes as read.
123 /// IoSliceMut::advance_slices(&mut bufs, 10);
124 /// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
125 /// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
126 /// ```
127 #[stable(feature = "io_slice_advance", since = "1.81.0")]
128 #[inline]
129 pub fn advance_slices(bufs: &mut &mut [IoSliceMut<'a>], n: usize) {
130 // Number of buffers to remove.
131 let mut remove = 0;
132 // Remaining length before reaching n.
133 let mut left = n;
134 for buf in bufs.iter() {
135 if let Some(remainder) = left.checked_sub(buf.len()) {
136 left = remainder;
137 remove += 1;
138 } else {
139 break;
140 }
141 }
142
143 *bufs = &mut take(bufs)[remove..];
144 if bufs.is_empty() {
145 assert!(left == 0, "advancing io slices beyond their length");
146 } else {
147 bufs[0].advance(left);
148 }
149 }
150
151 /// Get the underlying bytes as a mutable slice with the original lifetime.
152 ///
153 /// # Examples
154 ///
155 /// ```
156 /// #![feature(io_slice_as_bytes)]
157 /// use std::io::IoSliceMut;
158 ///
159 /// let mut data = *b"abcdef";
160 /// let io_slice = IoSliceMut::new(&mut data);
161 /// io_slice.into_slice()[0] = b'A';
162 ///
163 /// assert_eq!(&data, b"Abcdef");
164 /// ```
165 #[unstable(feature = "io_slice_as_bytes", issue = "132818")]
166 pub const fn into_slice(self) -> &'a mut [u8] {
167 self.0.into_slice()
168 }
169}
170
171#[stable(feature = "iovec", since = "1.36.0")]
172impl<'a> Deref for IoSliceMut<'a> {
173 type Target = [u8];
174
175 #[inline]
176 fn deref(&self) -> &[u8] {
177 self.0.as_slice()
178 }
179}
180
181#[stable(feature = "iovec", since = "1.36.0")]
182impl<'a> DerefMut for IoSliceMut<'a> {
183 #[inline]
184 fn deref_mut(&mut self) -> &mut [u8] {
185 self.0.as_mut_slice()
186 }
187}
188
189/// A buffer type used with `Write::write_vectored`.
190///
191/// It is semantically a wrapper around a `&[u8]`, but is guaranteed to be
192/// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on
193/// Windows.
194#[stable(feature = "iovec", since = "1.36.0")]
195#[derive(Copy, Clone)]
196#[repr(transparent)]
197pub struct IoSlice<'a>(repr::IoSlice<'a>);
198
199#[stable(feature = "iovec_send_sync", since = "1.44.0")]
200unsafe impl<'a> Send for IoSlice<'a> {}
201
202#[stable(feature = "iovec_send_sync", since = "1.44.0")]
203unsafe impl<'a> Sync for IoSlice<'a> {}
204
205#[stable(feature = "iovec", since = "1.36.0")]
206impl<'a> fmt::Debug for IoSlice<'a> {
207 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
208 fmt::Debug::fmt(self.0.as_slice(), fmt)
209 }
210}
211
212impl<'a> IoSlice<'a> {
213 /// Creates a new `IoSlice` wrapping a byte slice.
214 ///
215 /// # Panics
216 ///
217 /// Panics on Windows if the slice is larger than 4GB.
218 #[stable(feature = "iovec", since = "1.36.0")]
219 #[rustc_const_unstable(feature = "io_slice_const", issue = "146459")]
220 #[must_use]
221 #[inline]
222 pub const fn new(buf: &'a [u8]) -> IoSlice<'a> {
223 IoSlice(repr::IoSlice::new(buf))
224 }
225
226 /// Advance the internal cursor of the slice.
227 ///
228 /// Also see [`IoSlice::advance_slices`] to advance the cursors of multiple
229 /// buffers.
230 ///
231 /// # Panics
232 ///
233 /// Panics when trying to advance beyond the end of the slice.
234 ///
235 /// # Examples
236 ///
237 /// ```
238 /// use std::io::IoSlice;
239 /// use std::ops::Deref;
240 ///
241 /// let data = [1; 8];
242 /// let mut buf = IoSlice::new(&data);
243 ///
244 /// // Mark 3 bytes as read.
245 /// buf.advance(3);
246 /// assert_eq!(buf.deref(), [1; 5].as_ref());
247 /// ```
248 #[stable(feature = "io_slice_advance", since = "1.81.0")]
249 #[rustc_const_unstable(feature = "io_slice_const", issue = "146459")]
250 #[inline]
251 pub const fn advance(&mut self, n: usize) {
252 self.0.advance(n)
253 }
254
255 /// Advance a slice of slices.
256 ///
257 /// Shrinks the slice to remove any `IoSlice`s that are fully advanced over.
258 /// If the cursor ends up in the middle of an `IoSlice`, it is modified
259 /// to start at that cursor.
260 ///
261 /// For example, if we have a slice of two 8-byte `IoSlice`s, and we advance by 10 bytes,
262 /// the result will only include the second `IoSlice`, advanced by 2 bytes.
263 ///
264 /// # Panics
265 ///
266 /// Panics when trying to advance beyond the end of the slices.
267 ///
268 /// # Examples
269 ///
270 /// ```
271 /// use std::io::IoSlice;
272 /// use std::ops::Deref;
273 ///
274 /// let buf1 = [1; 8];
275 /// let buf2 = [2; 16];
276 /// let buf3 = [3; 8];
277 /// let mut bufs = &mut [
278 /// IoSlice::new(&buf1),
279 /// IoSlice::new(&buf2),
280 /// IoSlice::new(&buf3),
281 /// ][..];
282 ///
283 /// // Mark 10 bytes as written.
284 /// IoSlice::advance_slices(&mut bufs, 10);
285 /// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
286 /// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
287 #[stable(feature = "io_slice_advance", since = "1.81.0")]
288 #[inline]
289 pub fn advance_slices(bufs: &mut &mut [IoSlice<'a>], n: usize) {
290 // Number of buffers to remove.
291 let mut remove = 0;
292 // Remaining length before reaching n. This prevents overflow
293 // that could happen if the length of slices in `bufs` were instead
294 // accumulated. Those slice may be aliased and, if they are large
295 // enough, their added length may overflow a `usize`.
296 let mut left = n;
297 for buf in bufs.iter() {
298 if let Some(remainder) = left.checked_sub(buf.len()) {
299 left = remainder;
300 remove += 1;
301 } else {
302 break;
303 }
304 }
305
306 *bufs = &mut take(bufs)[remove..];
307 if bufs.is_empty() {
308 assert!(left == 0, "advancing io slices beyond their length");
309 } else {
310 bufs[0].advance(left);
311 }
312 }
313
314 /// Get the underlying bytes as a slice with the original lifetime.
315 ///
316 /// This doesn't borrow from `self`, so is less restrictive than calling
317 /// `.deref()`, which does.
318 ///
319 /// # Examples
320 ///
321 /// ```
322 /// #![feature(io_slice_as_bytes)]
323 /// use std::io::IoSlice;
324 ///
325 /// let data = b"abcdef";
326 ///
327 /// let mut io_slice = IoSlice::new(data);
328 /// let tail = &io_slice.as_slice()[3..];
329 ///
330 /// // This works because `tail` doesn't borrow `io_slice`
331 /// io_slice = IoSlice::new(tail);
332 ///
333 /// assert_eq!(io_slice.as_slice(), b"def");
334 /// ```
335 #[unstable(feature = "io_slice_as_bytes", issue = "132818")]
336 pub const fn as_slice(self) -> &'a [u8] {
337 self.0.as_slice()
338 }
339}
340
341#[stable(feature = "iovec", since = "1.36.0")]
342impl<'a> Deref for IoSlice<'a> {
343 type Target = [u8];
344
345 #[inline]
346 fn deref(&self) -> &[u8] {
347 self.0.as_slice()
348 }
349}