Rollup merge of #126135 - hermit-os:fuse, r=jhpratt

add HermitOS support for vectored read/write operations

In general, the I/O interface of hermit-abi is revised and now a more POSIX-like interface. Consequently, platform abstraction layer for HermitOS has slightly adjusted and some inaccuracies remove.

Hermit is a tier 3 platform and this PR changes only files, wich are related to the tier 3 platform.
This commit is contained in:
Matthias Krüger 2024-06-14 12:23:36 +02:00 committed by GitHub
commit 6396d4c846
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 189 additions and 94 deletions

View file

@ -1694,6 +1694,12 @@ name = "hermit-abi"
version = "0.3.9" version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
name = "hermit-abi"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
dependencies = [ dependencies = [
"compiler_builtins", "compiler_builtins",
"rustc-std-workspace-alloc", "rustc-std-workspace-alloc",
@ -2636,7 +2642,7 @@ version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [ dependencies = [
"hermit-abi", "hermit-abi 0.3.9",
"libc", "libc",
] ]
@ -5346,7 +5352,7 @@ dependencies = [
"dlmalloc", "dlmalloc",
"fortanix-sgx-abi", "fortanix-sgx-abi",
"hashbrown", "hashbrown",
"hermit-abi", "hermit-abi 0.4.0",
"libc", "libc",
"miniz_oxide", "miniz_oxide",
"object 0.36.0", "object 0.36.0",

View file

@ -50,7 +50,7 @@ dlmalloc = { version = "0.2.4", features = ['rustc-dep-of-std'] }
fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'], public = true } fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'], public = true }
[target.'cfg(target_os = "hermit")'.dependencies] [target.'cfg(target_os = "hermit")'.dependencies]
hermit-abi = { version = "0.3.9", features = ['rustc-dep-of-std'], public = true } hermit-abi = { version = "0.4.0", features = ['rustc-dep-of-std'], public = true }
[target.'cfg(target_os = "wasi")'.dependencies] [target.'cfg(target_os = "wasi")'.dependencies]
wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false } wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }

View file

@ -1,7 +1,8 @@
#![unstable(reason = "not public", issue = "none", feature = "fd")] #![unstable(reason = "not public", issue = "none", feature = "fd")]
use super::hermit_abi; use super::hermit_abi;
use crate::io::{self, Read}; use crate::cmp;
use crate::io::{self, IoSlice, IoSliceMut, Read};
use crate::os::hermit::io::{FromRawFd, OwnedFd, RawFd}; use crate::os::hermit::io::{FromRawFd, OwnedFd, RawFd};
use crate::sys::cvt; use crate::sys::cvt;
use crate::sys::unsupported; use crate::sys::unsupported;
@ -9,6 +10,10 @@
use crate::os::hermit::io::*; use crate::os::hermit::io::*;
const fn max_iov() -> usize {
hermit_abi::IOV_MAX
}
#[derive(Debug)] #[derive(Debug)]
pub struct FileDesc { pub struct FileDesc {
fd: OwnedFd, fd: OwnedFd,
@ -21,6 +26,22 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
Ok(result as usize) Ok(result as usize)
} }
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
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<u8>) -> io::Result<usize> { pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
let mut me = self; let mut me = self;
(&mut me).read_to_end(buf) (&mut me).read_to_end(buf)
@ -32,6 +53,22 @@ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
Ok(result as usize) Ok(result as usize)
} }
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
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 duplicate(&self) -> io::Result<FileDesc> { pub fn duplicate(&self) -> io::Result<FileDesc> {
self.duplicate_path(&[]) self.duplicate_path(&[])
} }

View file

