1use io_lifetimes::{AsFilelike, AsSocketlike};
2use std::fmt::Arguments;
3use std::io::{self, IoSlice, IoSliceMut, Read, Write};
4use std::slice;
5
6pub trait IoExt {
9 fn read(&self, buf: &mut [u8]) -> io::Result<usize>;
17
18 fn read_exact(&self, buf: &mut [u8]) -> io::Result<()>;
25
26 fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize>;
33
34 fn read_exact_vectored(&self, mut bufs: &mut [IoSliceMut]) -> io::Result<()> {
36 bufs = skip_leading_empties(bufs);
37 while !bufs.is_empty() {
38 match self.read_vectored(bufs) {
39 Ok(0) => {
40 return Err(io::Error::new(
41 io::ErrorKind::UnexpectedEof,
42 "failed to fill whole buffer",
43 ))
44 }
45 Ok(nread) => bufs = advance_mut(bufs, nread),
46 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => (),
47 Err(e) => return Err(e),
48 }
49 bufs = skip_leading_empties(bufs);
50 }
51 Ok(())
52 }
53
54 fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize>;
61
62 fn read_to_string(&self, buf: &mut String) -> io::Result<usize>;
69
70 fn peek(&self, buf: &mut [u8]) -> io::Result<usize>;
76
77 fn write(&self, buf: &[u8]) -> io::Result<usize>;
84
85 fn write_all(&self, buf: &[u8]) -> io::Result<()>;
92
93 fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize>;
100
101 fn write_all_vectored(&self, mut bufs: &mut [IoSlice]) -> io::Result<()> {
103 while !bufs.is_empty() {
106 match self.write_vectored(bufs) {
107 Ok(nwritten) => bufs = advance(bufs, nwritten),
108 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => (),
109 Err(e) => return Err(e),
110 }
111 }
112 Ok(())
113 }
114
115 fn write_fmt(&self, fmt: Arguments) -> io::Result<()>;
123
124 fn flush(&self) -> io::Result<()>;
132}
133
134fn skip_leading_empties<'a, 'b>(mut bufs: &'b mut [IoSliceMut<'a>]) -> &'b mut [IoSliceMut<'a>] {
136 while !bufs.is_empty() {
137 if !bufs[0].is_empty() {
138 break;
139 }
140 bufs = &mut bufs[1..];
141 }
142 bufs
143}
144
145fn advance<'a, 'b>(bufs: &'b mut [IoSlice<'a>], n: usize) -> &'b mut [IoSlice<'a>] {
149 let mut remove = 0;
151 let mut accumulated_len = 0;
153 for buf in bufs.iter() {
154 if accumulated_len + buf.len() > n {
155 break;
156 } else {
157 accumulated_len += buf.len();
158 remove += 1;
159 }
160 }
161
162 #[allow(clippy::indexing_slicing)]
163 let bufs = &mut bufs[remove..];
164 if let Some(first) = bufs.first_mut() {
165 let advance_by = n - accumulated_len;
166 let mut ptr = first.as_ptr();
167 let mut len = first.len();
168 unsafe {
169 ptr = ptr.add(advance_by);
170 len -= advance_by;
171 *first = IoSlice::<'a>::new(slice::from_raw_parts::<'a>(ptr, len));
172 }
173 }
174 bufs
175}
176
177fn advance_mut<'a, 'b>(bufs: &'b mut [IoSliceMut<'a>], n: usize) -> &'b mut [IoSliceMut<'a>] {
181 let mut remove = 0;
183 let mut accumulated_len = 0;
185 for buf in bufs.iter() {
186 if accumulated_len + buf.len() > n {
187 break;
188 } else {
189 accumulated_len += buf.len();
190 remove += 1;
191 }
192 }
193
194 #[allow(clippy::indexing_slicing)]
195 let bufs = &mut bufs[remove..];
196 if let Some(first) = bufs.first_mut() {
197 let advance_by = n - accumulated_len;
198 let mut ptr = first.as_mut_ptr();
199 let mut len = first.len();
200 unsafe {
201 ptr = ptr.add(advance_by);
202 len -= advance_by;
203 *first = IoSliceMut::<'a>::new(slice::from_raw_parts_mut::<'a>(ptr, len));
204 }
205 }
206 bufs
207}
208
209#[cfg(not(windows))]
211impl<T: AsFilelike + AsSocketlike> IoExt for T {
212 #[inline]
213 fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
214 Read::read(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
215 }
216
217 #[inline]
218 fn read_exact(&self, buf: &mut [u8]) -> io::Result<()> {
219 Read::read_exact(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
220 }
221
222 #[inline]
223 fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
224 Read::read_vectored(&mut &*self.as_filelike_view::<std::fs::File>(), bufs)
225 }
226
227 #[inline]
228 fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
229 Read::read_to_end(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
230 }
231
232 #[inline]
233 fn read_to_string(&self, buf: &mut String) -> io::Result<usize> {
234 Read::read_to_string(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
235 }
236
237 #[inline]
238 fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
239 match self.as_socketlike_view::<std::net::TcpStream>().peek(buf) {
240 Err(err) if err.raw_os_error() == Some(rustix::io::Errno::NOTSOCK.raw_os_error()) => {
241 match self.as_filelike_view::<std::fs::File>().peek(buf) {
242 Err(err)
243 if err.raw_os_error() == Some(rustix::io::Errno::SPIPE.raw_os_error()) =>
244 {
245 Ok(0)
246 }
247 otherwise => otherwise,
248 }
249 }
250 otherwise => otherwise,
251 }
252 }
253
254 #[inline]
255 fn write(&self, buf: &[u8]) -> io::Result<usize> {
256 Write::write(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
257 }
258
259 #[inline]
260 fn write_all(&self, buf: &[u8]) -> io::Result<()> {
261 Write::write_all(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
262 }
263
264 #[inline]
265 fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize> {
266 Write::write_vectored(&mut &*self.as_filelike_view::<std::fs::File>(), bufs)
267 }
268
269 #[inline]
270 fn flush(&self) -> io::Result<()> {
271 Write::flush(&mut &*self.as_filelike_view::<std::fs::File>())
272 }
273
274 #[inline]
275 fn write_fmt(&self, fmt: Arguments) -> io::Result<()> {
276 Write::write_fmt(&mut &*self.as_filelike_view::<std::fs::File>(), fmt)
277 }
278}
279
280#[cfg(windows)]
281impl IoExt for std::fs::File {
282 #[inline]
283 fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
284 Read::read(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
285 }
286
287 #[inline]
288 fn read_exact(&self, buf: &mut [u8]) -> io::Result<()> {
289 Read::read_exact(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
290 }
291
292 #[inline]
293 fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
294 Read::read_vectored(&mut &*self.as_filelike_view::<std::fs::File>(), bufs)
295 }
296
297 #[inline]
298 fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
299 Read::read_to_end(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
300 }
301
302 #[inline]
303 fn read_to_string(&self, buf: &mut String) -> io::Result<usize> {
304 Read::read_to_string(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
305 }
306
307 #[inline]
308 fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
309 use std::os::windows::io::AsRawHandle;
310
311 let mut bytes_read = std::mem::MaybeUninit::<u32>::uninit();
312 let len = std::cmp::min(buf.len(), u32::MAX as usize) as u32;
313 let res = unsafe {
314 windows_sys::Win32::System::Pipes::PeekNamedPipe(
315 self.as_filelike().as_raw_handle() as _,
316 buf.as_mut_ptr() as *mut std::ffi::c_void,
317 len,
318 bytes_read.as_mut_ptr(),
319 std::ptr::null_mut(),
320 std::ptr::null_mut(),
321 )
322 };
323 if res == 0 {
324 return Err(io::Error::last_os_error());
325 }
326 Ok(unsafe { bytes_read.assume_init() } as usize)
327 }
328
329 #[inline]
330 fn write(&self, buf: &[u8]) -> io::Result<usize> {
331 Write::write(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
332 }
333
334 #[inline]
335 fn write_all(&self, buf: &[u8]) -> io::Result<()> {
336 Write::write_all(&mut &*self.as_filelike_view::<std::fs::File>(), buf)
337 }
338
339 #[inline]
340 fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize> {
341 Write::write_vectored(&mut &*self.as_filelike_view::<std::fs::File>(), bufs)
342 }
343
344 #[inline]
345 fn flush(&self) -> io::Result<()> {
346 Write::flush(&mut &*self.as_filelike_view::<std::fs::File>())
347 }
348
349 #[inline]
350 fn write_fmt(&self, fmt: Arguments) -> io::Result<()> {
351 Write::write_fmt(&mut &*self.as_filelike_view::<std::fs::File>(), fmt)
352 }
353}
354
355#[cfg(windows)]
356#[cfg(feature = "cap_std_impls")]
357impl IoExt for cap_std::fs::File {
358 #[inline]
359 fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
360 self.as_filelike_view::<std::fs::File>().read(buf)
361 }
362
363 #[inline]
364 fn read_exact(&self, buf: &mut [u8]) -> io::Result<()> {
365 self.as_filelike_view::<std::fs::File>().read_exact(buf)
366 }
367
368 #[inline]
369 fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
370 self.as_filelike_view::<std::fs::File>().read_vectored(bufs)
371 }
372
373 #[inline]
374 fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
375 self.as_filelike_view::<std::fs::File>().read_to_end(buf)
376 }
377
378 #[inline]
379 fn read_to_string(&self, buf: &mut String) -> io::Result<usize> {
380 self.as_filelike_view::<std::fs::File>().read_to_string(buf)
381 }
382
383 #[inline]
384 fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
385 self.as_filelike_view::<std::fs::File>().peek(buf)
386 }
387
388 #[inline]
389 fn write(&self, buf: &[u8]) -> io::Result<usize> {
390 self.as_filelike_view::<std::fs::File>().write(buf)
391 }
392
393 #[inline]
394 fn write_all(&self, buf: &[u8]) -> io::Result<()> {
395 self.as_filelike_view::<std::fs::File>().write_all(buf)
396 }
397
398 #[inline]
399 fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize> {
400 self.as_filelike_view::<std::fs::File>()
401 .write_vectored(bufs)
402 }
403
404 #[inline]
405 fn flush(&self) -> io::Result<()> {
406 self.as_filelike_view::<std::fs::File>().flush()
407 }
408
409 #[inline]
410 fn write_fmt(&self, fmt: Arguments) -> io::Result<()> {
411 self.as_filelike_view::<std::fs::File>().write_fmt(fmt)
412 }
413}
414
415#[cfg(windows)]
416#[cfg(feature = "cap_std_impls_fs_utf8")]
417impl IoExt for cap_std::fs_utf8::File {
418 #[inline]
419 fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
420 self.as_filelike_view::<std::fs::File>().read(buf)
421 }
422
423 #[inline]
424 fn read_exact(&self, buf: &mut [u8]) -> io::Result<()> {
425 self.as_filelike_view::<std::fs::File>().read_exact(buf)
426 }
427
428 #[inline]
429 fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
430 self.as_filelike_view::<std::fs::File>().read_vectored(bufs)
431 }
432
433 #[inline]
434 fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
435 self.as_filelike_view::<std::fs::File>().read_to_end(buf)
436 }
437
438 #[inline]
439 fn read_to_string(&self, buf: &mut String) -> io::Result<usize> {
440 self.as_filelike_view::<std::fs::File>().read_to_string(buf)
441 }
442
443 #[inline]
444 fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
445 self.as_filelike_view::<std::fs::File>().peek(buf)
446 }
447
448 #[inline]
449 fn write(&self, buf: &[u8]) -> io::Result<usize> {
450 self.as_filelike_view::<std::fs::File>().write(buf)
451 }
452
453 #[inline]
454 fn write_all(&self, buf: &[u8]) -> io::Result<()> {
455 self.as_filelike_view::<std::fs::File>().write_all(buf)
456 }
457
458 #[inline]
459 fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize> {
460 self.as_filelike_view::<std::fs::File>()
461 .write_vectored(bufs)
462 }
463
464 #[inline]
465 fn flush(&self) -> io::Result<()> {
466 self.as_filelike_view::<std::fs::File>().flush()
467 }
468
469 #[inline]
470 fn write_fmt(&self, fmt: Arguments) -> io::Result<()> {
471 self.as_filelike_view::<std::fs::File>().write_fmt(fmt)
472 }
473}
474
475#[cfg(windows)]
476impl IoExt for std::net::TcpStream {
477 #[inline]
478 fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
479 Read::read(&mut &*self.as_socketlike_view::<std::net::TcpStream>(), buf)
480 }
481
482 #[inline]
483 fn read_exact(&self, buf: &mut [u8]) -> io::Result<()> {
484 Read::read_exact(&mut &*self.as_socketlike_view::<std::net::TcpStream>(), buf)
485 }
486
487 #[inline]
488 fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
489 Read::read_vectored(
490 &mut &*self.as_socketlike_view::<std::net::TcpStream>(),
491 bufs,
492 )
493 }
494
495 #[inline]
496 fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
497 Read::read_to_end(&mut &*self.as_socketlike_view::<std::net::TcpStream>(), buf)
498 }
499
500 #[inline]
501 fn read_to_string(&self, buf: &mut String) -> io::Result<usize> {
502 Read::read_to_string(&mut &*self.as_socketlike_view::<std::net::TcpStream>(), buf)
503 }
504
505 #[inline]
506 fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
507 self.as_socketlike_view::<std::net::TcpStream>().peek(buf)
508 }
509
510 #[inline]
511 fn write(&self, buf: &[u8]) -> io::Result<usize> {
512 Write::write(&mut &*self.as_socketlike_view::<std::net::TcpStream>(), buf)
513 }
514
515 #[inline]
516 fn write_all(&self, buf: &[u8]) -> io::Result<()> {
517 Write::write_all(&mut &*self.as_socketlike_view::<std::net::TcpStream>(), buf)
518 }
519
520 #[inline]
521 fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize> {
522 Write::write_vectored(
523 &mut &*self.as_socketlike_view::<std::net::TcpStream>(),
524 bufs,
525 )
526 }
527
528 #[inline]
529 fn flush(&self) -> io::Result<()> {
530 Write::flush(&mut &*self.as_socketlike_view::<std::net::TcpStream>())
531 }
532
533 #[inline]
534 fn write_fmt(&self, fmt: Arguments) -> io::Result<()> {
535 Write::write_fmt(&mut &*self.as_socketlike_view::<std::net::TcpStream>(), fmt)
536 }
537}
538
539#[cfg(windows)]
540#[cfg(feature = "cap_std_impls")]
541impl IoExt for cap_std::net::TcpStream {
542 #[inline]
543 fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
544 self.as_socketlike_view::<std::net::TcpStream>().read(buf)
545 }
546
547 #[inline]
548 fn read_exact(&self, buf: &mut [u8]) -> io::Result<()> {
549 self.as_socketlike_view::<std::net::TcpStream>()
550 .read_exact(buf)
551 }
552
553 #[inline]
554 fn read_vectored(&self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
555 self.as_socketlike_view::<std::net::TcpStream>()
556 .read_vectored(bufs)
557 }
558
559 #[inline]
560 fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
561 self.as_socketlike_view::<std::net::TcpStream>()
562 .read_to_end(buf)
563 }
564
565 #[inline]
566 fn read_to_string(&self, buf: &mut String) -> io::Result<usize> {
567 self.as_socketlike_view::<std::net::TcpStream>()
568 .read_to_string(buf)
569 }
570
571 #[inline]
572 fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
573 self.as_socketlike_view::<std::net::TcpStream>().peek(buf)
574 }
575
576 #[inline]
577 fn write(&self, buf: &[u8]) -> io::Result<usize> {
578 self.as_socketlike_view::<std::net::TcpStream>().write(buf)
579 }
580
581 #[inline]
582 fn write_all(&self, buf: &[u8]) -> io::Result<()> {
583 self.as_socketlike_view::<std::net::TcpStream>()
584 .write_all(buf)
585 }
586
587 #[inline]
588 fn write_vectored(&self, bufs: &[IoSlice]) -> io::Result<usize> {
589 self.as_socketlike_view::<std::net::TcpStream>()
590 .write_vectored(bufs)
591 }
592
593 #[inline]
594 fn flush(&self) -> io::Result<()> {
595 self.as_socketlike_view::<std::net::TcpStream>().flush()
596 }
597
598 #[inline]
599 fn write_fmt(&self, fmt: Arguments) -> io::Result<()> {
600 self.as_socketlike_view::<std::net::TcpStream>()
601 .write_fmt(fmt)
602 }
603}
604
605fn _io_ext_can_be_trait_object(_: &dyn IoExt) {}