add support of RustyHermit's BSD socket layer

RustHermit publishs a new kernel interface and supports
a common BSD socket layer. By supporting this interface,
the implementation can be harmonized to other operating systems.

To realize this socket layer, the handling of file descriptors
is also harmonized to other operating systems.
This commit is contained in:
Stefan Lankes 2022-12-06 20:31:43 +01:00
parent 07c993eba8
commit 7143379a52
11 changed files with 818 additions and 465 deletions

View file

@ -1927,8 +1927,16 @@ version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
dependencies = [
"compiler_builtins",
"libc",
]
[[package]]
name = "hermit-abi"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "856b5cb0902c2b6d65d5fd97dfa30f9b70c7538e770b98eab5ed52d8db923e01"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
@ -5294,7 +5302,7 @@ dependencies = [
"dlmalloc",
"fortanix-sgx-abi",
"hashbrown 0.12.3",
"hermit-abi 0.2.6",
"hermit-abi 0.3.0",
"libc",
"miniz_oxide",
"object 0.29.0",

View file

@ -43,7 +43,7 @@ dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] }
fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'] }
[target.'cfg(target_os = "hermit")'.dependencies]
hermit-abi = { version = "0.2.6", features = ['rustc-dep-of-std'] }
hermit-abi = { version = "0.3.0", features = ['rustc-dep-of-std'] }
[target.wasm32-wasi.dependencies]
wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }

View file

@ -0,0 +1,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
use hermit_abi as abi;
#[stable(feature = "rust1", since = "1.0.0")]
pub type RawFd = abi::FileDescriptor;

View file