@ -1,7 +1,7 @@
use super::fd::FileDesc; use super::fd::FileDesc;
use super::hermit_abi::{ use super::hermit_abi::{
self, dirent64, stat as stat_struct, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, self, dirent64, stat as stat_struct, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT,
O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, O_DIRECTORY, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG,
}; };
use crate::ffi::{CStr, OsStr, OsString}; use crate::ffi::{CStr, OsStr, OsString};
use crate::fmt; use crate::fmt;
@ -62,7 +62,7 @@ pub struct DirEntry {
/// 64-bit inode number /// 64-bit inode number
ino: u64, ino: u64,
/// File type /// File type
type_: u32, type_: u8,
/// name of the entry /// name of the entry
name: OsString, name: OsString,
} }
@ -90,7 +90,7 @@ pub struct FilePermissions {
#[derive(Copy, Clone, Eq, Debug)] #[derive(Copy, Clone, Eq, Debug)]
pub struct FileType { pub struct FileType {
mode: u32, mode: u8,
} }
impl PartialEq for FileType { impl PartialEq for FileType {
@ -112,31 +112,23 @@ pub struct DirBuilder {
impl FileAttr { impl FileAttr {
pub fn modified(&self) -> io::Result<SystemTime> { pub fn modified(&self) -> io::Result<SystemTime> {
Ok(SystemTime::new( Ok(SystemTime::new(self.stat_val.st_mtim.tv_sec, self.stat_val.st_mtim.tv_nsec))
self.stat_val.st_mtime.try_into().unwrap(),
self.stat_val.st_mtime_nsec.try_into().unwrap(),
))
} }
pub fn accessed(&self) -> io::Result<SystemTime> { pub fn accessed(&self) -> io::Result<SystemTime> {
Ok(SystemTime::new( Ok(SystemTime::new(self.stat_val.st_atim.tv_sec, self.stat_val.st_atim.tv_nsec))
self.stat_val.st_atime.try_into().unwrap(),
self.stat_val.st_atime_nsec.try_into().unwrap(),
))
} }
pub fn created(&self) -> io::Result<SystemTime> { pub fn created(&self) -> io::Result<SystemTime> {
Ok(SystemTime::new( Ok(SystemTime::new(self.stat_val.st_ctim.tv_sec, self.stat_val.st_ctim.tv_nsec))
self.stat_val.st_ctime.try_into().unwrap(),
self.stat_val.st_ctime_nsec.try_into().unwrap(),
))
} }
pub fn size(&self) -> u64 { pub fn size(&self) -> u64 {
self.stat_val.st_size as u64 self.stat_val.st_size as u64
} }
pub fn perm(&self) -> FilePermissions { pub fn perm(&self) -> FilePermissions {
FilePermissions { mode: (self.stat_val.st_mode) } FilePermissions { mode: self.stat_val.st_mode }
} }
pub fn file_type(&self) -> FileType { pub fn file_type(&self) -> FileType {
@ -220,7 +212,7 @@ fn next(&mut self) -> Option<io::Result<DirEntry>> {
let entry = DirEntry { let entry = DirEntry {
root: self.inner.root.clone(), root: self.inner.root.clone(),
ino: dir.d_ino, ino: dir.d_ino,
type_: dir.d_type as u32, type_: dir.d_type,
name: OsString::from_vec(name_bytes.to_vec()), name: OsString::from_vec(name_bytes.to_vec()),
}; };
@ -251,7 +243,7 @@ pub fn metadata(&self) -> io::Result<FileAttr> {
} }
pub fn file_type(&self) -> io::Result<FileType> { pub fn file_type(&self) -> io::Result<FileType> {
Ok(FileType { mode: self.type_ as u32 }) Ok(FileType { mode: self.type_ })
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -385,12 +377,12 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
} }
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
crate::io::default_read_vectored(|buf| self.read(buf), bufs) self.0.read_vectored(bufs)
} }
#[inline] #[inline]
pub fn is_read_vectored(&self) -> bool { pub fn is_read_vectored(&self) -> bool {
false self.0.is_read_vectored()
} }
pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
@ -402,12 +394,12 @@ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
} }
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
crate::io::default_write_vectored(|buf| self.write(buf), bufs) self.0.write_vectored(bufs)
} }
#[inline] #[inline]
pub fn is_write_vectored(&self) -> bool { pub fn is_write_vectored(&self) -> bool {
false self.0.is_write_vectored()
} }
#[inline] #[inline]
@ -439,13 +431,13 @@ pub fn new() -> DirBuilder {
pub fn mkdir(&self, path: &Path) -> io::Result<()> { pub fn mkdir(&self, path: &Path) -> io::Result<()> {
run_path_with_cstr(path, &|path| { run_path_with_cstr(path, &|path| {
cvt(unsafe { hermit_abi::mkdir(path.as_ptr(), self.mode) }).map(|_| ()) cvt(unsafe { hermit_abi::mkdir(path.as_ptr(), self.mode.into()) }).map(|_| ())
}) })
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn set_mode(&mut self, mode: u32) { pub fn set_mode(&mut self, mode: u32) {
self.mode = mode as u32; self.mode = mode;
} }
} }
@ -501,8 +493,9 @@ unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
} }
pub fn readdir(path: &Path) -> io::Result<ReadDir> { pub fn readdir(path: &Path) -> io::Result<ReadDir> {
let fd_raw = let fd_raw = run_path_with_cstr(path, &|path| {
run_path_with_cstr(path, &|path| cvt(unsafe { hermit_abi::opendir(path.as_ptr()) }))?; cvt(unsafe { hermit_abi::open(path.as_ptr(), O_RDONLY | O_DIRECTORY, 0) })
})?;
let fd = unsafe { FileDesc::from_raw_fd(fd_raw as i32) }; let fd = unsafe { FileDesc::from_raw_fd(fd_raw as i32) };
let root = path.to_path_buf(); let root = path.to_path_buf();

View file

@ -10,7 +10,7 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
let timespec = timeout.and_then(|dur| { let timespec = timeout.and_then(|dur| {
Some(hermit_abi::timespec { Some(hermit_abi::timespec {
tv_sec: dur.as_secs().try_into().ok()?, tv_sec: dur.as_secs().try_into().ok()?,
tv_nsec: dur.subsec_nanos().into(), tv_nsec: dur.subsec_nanos().try_into().ok()?,
}) })
}); });

View file

@ -0,0 +1,82 @@
use crate::marker::PhantomData;
use crate::os::hermit::io::{AsFd, AsRawFd};
use crate::slice;
use hermit_abi::{c_void, iovec};
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct IoSlice<'a> {
vec: iovec,
_p: PhantomData<&'a [u8]>,
}
impl<'a> IoSlice<'a> {
#[inline]
pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
IoSlice {
vec: iovec { iov_base: buf.as_ptr() as *mut u8 as *mut c_void, iov_len: buf.len() },
_p: PhantomData,
}
}
#[inline]
pub fn advance(&mut self, n: usize) {
if self.vec.iov_len < n {
panic!("advancing IoSlice beyond its length");
}
unsafe {
self.vec.iov_len -= n;
self.vec.iov_base = self.vec.iov_base.add(n);
}
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
}
}
#[repr(transparent)]
pub struct IoSliceMut<'a> {
vec: iovec,
_p: PhantomData<&'a mut [u8]>,
}
impl<'a> IoSliceMut<'a> {
#[inline]
pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
IoSliceMut {
vec: iovec { iov_base: buf.as_mut_ptr() as *mut c_void, iov_len: buf.len() },
_p: PhantomData,
}
}
#[inline]
pub fn advance(&mut self, n: usize) {
if self.vec.iov_len < n {
panic!("advancing IoSliceMut beyond its length");
}
unsafe {
self.vec.iov_len -= n;
self.vec.iov_base = self.vec.iov_base.add(n);
}
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
}
}
pub fn is_terminal(fd: &impl AsFd) -> bool {
let fd = fd.as_fd();
hermit_abi::isatty(fd.as_raw_fd())
}

