1#![allow(clippy::non_send_fields_in_send_ty)]
19
20use std::future::Future;
21use std::marker::PhantomData;
22use std::mem::{ManuallyDrop, MaybeUninit};
23use std::os::fd::RawFd;
24use std::pin::Pin;
25use std::task::{self, Poll};
26use std::{io, ptr};
27
28use crate::cancel::{Cancel, CancelOp, CancelResult};
29use crate::extract::{Extract, Extractor};
30use crate::fd::{AsyncFd, Descriptor, File};
31use crate::op::{op_future, poll_state, OpState, NO_OFFSET};
32use crate::{libc, man_link, SubmissionQueue};
33
34mod read_buf;
35#[doc(hidden)]
36pub use read_buf::{BufGroupId, BufIdx};
37pub use read_buf::{ReadBuf, ReadBufPool};
38
39pub(crate) use std::io::*;
41
42macro_rules! stdio {
43 (
44 $fn: ident () -> $name: ident, $fd: expr
45 ) => {
46 #[doc = concat!("Create a new `", stringify!($name), "`.\n\n")]
47 pub fn $fn(sq: $crate::SubmissionQueue) -> $name {
48 unsafe { $name(std::mem::ManuallyDrop::new($crate::AsyncFd::from_raw_fd($fd, sq))) }
49 }
50
51 #[doc = concat!(
52 "An [`AsyncFd`] for ", stringify!($fn), ".\n\n",
53 "# Notes\n\n",
54 "This directly writes to the raw file descriptor, which means it's not buffered and will not flush anything buffered by the standard library.\n\n",
55 "When this type is dropped it will not close ", stringify!($fn), ".",
56 )]
57 pub struct $name(std::mem::ManuallyDrop<$crate::AsyncFd>);
58
59 impl std::ops::Deref for $name {
60 type Target = $crate::AsyncFd;
61
62 fn deref(&self) -> &Self::Target {
63 &self.0
64 }
65 }
66
67 impl std::fmt::Debug for $name {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 f.debug_struct(stringify!($name))
70 .field("fd", &*self.0)
71 .finish()
72 }
73 }
74
75 impl std::ops::Drop for $name {
76 fn drop(&mut self) {
77 unsafe { std::ptr::drop_in_place(&mut self.0.sq) };
83 }
84 }
85 };
86}
87
88stdio!(stdin() -> Stdin, libc::STDIN_FILENO);
89stdio!(stdout() -> Stdout, libc::STDOUT_FILENO);
90stdio!(stderr() -> Stderr, libc::STDERR_FILENO);
91
92impl<D: Descriptor> AsyncFd<D> {
94 #[doc = man_link!(read(2))]
96 pub const fn read<'fd, B>(&'fd self, buf: B) -> Read<'fd, B, D>
97 where
98 B: BufMut,
99 {
100 self.read_at(buf, NO_OFFSET)
101 }
102
103 pub const fn read_at<'fd, B>(&'fd self, buf: B, offset: u64) -> Read<'fd, B, D>
109 where
110 B: BufMut,
111 {
112 Read::new(self, buf, offset)
113 }
114
115 pub const fn read_n<'fd, B>(&'fd self, buf: B, n: usize) -> ReadN<'fd, B, D>
117 where
118 B: BufMut,
119 {
120 self.read_n_at(buf, NO_OFFSET, n)
121 }
122
123 pub const fn read_n_at<'fd, B>(&'fd self, buf: B, offset: u64, n: usize) -> ReadN<'fd, B, D>
127 where
128 B: BufMut,
129 {
130 ReadN::new(self, buf, offset, n)
131 }
132
133 #[doc = man_link!(readv(2))]
135 pub fn read_vectored<'fd, B, const N: usize>(&'fd self, bufs: B) -> ReadVectored<'fd, B, N, D>
136 where
137 B: BufMutSlice<N>,
138 {
139 self.read_vectored_at(bufs, NO_OFFSET)
140 }
141
142 pub fn read_vectored_at<'fd, B, const N: usize>(
146 &'fd self,
147 mut bufs: B,
148 offset: u64,
149 ) -> ReadVectored<'fd, B, N, D>
150 where
151 B: BufMutSlice<N>,
152 {
153 let iovecs = unsafe { bufs.as_iovecs_mut() };
154 ReadVectored::new(self, bufs, iovecs, offset)
155 }
156
157 pub fn read_n_vectored<'fd, B, const N: usize>(
159 &'fd self,
160 bufs: B,
161 n: usize,
162 ) -> ReadNVectored<'fd, B, N, D>
163 where
164 B: BufMutSlice<N>,
165 {
166 self.read_n_vectored_at(bufs, NO_OFFSET, n)
167 }
168
169 pub fn read_n_vectored_at<'fd, B, const N: usize>(
173 &'fd self,
174 bufs: B,
175 offset: u64,
176 n: usize,
177 ) -> ReadNVectored<'fd, B, N, D>
178 where
179 B: BufMutSlice<N>,
180 {
181 ReadNVectored::new(self, bufs, offset, n)
182 }
183
184 #[doc = man_link!(write(2))]
186 pub const fn write<'fd, B>(&'fd self, buf: B) -> Write<'fd, B, D>
187 where
188 B: Buf,
189 {
190 self.write_at(buf, NO_OFFSET)
191 }
192
193 pub const fn write_at<'fd, B>(&'fd self, buf: B, offset: u64) -> Write<'fd, B, D>
197 where
198 B: Buf,
199 {
200 Write::new(self, buf, offset)
201 }
202
203 pub const fn write_all<'fd, B>(&'fd self, buf: B) -> WriteAll<'fd, B, D>
205 where
206 B: Buf,
207 {
208 self.write_all_at(buf, NO_OFFSET)
209 }
210
211 pub const fn write_all_at<'fd, B>(&'fd self, buf: B, offset: u64) -> WriteAll<'fd, B, D>
215 where
216 B: Buf,
217 {
218 WriteAll::new(self, buf, offset)
219 }
220
221 #[doc = man_link!(writev(2))]
223 pub fn write_vectored<'fd, B, const N: usize>(&'fd self, bufs: B) -> WriteVectored<'fd, B, N, D>
224 where
225 B: BufSlice<N>,
226 {
227 self.write_vectored_at(bufs, NO_OFFSET)
228 }
229
230 pub fn write_vectored_at<'fd, B, const N: usize>(
234 &'fd self,
235 bufs: B,
236 offset: u64,
237 ) -> WriteVectored<'fd, B, N, D>
238 where
239 B: BufSlice<N>,
240 {
241 let iovecs = unsafe { bufs.as_iovecs() };
242 WriteVectored::new(self, bufs, iovecs, offset)
243 }
244
245 pub fn write_all_vectored<'fd, B, const N: usize>(
247 &'fd self,
248 bufs: B,
249 ) -> WriteAllVectored<'fd, B, N, D>
250 where
251 B: BufSlice<N>,
252 {
253 self.write_all_vectored_at(bufs, NO_OFFSET)
254 }
255
256 pub fn write_all_vectored_at<'fd, B, const N: usize>(
260 &'fd self,
261 bufs: B,
262 offset: u64,
263 ) -> WriteAllVectored<'fd, B, N, D>
264 where
265 B: BufSlice<N>,
266 {
267 WriteAllVectored::new(self, bufs, offset)
268 }
269
270 #[doc = man_link!(splice(2))]
274 #[doc(alias = "splice")]
275 pub const fn splice_to<'fd>(
276 &'fd self,
277 target: RawFd,
278 length: u32,
279 flags: libc::c_int,
280 ) -> Splice<'fd, D> {
281 self.splice_to_at(NO_OFFSET, target, NO_OFFSET, length, flags)
282 }
283
284 pub const fn splice_to_at<'fd>(
288 &'fd self,
289 offset: u64,
290 target: RawFd,
291 target_offset: u64,
292 length: u32,
293 flags: libc::c_int,
294 ) -> Splice<'fd, D> {
295 self.splice(
296 target,
297 SpliceDirection::To,
298 offset,
299 target_offset,
300 length,
301 flags,
302 )
303 }
304
305 #[doc(alias = "splice")]
309 pub const fn splice_from<'fd>(
310 &'fd self,
311 target: RawFd,
312 length: u32,
313 flags: libc::c_int,
314 ) -> Splice<'fd, D> {
315 self.splice_from_at(NO_OFFSET, target, NO_OFFSET, length, flags)
316 }
317
318 #[doc(alias = "splice")]
322 pub const fn splice_from_at<'fd>(
323 &'fd self,
324 offset: u64,
325 target: RawFd,
326 target_offset: u64,
327 length: u32,
328 flags: libc::c_int,
329 ) -> Splice<'fd, D> {
330 self.splice(
331 target,
332 SpliceDirection::From,
333 target_offset,
334 offset,
335 length,
336 flags,
337 )
338 }
339
340 const fn splice<'fd>(
341 &'fd self,
342 target: RawFd,
343 direction: SpliceDirection,
344 off_in: u64,
345 off_out: u64,
346 length: u32,
347 flags: libc::c_int,
348 ) -> Splice<'fd, D> {
349 Splice::new(self, (target, direction, off_in, off_out, length, flags))
350 }
351
352 #[doc = man_link!(close(2))]
359 pub fn close(self) -> Close<D> {
360 let this = ManuallyDrop::new(self);
363 let fd = this.fd();
366 let sq = unsafe { ptr::read(&this.sq) };
367
368 Close {
369 sq,
370 state: OpState::NotStarted(fd),
371 kind: PhantomData,
372 }
373 }
374}
375
376op_future! {
378 fn AsyncFd::read -> B,
379 struct Read<'fd, B: BufMut> {
380 buf: B,
383 },
384 drop_using: Box,
385 setup_state: offset: u64,
386 setup: |submission, fd, (buf,), offset| unsafe {
387 let (ptr, len) = buf.parts_mut();
388 submission.read_at(fd.fd(), ptr, len, offset);
389 if let Some(buf_group) = buf.buffer_group() {
390 submission.set_buffer_select(buf_group.0);
391 }
392 },
393 map_result: |this, (mut buf,), buf_idx, n| {
394 #[allow(clippy::cast_sign_loss)] unsafe { buf.buffer_init(BufIdx(buf_idx), n as u32) };
398 Ok(buf)
399 },
400}
401
402#[derive(Debug)]
404pub struct ReadN<'fd, B, D: Descriptor = File> {
405 read: Read<'fd, ReadNBuf<B>, D>,
406 offset: u64,
407 left: usize,
409}
410
411impl<'fd, B: BufMut, D: Descriptor> ReadN<'fd, B, D> {
412 const fn new(fd: &'fd AsyncFd<D>, buf: B, offset: u64, n: usize) -> ReadN<'fd, B, D> {
413 let buf = ReadNBuf { buf, last_read: 0 };
414 ReadN {
415 read: fd.read_at(buf, offset),
416 offset,
417 left: n,
418 }
419 }
420}
421
422impl<'fd, B, D: Descriptor> Cancel for ReadN<'fd, B, D> {
423 fn try_cancel(&mut self) -> CancelResult {
424 self.read.try_cancel()
425 }
426
427 fn cancel(&mut self) -> CancelOp {
428 self.read.cancel()
429 }
430}
431
432impl<'fd, B: BufMut, D: Descriptor> Future for ReadN<'fd, B, D> {
433 type Output = io::Result<B>;
434
435 fn poll(self: Pin<&mut Self>, ctx: &mut task::Context<'_>) -> Poll<Self::Output> {
436 let this = unsafe { Pin::into_inner_unchecked(self) };
438 let mut read = unsafe { Pin::new_unchecked(&mut this.read) };
439 match read.as_mut().poll(ctx) {
440 Poll::Ready(Ok(buf)) => {
441 if buf.last_read == 0 {
442 return Poll::Ready(Err(io::ErrorKind::UnexpectedEof.into()));
443 }
444
445 if buf.last_read >= this.left {
446 return Poll::Ready(Ok(buf.buf));
448 }
449
450 this.left -= buf.last_read;
451 if this.offset != NO_OFFSET {
452 this.offset += buf.last_read as u64;
453 }
454
455 read.set(read.fd.read_at(buf, this.offset));
456 unsafe { Pin::new_unchecked(this) }.poll(ctx)
457 }
458 Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
459 Poll::Pending => Poll::Pending,
460 }
461 }
462}
463
464op_future! {
466 fn AsyncFd::read_vectored -> B,
467 struct ReadVectored<'fd, B: BufMutSlice<N>; const N: usize> {
468 bufs: B,
471 iovecs: [libc::iovec; N],
482 },
483 drop_using: Box,
484 impl !Unpin,
486 setup_state: offset: u64,
487 setup: |submission, fd, (_bufs, iovecs), offset| unsafe {
488 submission.read_vectored_at(fd.fd(), iovecs, offset);
489 },
490 map_result: |this, (mut bufs, _iovecs), _flags, n| {
491 #[allow(clippy::cast_sign_loss)] unsafe { bufs.set_init(n as usize) };
495 Ok(bufs)
496 },
497}
498
499#[derive(Debug)]
501pub struct ReadNVectored<'fd, B, const N: usize, D: Descriptor = File> {
502 read: ReadVectored<'fd, ReadNBuf<B>, N, D>,
503 offset: u64,
504 left: usize,
506}
507
508impl<'fd, B: BufMutSlice<N>, const N: usize, D: Descriptor> ReadNVectored<'fd, B, N, D> {
509 fn new(fd: &'fd AsyncFd<D>, bufs: B, offset: u64, n: usize) -> ReadNVectored<'fd, B, N, D> {
510 let bufs = ReadNBuf {
511 buf: bufs,
512 last_read: 0,
513 };
514 ReadNVectored {
515 read: fd.read_vectored_at(bufs, offset),
516 offset,
517 left: n,
518 }
519 }
520}
521
522impl<'fd, B, const N: usize, D: Descriptor> Cancel for ReadNVectored<'fd, B, N, D> {
523 fn try_cancel(&mut self) -> CancelResult {
524 self.read.try_cancel()
525 }
526
527 fn cancel(&mut self) -> CancelOp {
528 self.read.cancel()
529 }
530}
531
532impl<'fd, B: BufMutSlice<N>, const N: usize, D: Descriptor> Future for ReadNVectored<'fd, B, N, D> {
533 type Output = io::Result<B>;
534
535 fn poll(self: Pin<&mut Self>, ctx: &mut task::Context<'_>) -> Poll<Self::Output> {
536 let this = unsafe { Pin::into_inner_unchecked(self) };
538 let mut read = unsafe { Pin::new_unchecked(&mut this.read) };
539 match read.as_mut().poll(ctx) {
540 Poll::Ready(Ok(bufs)) => {
541 if bufs.last_read == 0 {
542 return Poll::Ready(Err(io::ErrorKind::UnexpectedEof.into()));
543 }
544
545 if bufs.last_read >= this.left {
546 return Poll::Ready(Ok(bufs.buf));
548 }
549
550 this.left -= bufs.last_read;
551 if this.offset != NO_OFFSET {
552 this.offset += bufs.last_read as u64;
553 }
554
555 read.set(read.fd.read_vectored_at(bufs, this.offset));
556 unsafe { Pin::new_unchecked(this) }.poll(ctx)
557 }
558 Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
559 Poll::Pending => Poll::Pending,
560 }
561 }
562}
563
564#[derive(Debug)]
566pub(crate) struct ReadNBuf<B> {
567 pub(crate) buf: B,
568 pub(crate) last_read: usize,
569}
570
571unsafe impl<B: BufMut> BufMut for ReadNBuf<B> {
572 unsafe fn parts_mut(&mut self) -> (*mut u8, u32) {
573 self.buf.parts_mut()
574 }
575
576 unsafe fn set_init(&mut self, n: usize) {
577 self.last_read = n;
578 self.buf.set_init(n);
579 }
580}
581
582unsafe impl<B: BufMutSlice<N>, const N: usize> BufMutSlice<N> for ReadNBuf<B> {
583 unsafe fn as_iovecs_mut(&mut self) -> [libc::iovec; N] {
584 self.buf.as_iovecs_mut()
585 }
586
587 unsafe fn set_init(&mut self, n: usize) {
588 self.last_read = n;
589 self.buf.set_init(n);
590 }
591}
592
593op_future! {
595 fn AsyncFd::write -> usize,
596 struct Write<'fd, B: Buf> {
597 buf: B,
600 },
601 drop_using: Box,
602 setup_state: offset: u64,
603 setup: |submission, fd, (buf,), offset| unsafe {
604 let (ptr, len) = buf.parts();
605 submission.write_at(fd.fd(), ptr, len, offset);
606 },
607 map_result: |n| {
608 #[allow(clippy::cast_sign_loss)] Ok(n as usize)
610 },
611 extract: |this, (buf,), n| -> (B, usize) {
612 #[allow(clippy::cast_sign_loss)] Ok((buf, n as usize))
614 },
615}
616
617#[derive(Debug)]
619pub struct WriteAll<'fd, B, D: Descriptor = File> {
620 write: Extractor<Write<'fd, SkipBuf<B>, D>>,
621 offset: u64,
622}
623
624impl<'fd, B: Buf, D: Descriptor> WriteAll<'fd, B, D> {
625 const fn new(fd: &'fd AsyncFd<D>, buf: B, offset: u64) -> WriteAll<'fd, B, D> {
626 let buf = SkipBuf { buf, skip: 0 };
627 WriteAll {
628 write: Extractor {
630 fut: fd.write_at(buf, offset),
631 },
632 offset,
633 }
634 }
635
636 fn inner_poll(self: Pin<&mut Self>, ctx: &mut task::Context<'_>) -> Poll<io::Result<B>> {
639 let this = unsafe { Pin::into_inner_unchecked(self) };
641 let mut write = unsafe { Pin::new_unchecked(&mut this.write) };
642 match write.as_mut().poll(ctx) {
643 Poll::Ready(Ok((_, 0))) => Poll::Ready(Err(io::ErrorKind::WriteZero.into())),
644 Poll::Ready(Ok((mut buf, n))) => {
645 buf.skip += n as u32;
646 if this.offset != NO_OFFSET {
647 this.offset += n as u64;
648 }
649
650 if let (_, 0) = unsafe { buf.parts() } {
651 return Poll::Ready(Ok(buf.buf));
653 }
654
655 write.set(write.fut.fd.write_at(buf, this.offset).extract());
656 unsafe { Pin::new_unchecked(this) }.inner_poll(ctx)
657 }
658 Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
659 Poll::Pending => Poll::Pending,
660 }
661 }
662}
663
664impl<'fd, B, D: Descriptor> Cancel for WriteAll<'fd, B, D> {
665 fn try_cancel(&mut self) -> CancelResult {
666 self.write.try_cancel()
667 }
668
669 fn cancel(&mut self) -> CancelOp {
670 self.write.cancel()
671 }
672}
673
674impl<'fd, B: Buf, D: Descriptor> Future for WriteAll<'fd, B, D> {
675 type Output = io::Result<()>;
676
677 fn poll(self: Pin<&mut Self>, ctx: &mut task::Context<'_>) -> Poll<Self::Output> {
678 self.inner_poll(ctx).map_ok(|_| ())
679 }
680}
681
682impl<'fd, B: Buf, D: Descriptor> Extract for WriteAll<'fd, B, D> {}
683
684impl<'fd, B: Buf, D: Descriptor> Future for Extractor<WriteAll<'fd, B, D>> {
685 type Output = io::Result<B>;
686
687 fn poll(self: Pin<&mut Self>, ctx: &mut task::Context<'_>) -> Poll<Self::Output> {
688 unsafe { Pin::map_unchecked_mut(self, |s| &mut s.fut) }.inner_poll(ctx)
689 }
690}
691
692#[derive(Debug)]
694pub(crate) struct SkipBuf<B> {
695 pub(crate) buf: B,
696 pub(crate) skip: u32,
697}
698
699unsafe impl<B: Buf> Buf for SkipBuf<B> {
700 unsafe fn parts(&self) -> (*const u8, u32) {
701 let (ptr, size) = self.buf.parts();
702 if self.skip >= size {
703 (ptr, 0)
704 } else {
705 (ptr.add(self.skip as usize), size - self.skip)
706 }
707 }
708}
709
710op_future! {
712 fn AsyncFd::write_vectored -> usize,
713 struct WriteVectored<'fd, B: BufSlice<N>; const N: usize> {
714 bufs: B,
717 iovecs: [libc::iovec; N],
728 },
729 drop_using: Box,
730 impl !Unpin,
732 setup_state: offset: u64,
733 setup: |submission, fd, (_bufs, iovecs), offset| unsafe {
734 submission.write_vectored_at(fd.fd(), iovecs, offset);
735 },
736 map_result: |n| {
737 #[allow(clippy::cast_sign_loss)] Ok(n as usize)
739 },
740 extract: |this, (buf, _iovecs), n| -> (B, usize) {
741 #[allow(clippy::cast_sign_loss)] Ok((buf, n as usize))
743 },
744}
745
746#[derive(Debug)]
748pub struct WriteAllVectored<'fd, B, const N: usize, D: Descriptor = File> {
749 write: Extractor<WriteVectored<'fd, B, N, D>>,
750 offset: u64,
751 skip: u64,
752}
753
754impl<'fd, B: BufSlice<N>, const N: usize, D: Descriptor> WriteAllVectored<'fd, B, N, D> {
755 fn new(fd: &'fd AsyncFd<D>, buf: B, offset: u64) -> WriteAllVectored<'fd, B, N, D> {
756 WriteAllVectored {
757 write: fd.write_vectored_at(buf, offset).extract(),
758 offset,
759 skip: 0,
760 }
761 }
762
763 fn inner_poll(self: Pin<&mut Self>, ctx: &mut task::Context<'_>) -> Poll<io::Result<B>> {
766 let this = unsafe { Pin::into_inner_unchecked(self) };
768 let mut write = unsafe { Pin::new_unchecked(&mut this.write) };
769 match write.as_mut().poll(ctx) {
770 Poll::Ready(Ok((_, 0))) => Poll::Ready(Err(io::ErrorKind::WriteZero.into())),
771 Poll::Ready(Ok((bufs, n))) => {
772 this.skip += n as u64;
773 if this.offset != NO_OFFSET {
774 this.offset += n as u64;
775 }
776
777 let mut iovecs = unsafe { bufs.as_iovecs() };
778 let mut skip = this.skip;
779 for iovec in &mut iovecs {
780 if iovec.iov_len as u64 <= skip {
781 skip -= iovec.iov_len as u64;
783 iovec.iov_len = 0;
784 } else {
785 iovec.iov_len -= skip as usize;
786 break;
787 }
788 }
789
790 if iovecs[N - 1].iov_len == 0 {
791 return Poll::Ready(Ok(bufs));
793 }
794
795 write.set(WriteVectored::new(write.fut.fd, bufs, iovecs, this.offset).extract());
796 unsafe { Pin::new_unchecked(this) }.inner_poll(ctx)
797 }
798 Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
799 Poll::Pending => Poll::Pending,
800 }
801 }
802}
803
804impl<'fd, B, const N: usize, D: Descriptor> Cancel for WriteAllVectored<'fd, B, N, D> {
805 fn try_cancel(&mut self) -> CancelResult {
806 self.write.try_cancel()
807 }
808
809 fn cancel(&mut self) -> CancelOp {
810 self.write.cancel()
811 }
812}
813
814impl<'fd, B: BufSlice<N>, const N: usize, D: Descriptor> Future for WriteAllVectored<'fd, B, N, D> {
815 type Output = io::Result<()>;
816
817 fn poll(self: Pin<&mut Self>, ctx: &mut task::Context<'_>) -> Poll<Self::Output> {
818 self.inner_poll(ctx).map_ok(|_| ())
819 }
820}
821
822impl<'fd, B: BufSlice<N>, const N: usize, D: Descriptor> Extract
823 for WriteAllVectored<'fd, B, N, D>
824{
825}
826
827impl<'fd, B: BufSlice<N>, const N: usize, D: Descriptor> Future
828 for Extractor<WriteAllVectored<'fd, B, N, D>>
829{
830 type Output = io::Result<B>;
831
832 fn poll(self: Pin<&mut Self>, ctx: &mut task::Context<'_>) -> Poll<Self::Output> {
833 unsafe { Pin::map_unchecked_mut(self, |s| &mut s.fut) }.inner_poll(ctx)
834 }
835}
836
837op_future! {
839 fn AsyncFd::splice_to -> usize,
840 struct Splice<'fd> {
841 },
843 setup_state: flags: (RawFd, SpliceDirection, u64, u64, u32, libc::c_int),
844 setup: |submission, fd, (), (target, direction, off_in, off_out, len, flags)| unsafe {
845 let (fd_in, fd_out) = match direction {
846 SpliceDirection::To => (fd.fd(), target),
847 SpliceDirection::From => (target, fd.fd()),
848 };
849 submission.splice(fd_in, off_in, fd_out, off_out, len, flags);
850 },
851 map_result: |n| {
852 #[allow(clippy::cast_sign_loss)] Ok(n as usize)
854 },
855}
856
857#[derive(Copy, Clone, Debug)]
858enum SpliceDirection {
859 To,
860 From,
861}
862
863#[derive(Debug)]
865#[must_use = "`Future`s do nothing unless polled"]
866pub struct Close<D: Descriptor = File> {
867 sq: SubmissionQueue,
868 state: OpState<RawFd>,
869 kind: PhantomData<D>,
870}
871
872impl<D: Descriptor + Unpin> Future for Close<D> {
873 type Output = io::Result<()>;
874
875 fn poll(mut self: Pin<&mut Self>, ctx: &mut task::Context<'_>) -> Poll<Self::Output> {
876 let op_index = poll_state!(Close, self.state, self.sq, ctx, |submission, fd| unsafe {
877 submission.close(fd);
878 D::use_flags(submission);
879 });
880
881 match self.sq.poll_op(ctx, op_index) {
882 Poll::Ready(result) => {
883 self.state = OpState::Done;
884 match result {
885 Ok(_) => Poll::Ready(Ok(())),
886 Err(err) => Poll::Ready(Err(err)),
887 }
888 }
889 Poll::Pending => Poll::Pending,
890 }
891 }
892}
893
894pub unsafe trait BufMut: 'static {
911 unsafe fn parts_mut(&mut self) -> (*mut u8, u32);
943
944 unsafe fn set_init(&mut self, n: usize);
951
952 #[doc(hidden)]
956 fn buffer_group(&self) -> Option<BufGroupId> {
957 None
958 }
959
960 #[doc(hidden)]
964 unsafe fn buffer_init(&mut self, idx: BufIdx, n: u32) {
965 debug_assert!(idx.0 == 0);
966 self.set_init(n as usize);
967 }
968}
969
970unsafe impl BufMut for Vec<u8> {
976 unsafe fn parts_mut(&mut self) -> (*mut u8, u32) {
977 let slice = self.spare_capacity_mut();
978 (slice.as_mut_ptr().cast(), slice.len() as u32)
979 }
980
981 unsafe fn set_init(&mut self, n: usize) {
982 self.set_len(self.len() + n);
983 }
984}
985
986pub unsafe trait BufMutSlice<const N: usize>: 'static {
994 unsafe fn as_iovecs_mut(&mut self) -> [libc::iovec; N];
1001
1002 unsafe fn set_init(&mut self, n: usize);
1014}
1015
1016unsafe impl<B: BufMut, const N: usize> BufMutSlice<N> for [B; N] {
1020 unsafe fn as_iovecs_mut(&mut self) -> [libc::iovec; N] {
1021 let mut iovecs =
1024 unsafe { MaybeUninit::<[MaybeUninit<libc::iovec>; N]>::uninit().assume_init() };
1025 for (buf, iovec) in self.iter_mut().zip(iovecs.iter_mut()) {
1026 debug_assert!(
1027 buf.buffer_group().is_none(),
1028 "can't use a10::ReadBuf as a10::BufMutSlice in vectored I/O"
1029 );
1030 let (ptr, len) = buf.parts_mut();
1031 iovec.write(libc::iovec {
1032 iov_base: ptr.cast(),
1033 iov_len: len as _,
1034 });
1035 }
1036 unsafe { std::mem::transmute_copy(&std::mem::ManuallyDrop::new(iovecs)) }
1040 }
1041
1042 unsafe fn set_init(&mut self, n: usize) {
1043 let mut left = n;
1044 for buf in self {
1045 let (_, len) = buf.parts_mut();
1046 let len = len as usize;
1047 if len < left {
1048 buf.set_init(len);
1050 left -= len;
1051 } else {
1052 buf.set_init(left);
1054 return;
1055 }
1056 }
1057 unreachable!(
1058 "called BufMutSlice::set_init({n}), with buffers totaling in {} in size",
1059 n - left
1060 );
1061 }
1062}
1063
1064pub unsafe trait Buf: 'static {
1084 unsafe fn parts(&self) -> (*const u8, u32);
1099}
1100
1101unsafe impl Buf for Vec<u8> {
1105 unsafe fn parts(&self) -> (*const u8, u32) {
1106 let slice = self.as_slice();
1107 (slice.as_ptr().cast(), slice.len() as u32)
1108 }
1109}
1110
1111unsafe impl Buf for Box<[u8]> {
1115 unsafe fn parts(&self) -> (*const u8, u32) {
1116 (self.as_ptr().cast(), self.len() as u32)
1117 }
1118}
1119
1120unsafe impl Buf for String {
1123 unsafe fn parts(&self) -> (*const u8, u32) {
1124 let slice = self.as_bytes();
1125 (slice.as_ptr().cast(), slice.len() as u32)
1126 }
1127}
1128
1129unsafe impl Buf for &'static [u8] {
1132 unsafe fn parts(&self) -> (*const u8, u32) {
1133 (self.as_ptr(), self.len() as u32)
1134 }
1135}
1136
1137unsafe impl Buf for &'static str {
1140 unsafe fn parts(&self) -> (*const u8, u32) {
1141 (self.as_bytes().as_ptr(), self.len() as u32)
1142 }
1143}
1144
1145pub unsafe trait BufSlice<const N: usize>: 'static {
1153 unsafe fn as_iovecs(&self) -> [libc::iovec; N];
1160}
1161
1162unsafe impl<B: Buf, const N: usize> BufSlice<N> for [B; N] {
1165 unsafe fn as_iovecs(&self) -> [libc::iovec; N] {
1166 let mut iovecs =
1169 unsafe { MaybeUninit::<[MaybeUninit<libc::iovec>; N]>::uninit().assume_init() };
1170 for (buf, iovec) in self.iter().zip(iovecs.iter_mut()) {
1171 let (ptr, len) = buf.parts();
1172 iovec.write(libc::iovec {
1173 iov_base: ptr as _,
1174 iov_len: len as _,
1175 });
1176 }
1177 unsafe { std::mem::transmute_copy(&std::mem::ManuallyDrop::new(iovecs)) }
1181 }
1182}
1183
1184macro_rules! buf_slice_for_tuple {
1185 (
1186 $N: expr,
1188 $( $generic: ident . $index: tt ),+
1190 ) => {
1191 unsafe impl<$( $generic: BufMut ),+> BufMutSlice<$N> for ($( $generic ),+) {
1195 unsafe fn as_iovecs_mut(&mut self) -> [libc::iovec; $N] {
1196 [
1197 $({
1198 debug_assert!(
1199 self.$index.buffer_group().is_none(),
1200 "can't use a10::ReadBuf as a10::BufMutSlice in vectored I/O"
1201 );
1202 let (ptr, len) = self.$index.parts_mut();
1203 libc::iovec {
1204 iov_base: ptr.cast(),
1205 iov_len: len as _,
1206 }
1207 }),+
1208 ]
1209 }
1210
1211 unsafe fn set_init(&mut self, n: usize) {
1212 let mut left = n;
1213 $({
1214 let (_, len) = self.$index.parts_mut();
1215 let len = len as usize;
1216 if len < left {
1217 self.$index.set_init(len);
1219 left -= len;
1220 } else {
1221 self.$index.set_init(left);
1223 return;
1224 }
1225 })+
1226 unreachable!(
1227 "called BufMutSlice::set_init({n}), with buffers totaling in {} in size",
1228 n - left
1229 );
1230 }
1231 }
1232
1233 unsafe impl<$( $generic: Buf ),+> BufSlice<$N> for ($( $generic ),+) {
1237 unsafe fn as_iovecs(&self) -> [libc::iovec; $N] {
1238 [
1239 $({
1240 let (ptr, len) = self.$index.parts();
1241 libc::iovec {
1242 iov_base: ptr as _,
1243 iov_len: len as _,
1244 }
1245 }),+
1246 ]
1247 }
1248 }
1249 };
1250}
1251
1252buf_slice_for_tuple!(2, A.0, B.1);
1253buf_slice_for_tuple!(3, A.0, B.1, C.2);
1254buf_slice_for_tuple!(4, A.0, B.1, C.2, D.3);
1255buf_slice_for_tuple!(5, A.0, B.1, C.2, D.3, E.4);
1256buf_slice_for_tuple!(6, A.0, B.1, C.2, D.3, E.4, F.5);
1257buf_slice_for_tuple!(7, A.0, B.1, C.2, D.3, E.4, F.5, G.6);
1258buf_slice_for_tuple!(8, A.0, B.1, C.2, D.3, E.4, F.5, G.6, I.7);