@ -1,36 +1,26 @@
#![unstable(reason = "not public", issue = "none", feature = "fd")]
mod owned;
mod raw;
use crate::io::{self, Read};
use crate::mem;
use crate::sys::cvt;
use crate::sys::hermit::abi;
use crate::sys::unsupported;
use crate::sys_common::AsInner;
use crate::sys_common::{AsInner, FromInner, IntoInner};
pub use self::owned::*;
pub use self::raw::*;
#[derive(Debug)]
pub struct FileDesc {
fd: i32,
fd: OwnedFd,
}
impl FileDesc {
pub fn new(fd: i32) -> FileDesc {
FileDesc { fd }
}
pub fn raw(&self) -> i32 {
self.fd
}
/// Extracts the actual file descriptor without closing it.
pub fn into_raw(self) -> i32 {
let fd = self.fd;
mem::forget(self);
fd
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
let result = unsafe { abi::read(self.fd, buf.as_mut_ptr(), buf.len()) };
cvt(result as i32)
let result = cvt(unsafe { abi::read(self.fd.as_raw_fd(), buf.as_mut_ptr(), buf.len()) })?;
Ok(result as usize)
}
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
@ -39,8 +29,8 @@ pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let result = unsafe { abi::write(self.fd, buf.as_ptr(), buf.len()) };
cvt(result as i32)
let result = cvt(unsafe { abi::write(self.fd.as_raw_fd(), buf.as_ptr(), buf.len()) })?;
Ok(result as usize)
}
pub fn duplicate(&self) -> io::Result<FileDesc> {
@ -69,19 +59,39 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
}
}
impl AsInner<i32> for FileDesc {
fn as_inner(&self) -> &i32 {
impl IntoInner<OwnedFd> for FileDesc {
fn into_inner(self) -> OwnedFd {
self.fd
}
}
impl FromInner<OwnedFd> 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 {
Self { fd: FromRawFd::from_raw_fd(raw_fd) }
}
}
impl AsInner<OwnedFd> for FileDesc {
fn as_inner(&self) -> &OwnedFd {
&self.fd
}
}
impl Drop for FileDesc {
fn drop(&mut self) {
// Note that errors are ignored when closing a file descriptor. The
// reason for this is that if an error occurs we don't actually know if
// the file descriptor was closed or not, and if we retried (for
// something like EINTR), we might close another valid file descriptor
// (opened after we closed ours.
let _ = unsafe { abi::close(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()
}
}

View file

@ -0,0 +1,238 @@
use super::raw::RawFd;
use crate::marker::PhantomData;
use crate::mem::forget;
use crate::sys::fd::{AsRawFd, FromRawFd, IntoRawFd};
use crate::sys::hermit::abi;
use crate::sys_common::{AsInner, FromInner, IntoInner};
/// A borrowed file descriptor.
///
/// This has a lifetime parameter to tie it to the lifetime of something that
/// owns the file descriptor.
///
/// This uses `repr(transparent)` and has the representation of a host file
/// descriptor, so it can be used in FFI in places where a file descriptor is
/// passed as an argument, it is not captured or consumed, and it never has the
/// value `-1`.
///
/// This type's `.to_owned()` implementation returns another `BorrowedFd`
/// rather than an `OwnedFd`. It just makes a trivial copy of the raw file
/// descriptor, which is then borrowed under the same lifetime.
#[derive(Copy, Clone)]
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(0)]
// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
// 32-bit c_int. Below is -2, in two's complement, but that only works out
// because c_int is 32 bits.
#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
#[rustc_nonnull_optimization_guaranteed]
#[stable(feature = "io_safety", since = "1.63.0")]
pub struct BorrowedFd<'fd> {
fd: RawFd,
_phantom: PhantomData<&'fd OwnedFd>,
}
/// An owned file descriptor.
///
/// This closes the file descriptor on drop.
///
/// This uses `repr(transparent)` and has the representation of a host file
/// descriptor, so it can be used in FFI in places where a file descriptor is
/// passed as a consumed argument or returned as an owned value, and it never
/// has the value `-1`.
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(0)]
// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
// 32-bit c_int. Below is -2, in two's complement, but that only works out
// because c_int is 32 bits.
#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
#[rustc_nonnull_optimization_guaranteed]
#[stable(feature = "io_safety", since = "1.63.0")]
#[derive(Debug)]
pub struct OwnedFd {
fd: RawFd,
}
impl BorrowedFd<'_> {
/// Return a `BorrowedFd` holding the given raw file descriptor.
///
/// # Safety
///
/// The resource pointed to by `fd` must remain open for the duration of
/// the returned `BorrowedFd`, and it must not have the value `-1`.
#[inline]
#[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
#[stable(feature = "io_safety", since = "1.63.0")]
pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
assert!(fd != u32::MAX as RawFd);
// SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
unsafe { Self { fd, _phantom: PhantomData } }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsRawFd for BorrowedFd<'_> {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsRawFd for OwnedFd {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl IntoRawFd for OwnedFd {
#[inline]
fn into_raw_fd(self) -> RawFd {
let fd = self.fd;
forget(self);
fd
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl FromRawFd for OwnedFd {
/// Constructs a new instance of `Self` from the given raw file descriptor.
///
/// # Safety
///
/// The resource pointed to by `fd` must be open and suitable for assuming
/// ownership. The resource must not require any cleanup other than `close`.
#[inline]
unsafe fn from_raw_fd(fd: RawFd) -> Self {
assert_ne!(fd, u32::MAX as RawFd);
// SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
unsafe { Self { fd } }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsFd for crate::net::TcpStream {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
self.as_inner().socket().as_fd()
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::net::TcpStream> for OwnedFd {
#[inline]
fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd {
tcp_stream.into_inner().into_socket().into_inner().into_inner().into()
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<OwnedFd> for crate::net::TcpStream {
#[inline]
fn from(owned_fd: OwnedFd) -> Self {
Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
owned_fd,
))))
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsFd for crate::net::TcpListener {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
self.as_inner().socket().as_fd()
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::net::TcpListener> for OwnedFd {
#[inline]
fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd {
tcp_listener.into_inner().into_socket().into_inner().into_inner().into()
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<OwnedFd> for crate::net::TcpListener {
#[inline]
fn from(owned_fd: OwnedFd) -> Self {
Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
owned_fd,
))))
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsFd for crate::net::UdpSocket {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
self.as_inner().socket().as_fd()
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::net::UdpSocket> for OwnedFd {
#[inline]
fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd {
udp_socket.into_inner().into_socket().into_inner().into_inner().into()
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<OwnedFd> for crate::net::UdpSocket {
#[inline]
fn from(owned_fd: OwnedFd) -> Self {
Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
owned_fd,
))))
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl Drop for OwnedFd {
#[inline]
fn drop(&mut self) {
unsafe {
// Note that errors are ignored when closing a file descriptor. The
// reason for this is that if an error occurs we don't actually know if
// the file descriptor was closed or not, and if we retried (for
// something like EINTR), we might close another valid file descriptor
// opened after we closed ours.
let _ = abi::close(self.fd);
}
}
}
pub trait AsFd {
/// Borrows the file descriptor.
///
/// # Example
///
/// ```rust,no_run
/// use std::fs::File;
/// # use std::io;
/// # #[cfg(any(unix, target_os = "wasi"))]
/// # use std::os::fd::{AsFd, BorrowedFd};
///
/// let mut f = File::open("foo.txt")?;
/// # #[cfg(any(unix, target_os = "wasi"))]
/// let borrowed_fd: BorrowedFd<'_> = f.as_fd();
/// # Ok::<(), io::Error>(())
/// ```
#[stable(feature = "io_safety", since = "1.63.0")]
fn as_fd(&self) -> BorrowedFd<'_>;
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsFd for OwnedFd {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
// Safety: `OwnedFd` and `BorrowedFd` have the same validity
// invariants, and the `BorrowdFd` is bounded by the lifetime
// of `&self`.
unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
}
}

View file

@ -0,0 +1,115 @@
/// Raw file descriptors.
#[rustc_allowed_through_unstable_modules]
#[stable(feature = "rust1", since = "1.0.0")]
pub type RawFd = i32;
/// A trait to extract the raw file descriptor from an underlying object.
///
/// This is only available on unix and WASI platforms and must be imported in
/// order to call the method. Windows platforms have a corresponding
/// `AsRawHandle` and `AsRawSocket` set of traits.
#[rustc_allowed_through_unstable_modules]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRawFd {
/// Extracts the raw file descriptor.
///
/// This function is typically used to **borrow** an owned file descriptor.
/// When used in this way, this method does **not** pass ownership of the
/// raw file descriptor to the caller, and the file descriptor is only
/// guaranteed to be valid while the original object has not yet been
/// destroyed.
///
/// However, borrowing is not strictly required. See [`AsFd::as_fd`]
/// for an API which strictly borrows a file descriptor.
///
/// # Example
///
/// ```no_run
/// use std::fs::File;
/// # use std::io;
/// #[cfg(any(unix, target_os = "wasi"))]
/// use std::os::fd::{AsRawFd, RawFd};
///
/// let mut f = File::open("foo.txt")?;
/// // Note that `raw_fd` is only valid as long as `f` exists.
/// #[cfg(any(unix, target_os = "wasi"))]
/// let raw_fd: RawFd = f.as_raw_fd();
/// # Ok::<(), io::Error>(())
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn as_raw_fd(&self) -> RawFd;
}
/// A trait to express the ability to consume an object and acquire ownership of
/// its raw file descriptor.
#[rustc_allowed_through_unstable_modules]
#[stable(feature = "into_raw_os", since = "1.4.0")]
pub trait IntoRawFd {
/// Consumes this object, returning the raw underlying file descriptor.
///
/// This function is typically used to **transfer ownership** of the underlying
/// file descriptor to the caller. When used in this way, callers are then the unique
/// owners of the file descriptor and must close it once it's no longer needed.
///
/// However, transferring ownership is not strictly required. Use a
/// [`Into<OwnedFd>::into`] implementation for an API which strictly
/// transfers ownership.
///
/// # Example
///
/// ```no_run
/// use std::fs::File;
/// # use std::io;
/// #[cfg(any(unix, target_os = "wasi"))]
/// use std::os::fd::{IntoRawFd, RawFd};
///
/// let f = File::open("foo.txt")?;
/// #[cfg(any(unix, target_os = "wasi"))]
/// let raw_fd: RawFd = f.into_raw_fd();
/// # Ok::<(), io::Error>(())
/// ```
#[stable(feature = "into_raw_os", since = "1.4.0")]
fn into_raw_fd(self) -> RawFd;
}
/// A trait to express the ability to construct an object from a raw file
/// descriptor.
#[rustc_allowed_through_unstable_modules]
#[stable(feature = "from_raw_os", since = "1.1.0")]
pub trait FromRawFd {
/// Constructs a new instance of `Self` from the given raw file
/// descriptor.
///
/// This function is typically used to **consume ownership** of the
/// specified file descriptor. When used in this way, the returned object
/// will take responsibility for closing it when the object goes out of
/// scope.
///
/// However, consuming ownership is not strictly required. Use a
/// [`From<OwnedFd>::from`] implementation for an API which strictly
/// consumes ownership.
///
/// # Safety
///
/// The `fd` passed in must be a valid and open file descriptor.
///
/// # Example
///
/// ```no_run
/// use std::fs::File;
/// # use std::io;
/// #[cfg(any(unix, target_os = "wasi"))]
/// use std::os::fd::{FromRawFd, IntoRawFd, RawFd};
///
/// let f = File::open("foo.txt")?;
/// # #[cfg(any(unix, target_os = "wasi"))]
/// let raw_fd: RawFd = f.into_raw_fd();
/// // SAFETY: no other functions should call `from_raw_fd`, so there
/// // is only one owner for the file descriptor.
/// # #[cfg(any(unix, target_os = "wasi"))]
/// let f = unsafe { File::from_raw_fd(raw_fd) };
/// # Ok::<(), io::Error>(())
/// ```
#[stable(feature = "from_raw_os", since = "1.1.0")]
unsafe fn from_raw_fd(fd: RawFd) -> Self;
}

View file

@ -8,7 +8,7 @@
use crate::sys::cvt;
use crate::sys::hermit::abi;
use crate::sys::hermit::abi::{O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY};
use crate::sys::hermit::fd::FileDesc;
use crate::sys::hermit::fd::{FileDesc, FromRawFd};
use crate::sys::time::SystemTime;
use crate::sys::unsupported;
@ -283,7 +283,7 @@ pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
}
let fd = unsafe { cvt(abi::open(path.as_ptr(), flags, mode))? };
Ok(File(FileDesc::new(fd as i32)))
Ok(File(unsafe { FileDesc::from_raw_fd(fd as i32) }))
}
pub fn file_attr(&self) -> io::Result<FileAttr> {

View file

@ -13,7 +13,7 @@
//! compiling for wasm. That way it's a compile time error for something that's
//! guaranteed to be a runtime error!
#![allow(unsafe_op_in_unsafe_fn)]
#![allow(missing_docs, nonstandard_style, unsafe_op_in_unsafe_fn)]
use crate::intrinsics;
use crate::os::raw::c_char;
@ -126,25 +126,72 @@ pub unsafe fn cleanup() {}
pub fn decode_error_kind(errno: i32) -> ErrorKind {
match errno {
x if x == 13 as i32 => ErrorKind::PermissionDenied,
x if x == 98 as i32 => ErrorKind::AddrInUse,
x if x == 99 as i32 => ErrorKind::AddrNotAvailable,
x if x == 11 as i32 => ErrorKind::WouldBlock,
x if x == 103 as i32 => ErrorKind::ConnectionAborted,
x if x == 111 as i32 => ErrorKind::ConnectionRefused,
x if x == 104 as i32 => ErrorKind::ConnectionReset,
x if x == 17 as i32 => ErrorKind::AlreadyExists,
x if x == 4 as i32 => ErrorKind::Interrupted,
x if x == 22 as i32 => ErrorKind::InvalidInput,
x if x == 2 as i32 => ErrorKind::NotFound,
x if x == 107 as i32 => ErrorKind::NotConnected,
x if x == 1 as i32 => ErrorKind::PermissionDenied,
x if x == 32 as i32 => ErrorKind::BrokenPipe,
x if x == 110 as i32 => ErrorKind::TimedOut,
abi::errno::EACCES => ErrorKind::PermissionDenied,
abi::errno::EADDRINUSE => ErrorKind::AddrInUse,
abi::errno::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
abi::errno::EAGAIN => ErrorKind::WouldBlock,
abi::errno::ECONNABORTED => ErrorKind::ConnectionAborted,
abi::errno::ECONNREFUSED => ErrorKind::ConnectionRefused,
abi::errno::ECONNRESET => ErrorKind::ConnectionReset,
abi::errno::EEXIST => ErrorKind::AlreadyExists,
abi::errno::EINTR => ErrorKind::Interrupted,
abi::errno::EINVAL => ErrorKind::InvalidInput,
abi::errno::ENOENT => ErrorKind::NotFound,
abi::errno::ENOTCONN => ErrorKind::NotConnected,
abi::errno::EPERM => ErrorKind::PermissionDenied,
abi::errno::EPIPE => ErrorKind::BrokenPipe,
abi::errno::ETIMEDOUT => ErrorKind::TimedOut,
_ => ErrorKind::Uncategorized,
}
}
pub fn cvt(result: i32) -> crate::io::Result<usize> {
if result < 0 { Err(crate::io::Error::from_raw_os_error(-result)) } else { Ok(result as usize) }
#[doc(hidden)]
pub trait IsNegative {
fn is_negative(&self) -> bool;
fn negate(&self) -> i32;
}
macro_rules! impl_is_negative {
($($t:ident)*) => ($(impl IsNegative for $t {
fn is_negative(&self) -> bool {
*self < 0
}
fn negate(&self) -> i32 {
i32::try_from(-(*self)).unwrap()
}
})*)
}
impl IsNegative for i32 {
fn is_negative(&self) -> bool {
*self < 0
}
fn negate(&self) -> i32 {
-(*self)
}
}
impl_is_negative! { i8 i16 i64 isize }
pub fn cvt<T: IsNegative>(t: T) -> crate::io::Result<T> {
if t.is_negative() {
let e = decode_error_kind(t.negate());
Err(crate::io::Error::from(e))
} else {
Ok(t)
}
}
pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
where
T: IsNegative,
F: FnMut() -> T,
{
loop {
match cvt(f()) {
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
other => return other,
}
}
}

View file

@ -1,129 +1,177 @@
use crate::fmt;
use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
use crate::str;
use crate::sync::Arc;
use crate::sys::hermit::abi;
use crate::sys::hermit::abi::IpAddress::{Ipv4, Ipv6};
use crate::sys::unsupported;
use crate::sys_common::AsInner;
#![allow(dead_code)]
use crate::cmp;
use crate::io::{self, IoSlice, IoSliceMut};
use crate::mem;
use crate::net::{Shutdown, SocketAddr};
use crate::sys::fd::{AsFd, AsRawFd, BorrowedFd, FileDesc, FromRawFd, RawFd};
use crate::sys::time::Instant;
use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::time::Duration;
use core::ffi::c_int;
#[allow(unused_extern_crates)]
pub extern crate hermit_abi as netc;
pub use crate::sys::{cvt, cvt_r};
pub type wrlen_t = usize;
pub fn cvt_gai(err: i32) -> io::Result<()> {
if err == 0 {
return Ok(());
}
let detail = "";
Err(io::Error::new(
io::ErrorKind::Uncategorized,
&format!("failed to lookup address information: {detail}")[..],
))
}
/// Checks whether the HermitCore's socket interface has been started already, and
/// if not, starts it.
pub fn init() -> io::Result<()> {
if abi::network_init() < 0 {
return Err(io::const_io_error!(
ErrorKind::Uncategorized,
"Unable to initialize network interface",
));
}
Ok(())
}
#[derive(Debug, Clone)]
pub struct Socket(abi::Handle);
impl AsInner<abi::Handle> for Socket {
fn as_inner(&self) -> &abi::Handle {
&self.0
pub fn init() {
if unsafe { netc::network_init() } < 0 {
panic!("Unable to initialize network interface");
}
}
impl Drop for Socket {
fn drop(&mut self) {
let _ = abi::tcpstream::close(self.0);
#[derive(Debug)]
pub struct Socket(FileDesc);
impl Socket {
pub fn new(addr: &SocketAddr, ty: i32) -> io::Result<Socket> {
let fam = match *addr {
SocketAddr::V4(..) => netc::AF_INET,
SocketAddr::V6(..) => netc::AF_INET6,
};
Socket::new_raw(fam, ty)
}
}
// Arc is used to count the number of used sockets.
// Only if all sockets are released, the drop
// method will close the socket.
#[derive(Clone)]
pub struct TcpStream(Arc<Socket>);
pub fn new_raw(fam: i32, ty: i32) -> io::Result<Socket> {
let fd = cvt(unsafe { netc::socket(fam, ty, 0) })?;
Ok(Socket(unsafe { FileDesc::from_raw_fd(fd) }))
}
impl TcpStream {
pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
let addr = addr?;
pub fn new_pair(_fam: i32, _ty: i32) -> io::Result<(Socket, Socket)> {
unimplemented!()
}
match abi::tcpstream::connect(addr.ip().to_string().as_bytes(), addr.port(), None) {
Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))),
_ => Err(io::const_io_error!(
ErrorKind::Uncategorized,
"Unable to initiate a connection on a socket",
)),
pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
self.set_nonblocking(true)?;
let r = unsafe {
let (addr, len) = addr.into_inner();
cvt(netc::connect(self.as_raw_fd(), addr.as_ptr(), len))
};
self.set_nonblocking(false)?;
match r {
Ok(_) => return Ok(()),
// there's no ErrorKind for EINPROGRESS :(
Err(ref e) if e.raw_os_error() == Some(netc::errno::EINPROGRESS) => {}
Err(e) => return Err(e),
}
let mut pollfd = netc::pollfd { fd: self.as_raw_fd(), events: netc::POLLOUT, revents: 0 };
if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
"cannot set a 0 duration timeout",
));
}
let start = Instant::now();
loop {
let elapsed = start.elapsed();
if elapsed >= timeout {
return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out"));
}
let timeout = timeout - elapsed;
let mut timeout = timeout
.as_secs()
.saturating_mul(1_000)
.saturating_add(timeout.subsec_nanos() as u64 / 1_000_000);
if timeout == 0 {
timeout = 1;
}
let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int;
match unsafe { netc::poll(&mut pollfd, 1, timeout) } {
-1 => {
let err = io::Error::last_os_error();
if err.kind() != io::ErrorKind::Interrupted {
return Err(err);
}
}
0 => {}
_ => {
// linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
// for POLLHUP rather than read readiness
if pollfd.revents & netc::POLLHUP != 0 {
let e = self.take_error()?.unwrap_or_else(|| {
io::const_io_error!(
io::ErrorKind::Uncategorized,
"no error set after POLLHUP",
)
});
return Err(e);
}
return Ok(());
}
}
}
}
pub fn connect_timeout(saddr: &SocketAddr, duration: Duration) -> io::Result<TcpStream> {
match abi::tcpstream::connect(
saddr.ip().to_string().as_bytes(),
saddr.port(),
Some(duration.as_millis() as u64),
) {
Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))),
_ => Err(io::const_io_error!(
ErrorKind::Uncategorized,
"Unable to initiate a connection on a socket",
)),
}
pub fn accept(
&self,
storage: *mut netc::sockaddr,
len: *mut netc::socklen_t,
) -> io::Result<Socket> {
let fd = cvt(unsafe { netc::accept(self.0.as_raw_fd(), storage, len) })?;
Ok(Socket(unsafe { FileDesc::from_raw_fd(fd) }))
}
pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
abi::tcpstream::set_read_timeout(*self.0.as_inner(), duration.map(|d| d.as_millis() as u64))
.map_err(|_| {
io::const_io_error!(ErrorKind::Uncategorized, "Unable to set timeout value")
})
pub fn duplicate(&self) -> io::Result<Socket> {
let fd = cvt(unsafe { netc::dup(self.0.as_raw_fd()) })?;
Ok(Socket(unsafe { FileDesc::from_raw_fd(fd) }))
}
pub fn set_write_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
abi::tcpstream::set_write_timeout(
*self.0.as_inner(),
duration.map(|d| d.as_millis() as u64),
)
.map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "Unable to set timeout value"))
fn recv_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<usize> {
let ret =
cvt(unsafe { netc::recv(self.0.as_raw_fd(), buf.as_mut_ptr(), buf.len(), flags) })?;
Ok(ret as usize)
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
let duration = abi::tcpstream::get_read_timeout(*self.0.as_inner()).map_err(|_| {
io::const_io_error!(ErrorKind::Uncategorized, "Unable to determine timeout value")
})?;
Ok(duration.map(|d| Duration::from_millis(d)))
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
let duration = abi::tcpstream::get_write_timeout(*self.0.as_inner()).map_err(|_| {
io::const_io_error!(ErrorKind::Uncategorized, "Unable to determine timeout value")
})?;
Ok(duration.map(|d| Duration::from_millis(d)))
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.recv_with_flags(buf, 0)
}
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
abi::tcpstream::peek(*self.0.as_inner(), buf)
.map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "peek failed"))
self.recv_with_flags(buf, netc::MSG_PEEK)
}
pub fn read(&self, buffer: &mut [u8]) -> io::Result<usize> {
self.read_vectored(&mut [IoSliceMut::new(buffer)])
}
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let mut size: isize = 0;
pub fn read_vectored(&self, ioslice: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let mut size: usize = 0;
for i in ioslice.iter_mut() {
let ret = abi::tcpstream::read(*self.0.as_inner(), &mut i[0..]).map_err(|_| {
io::const_io_error!(ErrorKind::Uncategorized, "Unable to read on socket")
})?;
for i in bufs.iter_mut() {
let ret: isize =
cvt(unsafe { netc::read(self.0.as_raw_fd(), i.as_mut_ptr(), i.len()) })?;
if ret != 0 {
size += ret;
}
}
Ok(size)
Ok(size.try_into().unwrap())
}
#[inline]
@ -131,360 +179,174 @@ pub fn is_read_vectored(&self) -> bool {
true
}
pub fn write(&self, buffer: &[u8]) -> io::Result<usize> {
self.write_vectored(&[IoSlice::new(buffer)])
fn recv_from_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<(usize, SocketAddr)> {
let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() };
let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t;
let n = cvt(unsafe {
netc::recvfrom(
self.as_raw_fd(),
buf.as_mut_ptr(),
buf.len(),
flags,
&mut storage as *mut _ as *mut _,
&mut addrlen,
)
})?;
Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
}
pub fn write_vectored(&self, ioslice: &[IoSlice<'_>]) -> io::Result<usize> {
let mut size: usize = 0;
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.recv_from_with_flags(buf, 0)
}
for i in ioslice.iter() {
size += abi::tcpstream::write(*self.0.as_inner(), i).map_err(|_| {
io::const_io_error!(ErrorKind::Uncategorized, "Unable to write on socket")
})?;
pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.recv_from_with_flags(buf, netc::MSG_PEEK)
}
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()) })?;
Ok(sz.try_into().unwrap())
}
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
let mut size: isize = 0;
for i in bufs.iter() {
size += cvt(unsafe { netc::write(self.0.as_raw_fd(), i.as_ptr(), i.len()) })?;
}
Ok(size)
Ok(size.try_into().unwrap())
}
#[inline]
pub fn is_write_vectored(&self) -> bool {
true
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
let (ipaddr, port) = abi::tcpstream::peer_addr(*self.0.as_inner())
.map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "peer_addr failed"))?;
pub fn set_timeout(&self, dur: Option<Duration>, kind: i32) -> io::Result<()> {
let timeout = match dur {
Some(dur) => {
if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
"cannot set a 0 duration timeout",
));
}
let saddr = match ipaddr {
Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port),
Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port),
_ => {
return Err(io::const_io_error!(ErrorKind::Uncategorized, "peer_addr failed"));
let secs = if dur.as_secs() > netc::time_t::MAX as u64 {
netc::time_t::MAX
} else {
dur.as_secs() as netc::time_t
};
let mut timeout = netc::timeval {
tv_sec: secs,
tv_usec: dur.subsec_micros() as netc::suseconds_t,
};
if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
timeout.tv_usec = 1;
}
timeout
}
None => netc::timeval { tv_sec: 0, tv_usec: 0 },
};
Ok(saddr)
setsockopt(self, netc::SOL_SOCKET, kind, timeout)
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
unsupported()
pub fn timeout(&self, kind: i32) -> io::Result<Option<Duration>> {
let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?;
if raw.tv_sec == 0 && raw.tv_usec == 0 {
Ok(None)
} else {
let sec = raw.tv_sec as u64;
let nsec = (raw.tv_usec as u32) * 1000;
Ok(Some(Duration::new(sec, nsec)))
}
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
abi::tcpstream::shutdown(*self.0.as_inner(), how as i32)
.map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to shutdown socket"))
let how = match how {
Shutdown::Write => netc::SHUT_WR,
Shutdown::Read => netc::SHUT_RD,
Shutdown::Both => netc::SHUT_RDWR,
};
cvt(unsafe { netc::shutdown_socket(self.as_raw_fd(), how) })?;
Ok(())
}
pub fn duplicate(&self) -> io::Result<TcpStream> {
Ok(self.clone())
}
pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
let linger = netc::linger {
l_onoff: linger.is_some() as i32,
l_linger: linger.unwrap_or_default().as_secs() as libc::c_int,
};
pub fn set_linger(&self, _linger: Option<Duration>) -> io::Result<()> {
unsupported()
setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger)
}
pub fn linger(&self) -> io::Result<Option<Duration>> {
unsupported()
let val: netc::linger = getsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER)?;
Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64)))
}
pub fn set_nodelay(&self, mode: bool) -> io::Result<()> {
abi::tcpstream::set_nodelay(*self.0.as_inner(), mode)
.map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "set_nodelay failed"))
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
let value: i32 = if nodelay { 1 } else { 0 };
setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, value)
}
pub fn nodelay(&self) -> io::Result<bool> {
abi::tcpstream::nodelay(*self.0.as_inner())
.map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "nodelay failed"))
let raw: i32 = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?;
Ok(raw != 0)
}
pub fn set_ttl(&self, tll: u32) -> io::Result<()> {
abi::tcpstream::set_tll(*self.0.as_inner(), tll)
.map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to set TTL"))
}
pub fn ttl(&self) -> io::Result<u32> {
abi::tcpstream::get_tll(*self.0.as_inner())
.map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to get TTL"))
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
unsupported()
}
pub fn set_nonblocking(&self, mode: bool) -> io::Result<()> {
abi::tcpstream::set_nonblocking(*self.0.as_inner(), mode).map_err(|_| {
io::const_io_error!(ErrorKind::Uncategorized, "unable to set blocking mode")
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
let mut nonblocking: i32 = if nonblocking { 1 } else { 0 };
cvt(unsafe {
netc::ioctl(
self.as_raw_fd(),
netc::FIONBIO,
&mut nonblocking as *mut _ as *mut core::ffi::c_void,
)
})
}
}
impl fmt::Debug for TcpStream {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
Ok(())
}
}
#[derive(Clone)]
pub struct TcpListener(SocketAddr);
impl TcpListener {
pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
let addr = addr?;
Ok(TcpListener(*addr))
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
Ok(self.0)
}
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
let (handle, ipaddr, port) = abi::tcplistener::accept(self.0.port())
.map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "accept failed"))?;
let saddr = match ipaddr {
Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port),
Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port),
_ => {
return Err(io::const_io_error!(ErrorKind::Uncategorized, "accept failed"));
}
};
Ok((TcpStream(Arc::new(Socket(handle))), saddr))
}
pub fn duplicate(&self) -> io::Result<TcpListener> {
Ok(self.clone())
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
unsupported()
}
pub fn ttl(&self) -> io::Result<u32> {
unsupported()
}
pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
unsupported()
}
pub fn only_v6(&self) -> io::Result<bool> {
unsupported()
.map(drop)
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
unsupported()
unimplemented!()
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
unsupported()
// This is used by sys_common code to abstract over Windows and Unix.
pub fn as_raw(&self) -> RawFd {
self.0.as_raw_fd()
}
}
impl fmt::Debug for TcpListener {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
Ok(())
impl AsInner<FileDesc> for Socket {
fn as_inner(&self) -> &FileDesc {
&self.0
}
}
pub struct UdpSocket(abi::Handle);
impl UdpSocket {
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
unsupported()
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
unsupported()
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
unsupported()
}
pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
unsupported()
}
pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
unsupported()
}
pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
unsupported()
}
pub fn duplicate(&self) -> io::Result<UdpSocket> {
unsupported()
}
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
unsupported()
}
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
unsupported()
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
unsupported()
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
unsupported()
}
pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
unsupported()
}
pub fn broadcast(&self) -> io::Result<bool> {
unsupported()
}
pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
unsupported()
}
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
unsupported()
}
pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
unsupported()
}
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
unsupported()
}
pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
unsupported()
}
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
unsupported()
}
pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
unsupported()
}
pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
unsupported()
}
pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
unsupported()
}
pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
unsupported()
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
unsupported()
}
pub fn ttl(&self) -> io::Result<u32> {
unsupported()
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
unsupported()
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
unsupported()
}
pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
unsupported()
}
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
unsupported()
}
pub fn send(&self, _: &[u8]) -> io::Result<usize> {
unsupported()
}
pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
unsupported()
}
}
impl fmt::Debug for UdpSocket {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
Ok(())
}
}
pub struct LookupHost(!);
impl LookupHost {
pub fn port(&self) -> u16 {
impl IntoInner<FileDesc> for Socket {
fn into_inner(self) -> FileDesc {
self.0
}
}
impl Iterator for LookupHost {
type Item = SocketAddr;
fn next(&mut self) -> Option<SocketAddr> {
self.0
impl FromInner<FileDesc> for Socket {
fn from_inner(file_desc: FileDesc) -> Self {
Self(file_desc)
}
}
impl TryFrom<&str> for LookupHost {
type Error = io::Error;
fn try_from(_v: &str) -> io::Result<LookupHost> {
unsupported()
impl AsFd for Socket {
fn as_fd(&self) -> BorrowedFd<'_> {
self.0.as_fd()
}
}
impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
type Error = io::Error;
fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
unsupported()
impl AsRawFd for Socket {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
#[allow(nonstandard_style)]
pub mod netc {
pub const AF_INET: u8 = 0;
pub const AF_INET6: u8 = 1;
pub type sa_family_t = u8;
#[derive(Copy, Clone)]
pub struct in_addr {
pub s_addr: u32,
}
#[derive(Copy, Clone)]
pub struct sockaddr_in {
pub sin_family: sa_family_t,
pub sin_port: u16,
pub sin_addr: in_addr,
}
#[derive(Copy, Clone)]
pub struct in6_addr {
pub s6_addr: [u8; 16],
}
#[derive(Copy, Clone)]
pub struct sockaddr_in6 {
pub sin6_family: sa_family_t,
pub sin6_port: u16,
pub sin6_addr: in6_addr,
pub sin6_flowinfo: u32,
pub sin6_scope_id: u32,
}
#[derive(Copy, Clone)]
pub struct sockaddr {}
}

View file

@ -1,6 +1,7 @@
#![allow(dead_code)]
use crate::cmp::Ordering;
use crate::ops::{Add, AddAssign, Sub, SubAssign};
use crate::sys::hermit::abi;
use crate::sys::hermit::abi::timespec;
use crate::sys::hermit::abi::{CLOCK_MONOTONIC, CLOCK_REALTIME, NSEC_PER_SEC};
@ -102,55 +103,122 @@ fn hash<H: Hasher>(&self, state: &mut H) {
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Instant {
t: Timespec,
}
pub struct Instant(Timespec);
impl Instant {
pub fn now() -> Instant {
let mut time: Timespec = Timespec::zero();
let _ = unsafe { abi::clock_gettime(CLOCK_MONOTONIC, &mut time.t as *mut timespec) };
Instant { t: time }
Instant(time)
}
#[stable(feature = "time2", since = "1.8.0")]
pub fn elapsed(&self) -> Duration {
Instant::now() - *self
}
pub fn duration_since(&self, earlier: Instant) -> Duration {
self.checked_duration_since(earlier).unwrap_or_default()
}
pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
self.checked_sub_instant(&earlier)
}
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
self.t.sub_timespec(&other.t).ok()
self.0.sub_timespec(&other.0).ok()
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
Some(Instant { t: self.t.checked_add_duration(other)? })
Some(Instant(self.0.checked_add_duration(other)?))
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
Some(Instant { t: self.t.checked_sub_duration(other)? })
Some(Instant(self.0.checked_sub_duration(other)?))
}
pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
self.0.checked_add_duration(&duration).map(Instant)
}
pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
self.0.checked_sub_duration(&duration).map(Instant)
}
}
impl Add<Duration> for Instant {
type Output = Instant;
/// # Panics
///
/// This function may panic if the resulting point in time cannot be represented by the
/// underlying data structure. See [`Instant::checked_add`] for a version without panic.
fn add(self, other: Duration) -> Instant {
self.checked_add(other).expect("overflow when adding duration to instant")
}
}
impl AddAssign<Duration> for Instant {
fn add_assign(&mut self, other: Duration) {
*self = *self + other;
}
}
impl Sub<Duration> for Instant {
type Output = Instant;
fn sub(self, other: Duration) -> Instant {
self.checked_sub(other).expect("overflow when subtracting duration from instant")
}
}
impl SubAssign<Duration> for Instant {
fn sub_assign(&mut self, other: Duration) {
*self = *self - other;
}
}
impl Sub<Instant> for Instant {
type Output = Duration;
/// Returns the amount of time elapsed from another instant to this one,
/// or zero duration if that instant is later than this one.
///
/// # Panics
///
/// Previous rust versions panicked when `other` was later than `self`. Currently this
/// method saturates. Future versions may reintroduce the panic in some circumstances.
/// See [Monotonicity].
///
/// [Monotonicity]: Instant#monotonicity
fn sub(self, other: Instant) -> Duration {
self.duration_since(other)
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct SystemTime {
t: Timespec,
}
pub struct SystemTime(Timespec);
pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero());
impl SystemTime {
pub fn now() -> SystemTime {
let mut time: Timespec = Timespec::zero();
let _ = unsafe { abi::clock_gettime(CLOCK_REALTIME, &mut time.t as *mut timespec) };
SystemTime { t: time }
SystemTime(time)
}
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.t.sub_timespec(&other.t)
self.0.sub_timespec(&other.0)
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime { t: self.t.checked_add_duration(other)? })
Some(SystemTime(self.0.checked_add_duration(other)?))
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime { t: self.t.checked_sub_duration(other)? })
Some(SystemTime(self.0.checked_sub_duration(other)?))
}
}

View file

@ -44,7 +44,6 @@
cfg_if::cfg_if! {
if #[cfg(any(target_os = "l4re",
target_os = "hermit",
feature = "restricted-std",
all(target_family = "wasm", not(target_os = "emscripten")),
all(target_vendor = "fortanix", target_env = "sgx")))] {