View file

@ -23,7 +23,6 @@
pub mod fd; pub mod fd;
pub mod fs; pub mod fs;
pub mod futex; pub mod futex;
#[path = "../unsupported/io.rs"]
pub mod io; pub mod io;
pub mod net; pub mod net;
pub mod os; pub mod os;

View file

@ -175,12 +175,12 @@ pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
} }
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
crate::io::default_read_vectored(|b| self.read(b), bufs) self.0.read_vectored(bufs)
} }
#[inline] #[inline]
pub fn is_read_vectored(&self) -> bool { pub fn is_read_vectored(&self) -> bool {
false self.0.is_read_vectored()
} }
fn recv_from_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<(usize, SocketAddr)> { fn recv_from_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<(usize, SocketAddr)> {
@ -209,16 +209,15 @@ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
} }
pub fn write(&self, buf: &[u8]) -> io::Result<usize> { pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let sz = cvt(unsafe { netc::write(self.0.as_raw_fd(), buf.as_ptr(), buf.len()) })?; self.0.write(buf)
Ok(sz.try_into().unwrap())
} }
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
crate::io::default_write_vectored(|b| self.write(b), bufs) self.0.write_vectored(bufs)
} }
pub fn is_write_vectored(&self) -> bool { pub fn is_write_vectored(&self) -> bool {
false self.0.is_write_vectored()
} }
pub fn set_timeout(&self, dur: Option<Duration>, kind: i32) -> io::Result<()> { pub fn set_timeout(&self, dur: Option<Duration>, kind: i32) -> io::Result<()> {
@ -265,7 +264,7 @@ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
Shutdown::Read => netc::SHUT_RD, Shutdown::Read => netc::SHUT_RD,
Shutdown::Both => netc::SHUT_RDWR, Shutdown::Both => netc::SHUT_RDWR,
}; };
cvt(unsafe { netc::shutdown_socket(self.as_raw_fd(), how) })?; cvt(unsafe { netc::shutdown(self.as_raw_fd(), how) })?;
Ok(()) Ok(())
} }

