#![unstable(reason = "not public", issue = "none", feature = "fd")] use crate::cmp; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, SeekFrom}; use crate::os::hermit::hermit_abi; use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::sys::{cvt, unsupported}; use crate::sys_common::{AsInner, FromInner, IntoInner}; const fn max_iov() -> usize { hermit_abi::IOV_MAX } #[derive(Debug)] pub struct FileDesc { fd: OwnedFd, } impl FileDesc { pub fn read(&self, buf: &mut [u8]) -> io::Result { let result = cvt(unsafe { hermit_abi::read(self.fd.as_raw_fd(), buf.as_mut_ptr(), buf.len()) })?; Ok(result as usize) } pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { // SAFETY: The `read` syscall does not read from the buffer, so it is // safe to use `&mut [MaybeUninit]`. let result = cvt(unsafe { hermit_abi::read( self.fd.as_raw_fd(), buf.as_mut().as_mut_ptr() as *mut u8, buf.capacity(), ) })?; // SAFETY: Exactly `result` bytes have been filled. unsafe { buf.advance_unchecked(result as usize) }; Ok(()) } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { let ret = cvt(unsafe { hermit_abi::readv( self.as_raw_fd(), bufs.as_mut_ptr() as *mut hermit_abi::iovec as *const hermit_abi::iovec, cmp::min(bufs.len(), max_iov()), ) })?; Ok(ret as usize) } #[inline] pub fn is_read_vectored(&self) -> bool { true } pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { let mut me = self; (&mut me).read_to_end(buf) } pub fn write(&self, buf: &[u8]) -> io::Result { let result = cvt(unsafe { hermit_abi::write(self.fd.as_raw_fd(), buf.as_ptr(), buf.len()) })?; Ok(result as usize) } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { let ret = cvt(unsafe { hermit_abi::writev( self.as_raw_fd(), bufs.as_ptr() as *const hermit_abi::iovec, cmp::min(bufs.len(), max_iov()), ) })?; Ok(ret as usize) } #[inline] pub fn is_write_vectored(&self) -> bool { true } pub fn seek(&self, pos: SeekFrom) -> io::Result { let (whence, pos) = match pos { // Casting to `i64` is fine, too large values will end up as // negative which will cause an error in `lseek`. SeekFrom::Start(off) => (hermit_abi::SEEK_SET, off as i64), SeekFrom::End(off) => (hermit_abi::SEEK_END, off), SeekFrom::Current(off) => (hermit_abi::SEEK_CUR, off), }; let n = cvt(unsafe { hermit_abi::lseek(self.as_raw_fd(), pos as isize, whence) })?; Ok(n as u64) } pub fn tell(&self) -> io::Result { self.seek(SeekFrom::Current(0)) } pub fn duplicate(&self) -> io::Result { self.duplicate_path(&[]) } pub fn duplicate_path(&self, _path: &[u8]) -> io::Result { unsupported() } pub fn nonblocking(&self) -> io::Result { Ok(false) } pub fn set_cloexec(&self) -> io::Result<()> { unsupported() } pub fn set_nonblocking(&self, _nonblocking: bool) -> io::Result<()> { unsupported() } pub fn fstat(&self, stat: *mut hermit_abi::stat) -> io::Result<()> { cvt(unsafe { hermit_abi::fstat(self.fd.as_raw_fd(), stat) })?; Ok(()) } } impl<'a> Read for &'a FileDesc { fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) } } impl IntoInner for FileDesc { fn into_inner(self) -> OwnedFd { self.fd } } impl FromInner for FileDesc { fn from_inner(owned_fd: OwnedFd) -> Self { Self { fd: owned_fd } } } impl FromRawFd for FileDesc { unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { let fd = unsafe { OwnedFd::from_raw_fd(raw_fd) }; Self { fd } } } impl AsInner for FileDesc { #[inline] fn as_inner(&self) -> &OwnedFd { &self.fd } } impl AsFd for FileDesc { fn as_fd(&self) -> BorrowedFd<'_> { self.fd.as_fd() } } impl AsRawFd for FileDesc { #[inline] fn as_raw_fd(&self) -> RawFd { self.fd.as_raw_fd() } } impl IntoRawFd for FileDesc { fn into_raw_fd(self) -> RawFd { self.fd.into_raw_fd() } }