View file

@ -198,5 +198,5 @@ pub fn exit(code: i32) -> ! {
} }
pub fn getpid() -> u32 { pub fn getpid() -> u32 {
unsafe { hermit_abi::getpid() } unsafe { hermit_abi::getpid() as u32 }
} }

View file

@ -1,6 +1,9 @@
use super::hermit_abi; use super::hermit_abi;
use crate::io; use crate::io;
use crate::io::{IoSlice, IoSliceMut}; use crate::io::{IoSlice, IoSliceMut};
use crate::mem::ManuallyDrop;
use crate::os::hermit::io::FromRawFd;
use crate::sys::fd::FileDesc;
pub struct Stdin; pub struct Stdin;
pub struct Stdout; pub struct Stdout;
@ -13,12 +16,14 @@ pub const fn new() -> Stdin {
} }
impl io::Read for Stdin { impl io::Read for Stdin {
fn read(&mut self, data: &mut [u8]) -> io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.read_vectored(&mut [IoSliceMut::new(data)]) unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDIN_FILENO)).read(buf) }
} }
fn read_vectored(&mut self, _data: &mut [IoSliceMut<'_>]) -> io::Result<usize> { fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
Ok(0) unsafe {
ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDIN_FILENO)).read_vectored(bufs)
}
} }
#[inline] #[inline]
@ -34,27 +39,13 @@ pub const fn new() -> Stdout {
} }
impl io::Write for Stdout { impl io::Write for Stdout {
fn write(&mut self, data: &[u8]) -> io::Result<usize> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let len; unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDOUT_FILENO)).write(buf) }
unsafe { len = hermit_abi::write(1, data.as_ptr() as *const u8, data.len()) }
if len < 0 {
Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stdout is not able to print"))
} else {
Ok(len as usize)
}
} }
fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> { fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
let len; unsafe {
ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDOUT_FILENO)).write_vectored(bufs)
unsafe { len = hermit_abi::write(1, data.as_ptr() as *const u8, data.len()) }
if len < 0 {
Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stdout is not able to print"))
} else {
Ok(len as usize)
} }
} }
@ -75,27 +66,13 @@ pub const fn new() -> Stderr {
} }
impl io::Write for Stderr { impl io::Write for Stderr {
fn write(&mut self, data: &[u8]) -> io::Result<usize> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let len; unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDERR_FILENO)).write(buf) }
unsafe { len = hermit_abi::write(2, data.as_ptr() as *const u8, data.len()) }
if len < 0 {
Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stderr is not able to print"))
} else {
Ok(len as usize)
}
} }
fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> { fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
let len; unsafe {
ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDERR_FILENO)).write_vectored(bufs)
unsafe { len = hermit_abi::write(2, data.as_ptr() as *const u8, data.len()) }
if len < 0 {
Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stderr is not able to print"))
} else {
Ok(len as usize)
} }
} }
@ -109,10 +86,10 @@ fn flush(&mut self) -> io::Result<()> {
} }
} }
pub const STDIN_BUF_SIZE: usize = 0; pub const STDIN_BUF_SIZE: usize = 128;
pub fn is_ebadf(_err: &io::Error) -> bool { pub fn is_ebadf(err: &io::Error) -> bool {
true err.raw_os_error() == Some(hermit_abi::EBADF)
} }
pub fn panic_output() -> Option<impl io::Write> { pub fn panic_output() -> Option<impl io::Write> {

View file

@ -98,5 +98,5 @@ pub fn into_id(self) -> Tid {
} }
pub fn available_parallelism() -> io::Result<NonZero<usize>> { pub fn available_parallelism() -> io::Result<NonZero<usize>> {
unsafe { Ok(NonZero::new_unchecked(hermit_abi::get_processor_count())) } unsafe { Ok(NonZero::new_unchecked(hermit_abi::available_parallelism())) }
} }

View file

@ -1,11 +1,13 @@
#![allow(dead_code)] #![allow(dead_code)]
use super::hermit_abi::{self, timespec, CLOCK_MONOTONIC, CLOCK_REALTIME, NSEC_PER_SEC}; use super::hermit_abi::{self, timespec, CLOCK_MONOTONIC, CLOCK_REALTIME};
use crate::cmp::Ordering; use crate::cmp::Ordering;
use crate::ops::{Add, AddAssign, Sub, SubAssign}; use crate::ops::{Add, AddAssign, Sub, SubAssign};
use crate::time::Duration; use crate::time::Duration;
use core::hash::{Hash, Hasher}; use core::hash::{Hash, Hasher};
const NSEC_PER_SEC: i32 = 1_000_000_000;
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
struct Timespec { struct Timespec {
t: timespec, t: timespec,
@ -16,8 +18,8 @@ const fn zero() -> Timespec {
Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } } Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } }
} }
const fn new(tv_sec: i64, tv_nsec: i64) -> Timespec { const fn new(tv_sec: i64, tv_nsec: i32) -> Timespec {
assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC as i64); assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC);
// SAFETY: The assert above checks tv_nsec is within the valid range // SAFETY: The assert above checks tv_nsec is within the valid range
Timespec { t: timespec { tv_sec: tv_sec, tv_nsec: tv_nsec } } Timespec { t: timespec { tv_sec: tv_sec, tv_nsec: tv_nsec } }
} }
@ -32,7 +34,7 @@ fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
} else { } else {
Duration::new( Duration::new(
(self.t.tv_sec - 1 - other.t.tv_sec) as u64, (self.t.tv_sec - 1 - other.t.tv_sec) as u64,
self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32, (self.t.tv_nsec + NSEC_PER_SEC - other.t.tv_nsec) as u32,
) )
}) })
} else { } else {
@ -48,9 +50,9 @@ fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
// Nano calculations can't overflow because nanos are <1B which fit // Nano calculations can't overflow because nanos are <1B which fit
// in a u32. // in a u32.
let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; let mut nsec = other.subsec_nanos() + u32::try_from(self.t.tv_nsec).unwrap();
if nsec >= NSEC_PER_SEC as u32 { if nsec >= NSEC_PER_SEC.try_into().unwrap() {
nsec -= NSEC_PER_SEC as u32; nsec -= u32::try_from(NSEC_PER_SEC).unwrap();
secs = secs.checked_add(1)?; secs = secs.checked_add(1)?;
} }
Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } }) Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } })
@ -200,7 +202,7 @@ fn sub(self, other: Instant) -> Duration {
pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero()); pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero());
impl SystemTime { impl SystemTime {
pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime { pub fn new(tv_sec: i64, tv_nsec: i32) -> SystemTime {
SystemTime(Timespec::new(tv_sec, tv_nsec)) SystemTime(Timespec::new(tv_sec, tv_nsec))
} }