summaryrefslogtreecommitdiffstats
path: root/library/std
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:50 +0000
commit2e00214b3efbdfeefaa0fe9e8b8fd519de7adc35 (patch)
treed325add32978dbdc1db975a438b3a77d571b1ab8 /library/std
parentReleasing progress-linux version 1.68.2+dfsg1-1~progress7.99u1. (diff)
downloadrustc-2e00214b3efbdfeefaa0fe9e8b8fd519de7adc35.tar.xz
rustc-2e00214b3efbdfeefaa0fe9e8b8fd519de7adc35.zip
Merging upstream version 1.69.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/std')
-rw-r--r--library/std/Cargo.toml6
-rw-r--r--library/std/build.rs1
-rw-r--r--library/std/src/collections/hash/map.rs2
-rw-r--r--library/std/src/f32.rs4
-rw-r--r--library/std/src/f64.rs4
-rw-r--r--library/std/src/fs.rs20
-rw-r--r--library/std/src/fs/tests.rs20
-rw-r--r--library/std/src/io/error.rs19
-rw-r--r--library/std/src/io/error/repr_bitpacked.rs9
-rw-r--r--library/std/src/io/error/repr_unpacked.rs4
-rw-r--r--library/std/src/io/error/tests.rs4
-rw-r--r--library/std/src/io/mod.rs2
-rw-r--r--library/std/src/keyword_docs.rs2
-rw-r--r--library/std/src/lib.rs10
-rw-r--r--library/std/src/net/display_buffer.rs40
-rw-r--r--library/std/src/net/ip_addr.rs2075
-rw-r--r--library/std/src/net/ip_addr/tests.rs1035
-rw-r--r--library/std/src/net/mod.rs6
-rw-r--r--library/std/src/net/parser.rs500
-rw-r--r--library/std/src/net/parser/tests.rs149
-rw-r--r--library/std/src/net/socket_addr.rs689
-rw-r--r--library/std/src/net/socket_addr/tests.rs8
-rw-r--r--library/std/src/net/tcp.rs2
-rw-r--r--library/std/src/net/tcp/tests.rs5
-rw-r--r--library/std/src/net/udp/tests.rs5
-rw-r--r--library/std/src/os/fd/owned.rs17
-rw-r--r--library/std/src/os/fd/raw.rs18
-rw-r--r--library/std/src/os/fuchsia/raw.rs7
-rw-r--r--library/std/src/os/hermit/io/mod.rs13
-rw-r--r--library/std/src/os/hermit/io/net.rs46
-rw-r--r--library/std/src/os/hermit/mod.rs5
-rw-r--r--library/std/src/os/l4re/raw.rs1
-rw-r--r--library/std/src/os/linux/raw.rs1
-rw-r--r--library/std/src/os/mod.rs14
-rw-r--r--library/std/src/os/net/mod.rs9
-rw-r--r--library/std/src/os/nto/fs.rs92
-rw-r--r--library/std/src/os/nto/mod.rs4
-rw-r--r--library/std/src/os/nto/raw.rs40
-rw-r--r--library/std/src/os/unix/fs.rs30
-rw-r--r--library/std/src/os/unix/fs/tests.rs57
-rw-r--r--library/std/src/os/unix/mod.rs5
-rw-r--r--library/std/src/os/unix/net/datagram.rs6
-rw-r--r--library/std/src/os/unix/net/tests.rs1
-rw-r--r--library/std/src/os/unix/process.rs26
-rw-r--r--library/std/src/os/unix/ucred.rs3
-rw-r--r--library/std/src/panicking.rs16
-rw-r--r--library/std/src/path.rs4
-rw-r--r--library/std/src/personality/emcc.rs2
-rw-r--r--library/std/src/personality/gcc.rs3
-rw-r--r--library/std/src/primitive_docs.rs6
-rw-r--r--library/std/src/process.rs2
-rw-r--r--library/std/src/sync/lazy_lock.rs86
-rw-r--r--library/std/src/sync/mod.rs2
-rw-r--r--library/std/src/sync/mpmc/array.rs18
-rw-r--r--library/std/src/sync/mpmc/utils.rs12
-rw-r--r--library/std/src/sync/once.rs16
-rw-r--r--library/std/src/sys/common/alloc.rs1
-rw-r--r--library/std/src/sys/hermit/args.rs2
-rw-r--r--library/std/src/sys/hermit/fd.rs77
-rw-r--r--library/std/src/sys/hermit/fs.rs57
-rw-r--r--library/std/src/sys/hermit/mod.rs92
-rw-r--r--library/std/src/sys/hermit/net.rs639
-rw-r--r--library/std/src/sys/hermit/os.rs2
-rw-r--r--library/std/src/sys/hermit/thread.rs4
-rw-r--r--library/std/src/sys/hermit/thread_local_dtor.rs23
-rw-r--r--library/std/src/sys/hermit/time.rs98
-rw-r--r--library/std/src/sys/itron/thread.rs2
-rw-r--r--library/std/src/sys/itron/thread_parking.rs37
-rw-r--r--library/std/src/sys/itron/wait_flag.rs72
-rw-r--r--library/std/src/sys/solid/mod.rs4
-rw-r--r--library/std/src/sys/solid/thread_local_dtor.rs32
-rw-r--r--library/std/src/sys/unix/args.rs31
-rw-r--r--library/std/src/sys/unix/env.rs11
-rw-r--r--library/std/src/sys/unix/fd.rs203
-rw-r--r--library/std/src/sys/unix/fs.rs92
-rw-r--r--library/std/src/sys/unix/locks/pthread_condvar.rs11
-rw-r--r--library/std/src/sys/unix/mod.rs2
-rw-r--r--library/std/src/sys/unix/net.rs2
-rw-r--r--library/std/src/sys/unix/os.rs12
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs74
-rw-r--r--library/std/src/sys/unix/thread.rs17
-rw-r--r--library/std/src/sys/unix/thread_local_dtor.rs36
-rw-r--r--library/std/src/sys/unix/thread_parking/pthread.rs9
-rw-r--r--library/std/src/sys/unix/time.rs22
-rw-r--r--library/std/src/sys/unsupported/once.rs11
-rw-r--r--library/std/src/sys/wasi/os.rs8
-rw-r--r--library/std/src/sys/windows/args.rs11
-rw-r--r--library/std/src/sys/windows/c.rs40
-rw-r--r--library/std/src/sys/windows/fs.rs9
-rw-r--r--library/std/src/sys/windows/io.rs32
-rw-r--r--library/std/src/sys/windows/stdio.rs75
-rw-r--r--library/std/src/sys/windows/thread.rs2
-rw-r--r--library/std/src/sys/windows/thread_parking.rs2
-rw-r--r--library/std/src/sys_common/backtrace.rs13
-rw-r--r--library/std/src/sys_common/mod.rs1
-rw-r--r--library/std/src/sys_common/net.rs15
-rw-r--r--library/std/src/sys_common/net/tests.rs2
-rw-r--r--library/std/src/sys_common/once/futex.rs11
-rw-r--r--library/std/src/sys_common/once/queue.rs11
-rw-r--r--library/std/src/sys_common/thread_local_dtor.rs2
-rw-r--r--library/std/src/sys_common/thread_local_key.rs10
-rw-r--r--library/std/src/sys_common/thread_parking/id.rs6
-rw-r--r--library/std/src/sys_common/thread_parking/mod.rs4
-rw-r--r--library/std/src/sys_common/thread_parking/wait_flag.rs102
-rw-r--r--library/std/src/sys_common/wtf8.rs8
-rw-r--r--library/std/src/thread/local.rs3
-rw-r--r--library/std/src/thread/mod.rs6
-rw-r--r--library/std/src/time.rs8
-rw-r--r--library/std/tests/common/mod.rs58
-rw-r--r--library/std/tests/create_dir_all_bare.rs39
-rw-r--r--library/std/tests/env.rs14
-rw-r--r--library/std/tests/run-time-detect.rs6
112 files changed, 1920 insertions, 5436 deletions
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index adf521d9b..598a4bf92 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -15,8 +15,8 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core" }
-libc = { version = "0.2.138", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.85" }
+libc = { version = "0.2.139", default-features = false, features = ['rustc-dep-of-std'] }
+compiler_builtins = { version = "0.1.87" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
hashbrown = { version = "0.12", default-features = false, features = ['rustc-dep-of-std'] }
@@ -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 }
diff --git a/library/std/build.rs b/library/std/build.rs
index 8b1a06ee7..ea8796675 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -31,6 +31,7 @@ fn main() {
|| target.contains("espidf")
|| target.contains("solid")
|| target.contains("nintendo-3ds")
+ || target.contains("nto")
{
// These platforms don't have any special requirements.
} else {
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index df4903588..742c4cc7c 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -238,7 +238,7 @@ impl<K, V> HashMap<K, V, RandomState> {
///
/// The hash map will be able to hold at least `capacity` elements without
/// reallocating. This method is allowed to allocate for more elements than
- /// `capacity`. If `capacity` is 0, the hash set will not allocate.
+ /// `capacity`. If `capacity` is 0, the hash map will not allocate.
///
/// # Examples
///
diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index 4e3007624..6b1f0cba8 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -69,8 +69,8 @@ impl f32 {
unsafe { intrinsics::ceilf32(self) }
}
- /// Returns the nearest integer to `self`. Round half-way cases away from
- /// `0.0`.
+ /// Returns the nearest integer to `self`. If a value is half-way between two
+ /// integers, round away from `0.0`.
///
/// # Examples
///
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index ec67fdad4..16359766b 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -69,8 +69,8 @@ impl f64 {
unsafe { intrinsics::ceilf64(self) }
}
- /// Returns the nearest integer to `self`. Round half-way cases away from
- /// `0.0`.
+ /// Returns the nearest integer to `self`. If a value is half-way between two
+ /// integers, round away from `0.0`.
///
/// # Examples
///
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 286ad68fd..c550378e7 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -334,6 +334,10 @@ impl File {
///
/// See the [`OpenOptions::open`] method for more details.
///
+ /// If you only need to read the entire file contents,
+ /// consider [`std::fs::read()`][self::read] or
+ /// [`std::fs::read_to_string()`][self::read_to_string] instead.
+ ///
/// # Errors
///
/// This function will return an error if `path` does not already exist.
@@ -343,9 +347,12 @@ impl File {
///
/// ```no_run
/// use std::fs::File;
+ /// use std::io::Read;
///
/// fn main() -> std::io::Result<()> {
/// let mut f = File::open("foo.txt")?;
+ /// let mut data = vec![];
+ /// f.read_to_end(&mut data)?;
/// Ok(())
/// }
/// ```
@@ -361,16 +368,20 @@ impl File {
///
/// Depending on the platform, this function may fail if the
/// full directory path does not exist.
- ///
/// See the [`OpenOptions::open`] function for more details.
///
+ /// See also [`std::fs::write()`][self::write] for a simple function to
+ /// create a file with a given data.
+ ///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
+ /// use std::io::Write;
///
/// fn main() -> std::io::Result<()> {
/// let mut f = File::create("foo.txt")?;
+ /// f.write_all(&1234_u32.to_be_bytes())?;
/// Ok(())
/// }
/// ```
@@ -397,9 +408,11 @@ impl File {
/// #![feature(file_create_new)]
///
/// use std::fs::File;
+ /// use std::io::Write;
///
/// fn main() -> std::io::Result<()> {
/// let mut f = File::create_new("foo.txt")?;
+ /// f.write_all("Hello, world!".as_bytes())?;
/// Ok(())
/// }
/// ```
@@ -426,9 +439,11 @@ impl File {
///
/// ```no_run
/// use std::fs::File;
+ /// use std::io::Write;
///
/// fn main() -> std::io::Result<()> {
/// let mut f = File::options().append(true).open("example.log")?;
+ /// writeln!(&mut f, "new line")?;
/// Ok(())
/// }
/// ```
@@ -966,6 +981,9 @@ impl OpenOptions {
/// In order for the file to be created, [`OpenOptions::write`] or
/// [`OpenOptions::append`] access must be used.
///
+ /// See also [`std::fs::write()`][self::write] for a simple function to
+ /// create a file with a given data.
+ ///
/// # Examples
///
/// ```no_run
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index eb582be01..909d9bf40 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -12,6 +12,8 @@ use crate::time::{Duration, Instant};
use rand::RngCore;
+#[cfg(target_os = "macos")]
+use crate::ffi::{c_char, c_int};
#[cfg(unix)]
use crate::os::unix::fs::symlink as symlink_dir;
#[cfg(unix)]
@@ -24,8 +26,6 @@ use crate::os::windows::fs::{symlink_dir, symlink_file};
use crate::sys::fs::symlink_junction;
#[cfg(target_os = "macos")]
use crate::sys::weak::weak;
-#[cfg(target_os = "macos")]
-use libc::{c_char, c_int};
macro_rules! check {
($e:expr) => {
@@ -1595,3 +1595,19 @@ fn test_read_dir_infinite_loop() {
// Check for duplicate errors
assert!(dir.filter(|e| e.is_err()).take(2).count() < 2);
}
+
+#[test]
+fn rename_directory() {
+ let tmpdir = tmpdir();
+ let old_path = tmpdir.join("foo/bar/baz");
+ fs::create_dir_all(&old_path).unwrap();
+ let test_file = &old_path.join("temp.txt");
+
+ File::create(test_file).unwrap();
+
+ let new_path = tmpdir.join("quux/blat");
+ fs::create_dir_all(&new_path).unwrap();
+ fs::rename(&old_path, &new_path.join("newdir")).unwrap();
+ assert!(new_path.join("newdir").is_dir());
+ assert!(new_path.join("newdir/temp.txt").exists());
+}
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index 3cabf2449..7f07e4fdd 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -88,12 +88,23 @@ impl From<alloc::ffi::NulError> for Error {
// doesn't accidentally get printed.
#[cfg_attr(test, derive(Debug))]
enum ErrorData<C> {
- Os(i32),
+ Os(RawOsError),
Simple(ErrorKind),
SimpleMessage(&'static SimpleMessage),
Custom(C),
}
+/// The type of raw OS error codes returned by [`Error::raw_os_error`].
+///
+/// This is an [`i32`] on all currently supported platforms, but platforms
+/// added in the future (such as UEFI) may use a different primitive type like
+/// [`usize`]. Use `as`or [`into`] conversions where applicable to ensure maximum
+/// portability.
+///
+/// [`into`]: Into::into
+#[unstable(feature = "raw_os_error_ty", issue = "107792")]
+pub type RawOsError = i32;
+
// `#[repr(align(4))]` is probably redundant, it should have that value or
// higher already. We include it just because repr_bitpacked.rs's encoding
// requires an alignment >= 4 (note that `#[repr(align)]` will not reduce the
@@ -579,7 +590,7 @@ impl Error {
#[must_use]
#[inline]
pub fn last_os_error() -> Error {
- Error::from_raw_os_error(sys::os::errno() as i32)
+ Error::from_raw_os_error(sys::os::errno())
}
/// Creates a new instance of an [`Error`] from a particular OS error code.
@@ -610,7 +621,7 @@ impl Error {
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
#[inline]
- pub fn from_raw_os_error(code: i32) -> Error {
+ pub fn from_raw_os_error(code: RawOsError) -> Error {
Error { repr: Repr::new_os(code) }
}
@@ -646,7 +657,7 @@ impl Error {
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
#[inline]
- pub fn raw_os_error(&self) -> Option<i32> {
+ pub fn raw_os_error(&self) -> Option<RawOsError> {
match self.repr.data() {
ErrorData::Os(i) => Some(i),
ErrorData::Custom(..) => None,
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
index 358148405..f94f88bac 100644
--- a/library/std/src/io/error/repr_bitpacked.rs
+++ b/library/std/src/io/error/repr_bitpacked.rs
@@ -102,7 +102,7 @@
//! to use a pointer type to store something that may hold an integer, some of
//! the time.
-use super::{Custom, ErrorData, ErrorKind, SimpleMessage};
+use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage};
use alloc::boxed::Box;
use core::marker::PhantomData;
use core::mem::{align_of, size_of};
@@ -172,7 +172,7 @@ impl Repr {
}
#[inline]
- pub(super) fn new_os(code: i32) -> Self {
+ pub(super) fn new_os(code: RawOsError) -> Self {
let utagged = ((code as usize) << 32) | TAG_OS;
// Safety: `TAG_OS` is not zero, so the result of the `|` is not 0.
let res = Self(unsafe { NonNull::new_unchecked(ptr::invalid_mut(utagged)) }, PhantomData);
@@ -250,7 +250,7 @@ where
let bits = ptr.as_ptr().addr();
match bits & TAG_MASK {
TAG_OS => {
- let code = ((bits as i64) >> 32) as i32;
+ let code = ((bits as i64) >> 32) as RawOsError;
ErrorData::Os(code)
}
TAG_SIMPLE => {
@@ -374,6 +374,9 @@ static_assert!((TAG_MASK + 1).is_power_of_two());
static_assert!(align_of::<SimpleMessage>() >= TAG_MASK + 1);
static_assert!(align_of::<Custom>() >= TAG_MASK + 1);
+// `RawOsError` must be an alias for `i32`.
+const _: fn(RawOsError) -> i32 = |os| os;
+
static_assert!(@usize_eq: TAG_MASK & TAG_SIMPLE_MESSAGE, TAG_SIMPLE_MESSAGE);
static_assert!(@usize_eq: TAG_MASK & TAG_CUSTOM, TAG_CUSTOM);
static_assert!(@usize_eq: TAG_MASK & TAG_OS, TAG_OS);
diff --git a/library/std/src/io/error/repr_unpacked.rs b/library/std/src/io/error/repr_unpacked.rs
index d6ad55b99..093fde337 100644
--- a/library/std/src/io/error/repr_unpacked.rs
+++ b/library/std/src/io/error/repr_unpacked.rs
@@ -2,7 +2,7 @@
//! non-64bit targets, where the packed 64 bit representation wouldn't work, and
//! would have no benefit.
-use super::{Custom, ErrorData, ErrorKind, SimpleMessage};
+use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage};
use alloc::boxed::Box;
type Inner = ErrorData<Box<Custom>>;
@@ -18,7 +18,7 @@ impl Repr {
Self(Inner::Custom(b))
}
#[inline]
- pub(super) fn new_os(code: i32) -> Self {
+ pub(super) fn new_os(code: RawOsError) -> Self {
Self(Inner::Os(code))
}
#[inline]
diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs
index 16c634e9a..36d52aef0 100644
--- a/library/std/src/io/error/tests.rs
+++ b/library/std/src/io/error/tests.rs
@@ -71,7 +71,7 @@ fn test_const() {
#[test]
fn test_os_packing() {
- for code in -20i32..20i32 {
+ for code in -20..20 {
let e = Error::from_raw_os_error(code);
assert_eq!(e.raw_os_error(), Some(code));
assert_matches!(
@@ -190,5 +190,5 @@ fn test_std_io_error_downcast() {
let io_error = io_error.downcast::<E>().unwrap_err();
assert_eq!(SIMPLE_MESSAGE.kind, io_error.kind());
- assert_eq!(SIMPLE_MESSAGE.message, &*format!("{io_error}"));
+ assert_eq!(SIMPLE_MESSAGE.message, format!("{io_error}"));
}
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index de528e853..b2b6d8613 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -262,6 +262,8 @@ use crate::sys_common::memchr;
#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
pub use self::buffered::WriterPanicked;
+#[unstable(feature = "raw_os_error_ty", issue = "107792")]
+pub use self::error::RawOsError;
pub(crate) use self::stdio::attempt_print_to_stderr;
#[unstable(feature = "internal_output_capture", issue = "none")]
#[doc(no_inline, hidden)]
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index e35145c4a..203c490fa 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -1568,7 +1568,7 @@ mod static_keyword {}
///
/// # Style conventions
///
-/// Structs are always written in CamelCase, with few exceptions. While the trailing comma on a
+/// Structs are always written in UpperCamelCase, with few exceptions. While the trailing comma on a
/// struct's list of fields can be omitted, it's usually kept for convenience in adding and
/// removing fields down the line.
///
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index a7e13f5b8..b62f3ad29 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -232,13 +232,13 @@
all(target_vendor = "fortanix", target_env = "sgx"),
feature(slice_index_methods, coerce_unsized, sgx_platform)
)]
+#![cfg_attr(windows, feature(round_char_boundary))]
//
// Language features:
#![feature(alloc_error_handler)]
#![feature(allocator_internals)]
#![feature(allow_internal_unsafe)]
#![feature(allow_internal_unstable)]
-#![feature(box_syntax)]
#![feature(c_unwind)]
#![feature(cfg_target_thread_local)]
#![feature(concat_idents)]
@@ -274,13 +274,9 @@
#![feature(utf8_chunks)]
//
// Library features (core):
-#![feature(array_error_internals)]
#![feature(atomic_mut_ptr)]
-#![feature(char_error_internals)]
#![feature(char_internals)]
#![feature(core_intrinsics)]
-#![feature(cstr_from_bytes_until_nul)]
-#![feature(cstr_internals)]
#![feature(duration_constants)]
#![feature(error_generic_member_access)]
#![feature(error_in_core)]
@@ -292,7 +288,8 @@
#![feature(float_next_up_down)]
#![feature(hasher_prefixfree_extras)]
#![feature(hashmap_internals)]
-#![feature(int_error_internals)]
+#![feature(ip)]
+#![feature(ip_in_core)]
#![feature(is_some_and)]
#![feature(maybe_uninit_slice)]
#![feature(maybe_uninit_write_slice)]
@@ -359,7 +356,6 @@
#![feature(const_ip)]
#![feature(const_ipv4)]
#![feature(const_ipv6)]
-#![feature(const_socketaddr)]
#![feature(thread_local_internals)]
//
#![default_lib_allocator]
diff --git a/library/std/src/net/display_buffer.rs b/library/std/src/net/display_buffer.rs
deleted file mode 100644
index 7aadf06e9..000000000
--- a/library/std/src/net/display_buffer.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-use crate::fmt;
-use crate::mem::MaybeUninit;
-use crate::str;
-
-/// Used for slow path in `Display` implementations when alignment is required.
-pub struct DisplayBuffer<const SIZE: usize> {
- buf: [MaybeUninit<u8>; SIZE],
- len: usize,
-}
-
-impl<const SIZE: usize> DisplayBuffer<SIZE> {
- #[inline]
- pub const fn new() -> Self {
- Self { buf: MaybeUninit::uninit_array(), len: 0 }
- }
-
- #[inline]
- pub fn as_str(&self) -> &str {
- // SAFETY: `buf` is only written to by the `fmt::Write::write_str` implementation
- // which writes a valid UTF-8 string to `buf` and correctly sets `len`.
- unsafe {
- let s = MaybeUninit::slice_assume_init_ref(&self.buf[..self.len]);
- str::from_utf8_unchecked(s)
- }
- }
-}
-
-impl<const SIZE: usize> fmt::Write for DisplayBuffer<SIZE> {
- fn write_str(&mut self, s: &str) -> fmt::Result {
- let bytes = s.as_bytes();
-
- if let Some(buf) = self.buf.get_mut(self.len..(self.len + bytes.len())) {
- MaybeUninit::write_slice(buf, bytes);
- self.len += bytes.len();
- Ok(())
- } else {
- Err(fmt::Error)
- }
- }
-}
diff --git a/library/std/src/net/ip_addr.rs b/library/std/src/net/ip_addr.rs
index 07f08c1b5..e167fbd1b 100644
--- a/library/std/src/net/ip_addr.rs
+++ b/library/std/src/net/ip_addr.rs
@@ -2,2101 +2,40 @@
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
-use crate::cmp::Ordering;
-use crate::fmt::{self, Write};
-use crate::mem::transmute;
use crate::sys::net::netc as c;
use crate::sys_common::{FromInner, IntoInner};
-use super::display_buffer::DisplayBuffer;
-
-/// An IP address, either IPv4 or IPv6.
-///
-/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their
-/// respective documentation for more details.
-///
-/// # Examples
-///
-/// ```
-/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-///
-/// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
-/// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
-///
-/// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4));
-/// assert_eq!("::1".parse(), Ok(localhost_v6));
-///
-/// assert_eq!(localhost_v4.is_ipv6(), false);
-/// assert_eq!(localhost_v4.is_ipv4(), true);
-/// ```
-#[cfg_attr(not(test), rustc_diagnostic_item = "IpAddr")]
#[stable(feature = "ip_addr", since = "1.7.0")]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
-pub enum IpAddr {
- /// An IPv4 address.
- #[stable(feature = "ip_addr", since = "1.7.0")]
- V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr),
- /// An IPv6 address.
- #[stable(feature = "ip_addr", since = "1.7.0")]
- V6(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv6Addr),
-}
+pub use core::net::IpAddr;
-/// An IPv4 address.
-///
-/// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791].
-/// They are usually represented as four octets.
-///
-/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
-///
-/// [IETF RFC 791]: https://tools.ietf.org/html/rfc791
-///
-/// # Textual representation
-///
-/// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal
-/// notation, divided by `.` (this is called "dot-decimal notation").
-/// Notably, octal numbers (which are indicated with a leading `0`) and hexadecimal numbers (which
-/// are indicated with a leading `0x`) are not allowed per [IETF RFC 6943].
-///
-/// [IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1
-/// [`FromStr`]: crate::str::FromStr
-///
-/// # Examples
-///
-/// ```
-/// use std::net::Ipv4Addr;
-///
-/// let localhost = Ipv4Addr::new(127, 0, 0, 1);
-/// assert_eq!("127.0.0.1".parse(), Ok(localhost));
-/// assert_eq!(localhost.is_loopback(), true);
-/// assert!("012.004.002.000".parse::<Ipv4Addr>().is_err()); // all octets are in octal
-/// assert!("0000000.0.0.0".parse::<Ipv4Addr>().is_err()); // first octet is a zero in octal
-/// assert!("0xcb.0x0.0x71.0x00".parse::<Ipv4Addr>().is_err()); // all octets are in hex
-/// ```
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Ipv4Addr {
- octets: [u8; 4],
-}
+pub use core::net::{Ipv4Addr, Ipv6Addr};
-/// An IPv6 address.
-///
-/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291].
-/// They are usually represented as eight 16-bit segments.
-///
-/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
-///
-/// # Embedding IPv4 Addresses
-///
-/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
-///
-/// To assist in the transition from IPv4 to IPv6 two types of IPv6 addresses that embed an IPv4 address were defined:
-/// IPv4-compatible and IPv4-mapped addresses. Of these IPv4-compatible addresses have been officially deprecated.
-///
-/// Both types of addresses are not assigned any special meaning by this implementation,
-/// other than what the relevant standards prescribe. This means that an address like `::ffff:127.0.0.1`,
-/// while representing an IPv4 loopback address, is not itself an IPv6 loopback address; only `::1` is.
-/// To handle these so called "IPv4-in-IPv6" addresses, they have to first be converted to their canonical IPv4 address.
-///
-/// ### IPv4-Compatible IPv6 Addresses
-///
-/// IPv4-compatible IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.1], and have been officially deprecated.
-/// The RFC describes the format of an "IPv4-Compatible IPv6 address" as follows:
-///
-/// ```text
-/// | 80 bits | 16 | 32 bits |
-/// +--------------------------------------+--------------------------+
-/// |0000..............................0000|0000| IPv4 address |
-/// +--------------------------------------+----+---------------------+
-/// ```
-/// So `::a.b.c.d` would be an IPv4-compatible IPv6 address representing the IPv4 address `a.b.c.d`.
-///
-/// To convert from an IPv4 address to an IPv4-compatible IPv6 address, use [`Ipv4Addr::to_ipv6_compatible`].
-/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-compatible IPv6 address to the canonical IPv4 address.
-///
-/// [IETF RFC 4291 Section 2.5.5.1]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.1
-///
-/// ### IPv4-Mapped IPv6 Addresses
-///
-/// IPv4-mapped IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.2].
-/// The RFC describes the format of an "IPv4-Mapped IPv6 address" as follows:
-///
-/// ```text
-/// | 80 bits | 16 | 32 bits |
-/// +--------------------------------------+--------------------------+
-/// |0000..............................0000|FFFF| IPv4 address |
-/// +--------------------------------------+----+---------------------+
-/// ```
-/// So `::ffff:a.b.c.d` would be an IPv4-mapped IPv6 address representing the IPv4 address `a.b.c.d`.
-///
-/// To convert from an IPv4 address to an IPv4-mapped IPv6 address, use [`Ipv4Addr::to_ipv6_mapped`].
-/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-mapped IPv6 address to the canonical IPv4 address.
-/// Note that this will also convert the IPv6 loopback address `::1` to `0.0.0.1`. Use
-/// [`Ipv6Addr::to_ipv4_mapped`] to avoid this.
-///
-/// [IETF RFC 4291 Section 2.5.5.2]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2
-///
-/// # Textual representation
-///
-/// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent
-/// an IPv6 address in text, but in general, each segments is written in hexadecimal
-/// notation, and segments are separated by `:`. For more information, see
-/// [IETF RFC 5952].
-///
-/// [`FromStr`]: crate::str::FromStr
-/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952
-///
-/// # Examples
-///
-/// ```
-/// use std::net::Ipv6Addr;
-///
-/// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
-/// assert_eq!("::1".parse(), Ok(localhost));
-/// assert_eq!(localhost.is_loopback(), true);
-/// ```
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Ipv6Addr {
- octets: [u8; 16],
-}
-
-/// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2].
-///
-/// # Stability Guarantees
-///
-/// Not all possible values for a multicast scope have been assigned.
-/// Future RFCs may introduce new scopes, which will be added as variants to this enum;
-/// because of this the enum is marked as `#[non_exhaustive]`.
-///
-/// # Examples
-/// ```
-/// #![feature(ip)]
-///
-/// use std::net::Ipv6Addr;
-/// use std::net::Ipv6MulticastScope::*;
-///
-/// // An IPv6 multicast address with global scope (`ff0e::`).
-/// let address = Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0);
-///
-/// // Will print "Global scope".
-/// match address.multicast_scope() {
-/// Some(InterfaceLocal) => println!("Interface-Local scope"),
-/// Some(LinkLocal) => println!("Link-Local scope"),
-/// Some(RealmLocal) => println!("Realm-Local scope"),
-/// Some(AdminLocal) => println!("Admin-Local scope"),
-/// Some(SiteLocal) => println!("Site-Local scope"),
-/// Some(OrganizationLocal) => println!("Organization-Local scope"),
-/// Some(Global) => println!("Global scope"),
-/// Some(_) => println!("Unknown scope"),
-/// None => println!("Not a multicast address!")
-/// }
-///
-/// ```
-///
-/// [IPv6 multicast address]: Ipv6Addr
-/// [IETF RFC 7346 section 2]: https://tools.ietf.org/html/rfc7346#section-2
-#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
#[unstable(feature = "ip", issue = "27709")]
-#[non_exhaustive]
-pub enum Ipv6MulticastScope {
- /// Interface-Local scope.
- InterfaceLocal,
- /// Link-Local scope.
- LinkLocal,
- /// Realm-Local scope.
- RealmLocal,
- /// Admin-Local scope.
- AdminLocal,
- /// Site-Local scope.
- SiteLocal,
- /// Organization-Local scope.
- OrganizationLocal,
- /// Global scope.
- Global,
-}
-
-impl IpAddr {
- /// Returns [`true`] for the special 'unspecified' address.
- ///
- /// See the documentation for [`Ipv4Addr::is_unspecified()`] and
- /// [`Ipv6Addr::is_unspecified()`] for more details.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
- ///
- /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true);
- /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true);
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(feature = "ip_shared", since = "1.12.0")]
- #[must_use]
- #[inline]
- pub const fn is_unspecified(&self) -> bool {
- match self {
- IpAddr::V4(ip) => ip.is_unspecified(),
- IpAddr::V6(ip) => ip.is_unspecified(),
- }
- }
-
- /// Returns [`true`] if this is a loopback address.
- ///
- /// See the documentation for [`Ipv4Addr::is_loopback()`] and
- /// [`Ipv6Addr::is_loopback()`] for more details.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
- ///
- /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true);
- /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true);
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(feature = "ip_shared", since = "1.12.0")]
- #[must_use]
- #[inline]
- pub const fn is_loopback(&self) -> bool {
- match self {
- IpAddr::V4(ip) => ip.is_loopback(),
- IpAddr::V6(ip) => ip.is_loopback(),
- }
- }
-
- /// Returns [`true`] if the address appears to be globally routable.
- ///
- /// See the documentation for [`Ipv4Addr::is_global()`] and
- /// [`Ipv6Addr::is_global()`] for more details.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(ip)]
- ///
- /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
- ///
- /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true);
- /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true);
- /// ```
- #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
- #[unstable(feature = "ip", issue = "27709")]
- #[must_use]
- #[inline]
- pub const fn is_global(&self) -> bool {
- match self {
- IpAddr::V4(ip) => ip.is_global(),
- IpAddr::V6(ip) => ip.is_global(),
- }
- }
-
- /// Returns [`true`] if this is a multicast address.
- ///
- /// See the documentation for [`Ipv4Addr::is_multicast()`] and
- /// [`Ipv6Addr::is_multicast()`] for more details.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
- ///
- /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true);
- /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true);
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(feature = "ip_shared", since = "1.12.0")]
- #[must_use]
- #[inline]
- pub const fn is_multicast(&self) -> bool {
- match self {
- IpAddr::V4(ip) => ip.is_multicast(),
- IpAddr::V6(ip) => ip.is_multicast(),
- }
- }
-
- /// Returns [`true`] if this address is in a range designated for documentation.
- ///
- /// See the documentation for [`Ipv4Addr::is_documentation()`] and
- /// [`Ipv6Addr::is_documentation()`] for more details.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(ip)]
- ///
- /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
- ///
- /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true);
- /// assert_eq!(
- /// IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_documentation(),
- /// true
- /// );
- /// ```
- #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
- #[unstable(feature = "ip", issue = "27709")]
- #[must_use]
- #[inline]
- pub const fn is_documentation(&self) -> bool {
- match self {
- IpAddr::V4(ip) => ip.is_documentation(),
- IpAddr::V6(ip) => ip.is_documentation(),
- }
- }
-
- /// Returns [`true`] if this address is in a range designated for benchmarking.
- ///
- /// See the documentation for [`Ipv4Addr::is_benchmarking()`] and
- /// [`Ipv6Addr::is_benchmarking()`] for more details.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(ip)]
- ///
- /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
- ///
- /// assert_eq!(IpAddr::V4(Ipv4Addr::new(198, 19, 255, 255)).is_benchmarking(), true);
- /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true);
- /// ```
- #[unstable(feature = "ip", issue = "27709")]
- #[must_use]
- #[inline]
- pub const fn is_benchmarking(&self) -> bool {
- match self {
- IpAddr::V4(ip) => ip.is_benchmarking(),
- IpAddr::V6(ip) => ip.is_benchmarking(),
- }
- }
-
- /// Returns [`true`] if this address is an [`IPv4` address], and [`false`]
- /// otherwise.
- ///
- /// [`IPv4` address]: IpAddr::V4
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
- ///
- /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true);
- /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false);
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(feature = "ipaddr_checker", since = "1.16.0")]
- #[must_use]
- #[inline]
- pub const fn is_ipv4(&self) -> bool {
- matches!(self, IpAddr::V4(_))
- }
-
- /// Returns [`true`] if this address is an [`IPv6` address], and [`false`]
- /// otherwise.
- ///
- /// [`IPv6` address]: IpAddr::V6
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
- ///
- /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false);
- /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true);
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(feature = "ipaddr_checker", since = "1.16.0")]
- #[must_use]
- #[inline]
- pub const fn is_ipv6(&self) -> bool {
- matches!(self, IpAddr::V6(_))
- }
-
- /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped IPv6 addresses, otherwise it
- /// return `self` as-is.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(ip)]
- /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
- ///
- /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).to_canonical().is_loopback(), true);
- /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).is_loopback(), false);
- /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).to_canonical().is_loopback(), true);
- /// ```
- #[inline]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
- #[unstable(feature = "ip", issue = "27709")]
- pub const fn to_canonical(&self) -> IpAddr {
- match self {
- &v4 @ IpAddr::V4(_) => v4,
- IpAddr::V6(v6) => v6.to_canonical(),
- }
- }
-}
-
-impl Ipv4Addr {
- /// Creates a new IPv4 address from four eight-bit octets.
- ///
- /// The result will represent the IP address `a`.`b`.`c`.`d`.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv4Addr;
- ///
- /// let addr = Ipv4Addr::new(127, 0, 0, 1);
- /// ```
- #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[must_use]
- #[inline]
- pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
- Ipv4Addr { octets: [a, b, c, d] }
- }
-
- /// An IPv4 address with the address pointing to localhost: `127.0.0.1`
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv4Addr;
- ///
- /// let addr = Ipv4Addr::LOCALHOST;
- /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1));
- /// ```
- #[stable(feature = "ip_constructors", since = "1.30.0")]
- pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1);
-
- /// An IPv4 address representing an unspecified address: `0.0.0.0`
- ///
- /// This corresponds to the constant `INADDR_ANY` in other languages.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv4Addr;
- ///
- /// let addr = Ipv4Addr::UNSPECIFIED;
- /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0));
- /// ```
- #[doc(alias = "INADDR_ANY")]
- #[stable(feature = "ip_constructors", since = "1.30.0")]
- pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0);
-
- /// An IPv4 address representing the broadcast address: `255.255.255.255`
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv4Addr;
- ///
- /// let addr = Ipv4Addr::BROADCAST;
- /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255));
- /// ```
- #[stable(feature = "ip_constructors", since = "1.30.0")]
- pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255);
-
- /// Returns the four eight-bit integers that make up this address.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv4Addr;
- ///
- /// let addr = Ipv4Addr::new(127, 0, 0, 1);
- /// assert_eq!(addr.octets(), [127, 0, 0, 1]);
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[must_use]
- #[inline]
- pub const fn octets(&self) -> [u8; 4] {
- self.octets
- }
-
- /// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`).
- ///
- /// This property is defined in _UNIX Network Programming, Second Edition_,
- /// W. Richard Stevens, p. 891; see also [ip7].
- ///
- /// [ip7]: https://man7.org/linux/man-pages/man7/ip.7.html
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv4Addr;
- ///
- /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true);
- /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false);
- /// ```
- #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
- #[stable(feature = "ip_shared", since = "1.12.0")]
- #[must_use]
- #[inline]
- pub const fn is_unspecified(&self) -> bool {
- u32::from_be_bytes(self.octets) == 0
- }
-
- /// Returns [`true`] if this is a loopback address (`127.0.0.0/8`).
- ///
- /// This property is defined by [IETF RFC 1122].
- ///
- /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv4Addr;
- ///
- /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true);
- /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false);
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(since = "1.7.0", feature = "ip_17")]
- #[must_use]
- #[inline]
- pub const fn is_loopback(&self) -> bool {
- self.octets()[0] == 127
- }
-
- /// Returns [`true`] if this is a private address.
- ///
- /// The private address ranges are defined in [IETF RFC 1918] and include:
- ///
- /// - `10.0.0.0/8`
- /// - `172.16.0.0/12`
- /// - `192.168.0.0/16`
- ///
- /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv4Addr;
- ///
- /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true);
- /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true);
- /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true);
- /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true);
- /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false);
- /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true);
- /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false);
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(since = "1.7.0", feature = "ip_17")]
- #[must_use]
- #[inline]
- pub const fn is_private(&self) -> bool {
- match self.octets() {
- [10, ..] => true,
- [172, b, ..] if b >= 16 && b <= 31 => true,
- [192, 168, ..] => true,
- _ => false,
- }
- }
-
- /// Returns [`true`] if the address is link-local (`169.254.0.0/16`).
- ///
- /// This property is defined by [IETF RFC 3927].
- ///
- /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv4Addr;
- ///
- /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true);
- /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true);
- /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false);
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(since = "1.7.0", feature = "ip_17")]
- #[must_use]
- #[inline]
- pub const fn is_link_local(&self) -> bool {
- matches!(self.octets(), [169, 254, ..])
- }
-
- /// Returns [`true`] if the address appears to be globally reachable
- /// as specified by the [IANA IPv4 Special-Purpose Address Registry].
- /// Whether or not an address is practically reachable will depend on your network configuration.
- ///
- /// Most IPv4 addresses are globally reachable;
- /// unless they are specifically defined as *not* globally reachable.
- ///
- /// Non-exhaustive list of notable addresses that are not globally reachable:
- ///
- /// - The [unspecified address] ([`is_unspecified`](Ipv4Addr::is_unspecified))
- /// - Addresses reserved for private use ([`is_private`](Ipv4Addr::is_private))
- /// - Addresses in the shared address space ([`is_shared`](Ipv4Addr::is_shared))
- /// - Loopback addresses ([`is_loopback`](Ipv4Addr::is_loopback))
- /// - Link-local addresses ([`is_link_local`](Ipv4Addr::is_link_local))
- /// - Addresses reserved for documentation ([`is_documentation`](Ipv4Addr::is_documentation))
- /// - Addresses reserved for benchmarking ([`is_benchmarking`](Ipv4Addr::is_benchmarking))
- /// - Reserved addresses ([`is_reserved`](Ipv4Addr::is_reserved))
- /// - The [broadcast address] ([`is_broadcast`](Ipv4Addr::is_broadcast))
- ///
- /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv4 Special-Purpose Address Registry].
- ///
- /// [IANA IPv4 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
- /// [unspecified address]: Ipv4Addr::UNSPECIFIED
- /// [broadcast address]: Ipv4Addr::BROADCAST
-
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(ip)]
- ///
- /// use std::net::Ipv4Addr;
- ///
- /// // Most IPv4 addresses are globally reachable:
- /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
- ///
- /// // However some addresses have been assigned a special meaning
- /// // that makes them not globally reachable. Some examples are:
- ///
- /// // The unspecified address (`0.0.0.0`)
- /// assert_eq!(Ipv4Addr::UNSPECIFIED.is_global(), false);
- ///
- /// // Addresses reserved for private use (`10.0.0.0/8`, `172.16.0.0/12`, 192.168.0.0/16)
- /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false);
- /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false);
- /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false);
- ///
- /// // Addresses in the shared address space (`100.64.0.0/10`)
- /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false);
- ///
- /// // The loopback addresses (`127.0.0.0/8`)
- /// assert_eq!(Ipv4Addr::LOCALHOST.is_global(), false);
- ///
- /// // Link-local addresses (`169.254.0.0/16`)
- /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false);
- ///
- /// // Addresses reserved for documentation (`192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`)
- /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false);
- /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false);
- /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false);
- ///
- /// // Addresses reserved for benchmarking (`198.18.0.0/15`)
- /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false);
- ///
- /// // Reserved addresses (`240.0.0.0/4`)
- /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false);
- ///
- /// // The broadcast address (`255.255.255.255`)
- /// assert_eq!(Ipv4Addr::BROADCAST.is_global(), false);
- ///
- /// // For a complete overview see the IANA IPv4 Special-Purpose Address Registry.
- /// ```
- #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
- #[unstable(feature = "ip", issue = "27709")]
- #[must_use]
- #[inline]
- pub const fn is_global(&self) -> bool {
- !(self.octets()[0] == 0 // "This network"
- || self.is_private()
- || self.is_shared()
- || self.is_loopback()
- || self.is_link_local()
- // addresses reserved for future protocols (`192.0.0.0/24`)
- ||(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
- || self.is_documentation()
- || self.is_benchmarking()
- || self.is_reserved()
- || self.is_broadcast())
- }
-
- /// Returns [`true`] if this address is part of the Shared Address Space defined in
- /// [IETF RFC 6598] (`100.64.0.0/10`).
- ///
- /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(ip)]
- /// use std::net::Ipv4Addr;
- ///
- /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true);
- /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true);
- /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false);
- /// ```
- #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
- #[unstable(feature = "ip", issue = "27709")]
- #[must_use]
- #[inline]
- pub const fn is_shared(&self) -> bool {
- self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
- }
-
- /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for
- /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0`
- /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`.
- ///
- /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544
- /// [errata 423]: https://www.rfc-editor.org/errata/eid423
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(ip)]
- /// use std::net::Ipv4Addr;
- ///
- /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false);
- /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true);
- /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true);
- /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false);
- /// ```
- #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
- #[unstable(feature = "ip", issue = "27709")]
- #[must_use]
- #[inline]
- pub const fn is_benchmarking(&self) -> bool {
- self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18
- }
-
- /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112]
- /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the
- /// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since
- /// it is obviously not reserved for future use.
- ///
- /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112
- ///
- /// # Warning
- ///
- /// As IANA assigns new addresses, this method will be
- /// updated. This may result in non-reserved addresses being
- /// treated as reserved in code that relies on an outdated version
- /// of this method.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(ip)]
- /// use std::net::Ipv4Addr;
- ///
- /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true);
- /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true);
- ///
- /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false);
- /// // The broadcast address is not considered as reserved for future use by this implementation
- /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false);
- /// ```
- #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
- #[unstable(feature = "ip", issue = "27709")]
- #[must_use]
- #[inline]
- pub const fn is_reserved(&self) -> bool {
- self.octets()[0] & 240 == 240 && !self.is_broadcast()
- }
-
- /// Returns [`true`] if this is a multicast address (`224.0.0.0/4`).
- ///
- /// Multicast addresses have a most significant octet between `224` and `239`,
- /// and is defined by [IETF RFC 5771].
- ///
- /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv4Addr;
- ///
- /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true);
- /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true);
- /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false);
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(since = "1.7.0", feature = "ip_17")]
- #[must_use]
- #[inline]
- pub const fn is_multicast(&self) -> bool {
- self.octets()[0] >= 224 && self.octets()[0] <= 239
- }
-
- /// Returns [`true`] if this is a broadcast address (`255.255.255.255`).
- ///
- /// A broadcast address has all octets set to `255` as defined in [IETF RFC 919].
- ///
- /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv4Addr;
- ///
- /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true);
- /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false);
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(since = "1.7.0", feature = "ip_17")]
- #[must_use]
- #[inline]
- pub const fn is_broadcast(&self) -> bool {
- u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets())
- }
-
- /// Returns [`true`] if this address is in a range designated for documentation.
- ///
- /// This is defined in [IETF RFC 5737]:
- ///
- /// - `192.0.2.0/24` (TEST-NET-1)
- /// - `198.51.100.0/24` (TEST-NET-2)
- /// - `203.0.113.0/24` (TEST-NET-3)
- ///
- /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv4Addr;
- ///
- /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true);
- /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true);
- /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true);
- /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false);
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(since = "1.7.0", feature = "ip_17")]
- #[must_use]
- #[inline]
- pub const fn is_documentation(&self) -> bool {
- matches!(self.octets(), [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _])
- }
-
- /// Converts this address to an [IPv4-compatible] [`IPv6` address].
- ///
- /// `a.b.c.d` becomes `::a.b.c.d`
- ///
- /// Note that IPv4-compatible addresses have been officially deprecated.
- /// If you don't explicitly need an IPv4-compatible address for legacy reasons, consider using `to_ipv6_mapped` instead.
- ///
- /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses
- /// [`IPv6` address]: Ipv6Addr
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{Ipv4Addr, Ipv6Addr};
- ///
- /// assert_eq!(
- /// Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(),
- /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x2ff)
- /// );
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn to_ipv6_compatible(&self) -> Ipv6Addr {
- let [a, b, c, d] = self.octets();
- Ipv6Addr { octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d] }
- }
-
- /// Converts this address to an [IPv4-mapped] [`IPv6` address].
- ///
- /// `a.b.c.d` becomes `::ffff:a.b.c.d`
- ///
- /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses
- /// [`IPv6` address]: Ipv6Addr
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{Ipv4Addr, Ipv6Addr};
- ///
- /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(),
- /// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff));
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn to_ipv6_mapped(&self) -> Ipv6Addr {
- let [a, b, c, d] = self.octets();
- Ipv6Addr { octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d] }
- }
-}
-
-#[stable(feature = "ip_addr", since = "1.7.0")]
-impl fmt::Display for IpAddr {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- IpAddr::V4(ip) => ip.fmt(fmt),
- IpAddr::V6(ip) => ip.fmt(fmt),
- }
- }
-}
-
-#[stable(feature = "ip_addr", since = "1.7.0")]
-impl fmt::Debug for IpAddr {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(self, fmt)
- }
-}
-
-#[stable(feature = "ip_from_ip", since = "1.16.0")]
-impl From<Ipv4Addr> for IpAddr {
- /// Copies this address to a new `IpAddr::V4`.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{IpAddr, Ipv4Addr};
- ///
- /// let addr = Ipv4Addr::new(127, 0, 0, 1);
- ///
- /// assert_eq!(
- /// IpAddr::V4(addr),
- /// IpAddr::from(addr)
- /// )
- /// ```
- #[inline]
- fn from(ipv4: Ipv4Addr) -> IpAddr {
- IpAddr::V4(ipv4)
- }
-}
-
-#[stable(feature = "ip_from_ip", since = "1.16.0")]
-impl From<Ipv6Addr> for IpAddr {
- /// Copies this address to a new `IpAddr::V6`.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{IpAddr, Ipv6Addr};
- ///
- /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
- ///
- /// assert_eq!(
- /// IpAddr::V6(addr),
- /// IpAddr::from(addr)
- /// );
- /// ```
- #[inline]
- fn from(ipv6: Ipv6Addr) -> IpAddr {
- IpAddr::V6(ipv6)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for Ipv4Addr {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- let octets = self.octets();
-
- // If there are no alignment requirements, write the IP address directly to `f`.
- // Otherwise, write it to a local buffer and then use `f.pad`.
- if fmt.precision().is_none() && fmt.width().is_none() {
- write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
- } else {
- const LONGEST_IPV4_ADDR: &str = "255.255.255.255";
-
- let mut buf = DisplayBuffer::<{ LONGEST_IPV4_ADDR.len() }>::new();
- // Buffer is long enough for the longest possible IPv4 address, so this should never fail.
- write!(buf, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap();
-
- fmt.pad(buf.as_str())
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for Ipv4Addr {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(self, fmt)
- }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialEq<Ipv4Addr> for IpAddr {
- #[inline]
- fn eq(&self, other: &Ipv4Addr) -> bool {
- match self {
- IpAddr::V4(v4) => v4 == other,
- IpAddr::V6(_) => false,
- }
- }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialEq<IpAddr> for Ipv4Addr {
- #[inline]
- fn eq(&self, other: &IpAddr) -> bool {
- match other {
- IpAddr::V4(v4) => self == v4,
- IpAddr::V6(_) => false,
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl PartialOrd for Ipv4Addr {
- #[inline]
- fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialOrd<Ipv4Addr> for IpAddr {
- #[inline]
- fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
- match self {
- IpAddr::V4(v4) => v4.partial_cmp(other),
- IpAddr::V6(_) => Some(Ordering::Greater),
- }
- }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialOrd<IpAddr> for Ipv4Addr {
- #[inline]
- fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
- match other {
- IpAddr::V4(v4) => self.partial_cmp(v4),
- IpAddr::V6(_) => Some(Ordering::Less),
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Ord for Ipv4Addr {
- #[inline]
- fn cmp(&self, other: &Ipv4Addr) -> Ordering {
- self.octets.cmp(&other.octets)
- }
-}
+pub use core::net::Ipv6MulticastScope;
impl IntoInner<c::in_addr> for Ipv4Addr {
#[inline]
fn into_inner(self) -> c::in_addr {
// `s_addr` is stored as BE on all machines and the array is in BE order.
// So the native endian conversion method is used so that it's never swapped.
- c::in_addr { s_addr: u32::from_ne_bytes(self.octets) }
+ c::in_addr { s_addr: u32::from_ne_bytes(self.octets()) }
}
}
impl FromInner<c::in_addr> for Ipv4Addr {
fn from_inner(addr: c::in_addr) -> Ipv4Addr {
- Ipv4Addr { octets: addr.s_addr.to_ne_bytes() }
- }
-}
-
-#[stable(feature = "ip_u32", since = "1.1.0")]
-impl From<Ipv4Addr> for u32 {
- /// Converts an `Ipv4Addr` into a host byte order `u32`.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv4Addr;
- ///
- /// let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78);
- /// assert_eq!(0x12345678, u32::from(addr));
- /// ```
- #[inline]
- fn from(ip: Ipv4Addr) -> u32 {
- u32::from_be_bytes(ip.octets)
- }
-}
-
-#[stable(feature = "ip_u32", since = "1.1.0")]
-impl From<u32> for Ipv4Addr {
- /// Converts a host byte order `u32` into an `Ipv4Addr`.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv4Addr;
- ///
- /// let addr = Ipv4Addr::from(0x12345678);
- /// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr);
- /// ```
- #[inline]
- fn from(ip: u32) -> Ipv4Addr {
- Ipv4Addr { octets: ip.to_be_bytes() }
- }
-}
-
-#[stable(feature = "from_slice_v4", since = "1.9.0")]
-impl From<[u8; 4]> for Ipv4Addr {
- /// Creates an `Ipv4Addr` from a four element byte array.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv4Addr;
- ///
- /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]);
- /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr);
- /// ```
- #[inline]
- fn from(octets: [u8; 4]) -> Ipv4Addr {
- Ipv4Addr { octets }
- }
-}
-
-#[stable(feature = "ip_from_slice", since = "1.17.0")]
-impl From<[u8; 4]> for IpAddr {
- /// Creates an `IpAddr::V4` from a four element byte array.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{IpAddr, Ipv4Addr};
- ///
- /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]);
- /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr);
- /// ```
- #[inline]
- fn from(octets: [u8; 4]) -> IpAddr {
- IpAddr::V4(Ipv4Addr::from(octets))
- }
-}
-
-impl Ipv6Addr {
- /// Creates a new IPv6 address from eight 16-bit segments.
- ///
- /// The result will represent the IP address `a:b:c:d:e:f:g:h`.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv6Addr;
- ///
- /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
- /// ```
- #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[must_use]
- #[inline]
- pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
- let addr16 = [
- a.to_be(),
- b.to_be(),
- c.to_be(),
- d.to_be(),
- e.to_be(),
- f.to_be(),
- g.to_be(),
- h.to_be(),
- ];
- Ipv6Addr {
- // All elements in `addr16` are big endian.
- // SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`.
- octets: unsafe { transmute::<_, [u8; 16]>(addr16) },
- }
- }
-
- /// An IPv6 address representing localhost: `::1`.
- ///
- /// This corresponds to constant `IN6ADDR_LOOPBACK_INIT` or `in6addr_loopback` in other
- /// languages.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv6Addr;
- ///
- /// let addr = Ipv6Addr::LOCALHOST;
- /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
- /// ```
- #[doc(alias = "IN6ADDR_LOOPBACK_INIT")]
- #[doc(alias = "in6addr_loopback")]
- #[stable(feature = "ip_constructors", since = "1.30.0")]
- pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
-
- /// An IPv6 address representing the unspecified address: `::`
- ///
- /// This corresponds to constant `IN6ADDR_ANY_INIT` or `in6addr_any` in other languages.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv6Addr;
- ///
- /// let addr = Ipv6Addr::UNSPECIFIED;
- /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
- /// ```
- #[doc(alias = "IN6ADDR_ANY_INIT")]
- #[doc(alias = "in6addr_any")]
- #[stable(feature = "ip_constructors", since = "1.30.0")]
- pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
-
- /// Returns the eight 16-bit segments that make up this address.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv6Addr;
- ///
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(),
- /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]);
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[must_use]
- #[inline]
- pub const fn segments(&self) -> [u16; 8] {
- // All elements in `self.octets` must be big endian.
- // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`.
- let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.octets) };
- // We want native endian u16
- [
- u16::from_be(a),
- u16::from_be(b),
- u16::from_be(c),
- u16::from_be(d),
- u16::from_be(e),
- u16::from_be(f),
- u16::from_be(g),
- u16::from_be(h),
- ]
- }
-
- /// Returns [`true`] for the special 'unspecified' address (`::`).
- ///
- /// This property is defined in [IETF RFC 4291].
- ///
- /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv6Addr;
- ///
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false);
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true);
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(since = "1.7.0", feature = "ip_17")]
- #[must_use]
- #[inline]
- pub const fn is_unspecified(&self) -> bool {
- u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets())
- }
-
- /// Returns [`true`] if this is the [loopback address] (`::1`),
- /// as defined in [IETF RFC 4291 section 2.5.3].
- ///
- /// Contrary to IPv4, in IPv6 there is only one loopback address.
- ///
- /// [loopback address]: Ipv6Addr::LOCALHOST
- /// [IETF RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv6Addr;
- ///
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false);
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true);
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(since = "1.7.0", feature = "ip_17")]
- #[must_use]
- #[inline]
- pub const fn is_loopback(&self) -> bool {
- u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets())
- }
-
- /// Returns [`true`] if the address appears to be globally reachable
- /// as specified by the [IANA IPv6 Special-Purpose Address Registry].
- /// Whether or not an address is practically reachable will depend on your network configuration.
- ///
- /// Most IPv6 addresses are globally reachable;
- /// unless they are specifically defined as *not* globally reachable.
- ///
- /// Non-exhaustive list of notable addresses that are not globally reachable:
- /// - The [unspecified address] ([`is_unspecified`](Ipv6Addr::is_unspecified))
- /// - The [loopback address] ([`is_loopback`](Ipv6Addr::is_loopback))
- /// - IPv4-mapped addresses
- /// - Addresses reserved for benchmarking
- /// - Addresses reserved for documentation ([`is_documentation`](Ipv6Addr::is_documentation))
- /// - Unique local addresses ([`is_unique_local`](Ipv6Addr::is_unique_local))
- /// - Unicast addresses with link-local scope ([`is_unicast_link_local`](Ipv6Addr::is_unicast_link_local))
- ///
- /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv6 Special-Purpose Address Registry].
- ///
- /// Note that an address having global scope is not the same as being globally reachable,
- /// and there is no direct relation between the two concepts: There exist addresses with global scope
- /// that are not globally reachable (for example unique local addresses),
- /// and addresses that are globally reachable without having global scope
- /// (multicast addresses with non-global scope).
- ///
- /// [IANA IPv6 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
- /// [unspecified address]: Ipv6Addr::UNSPECIFIED
- /// [loopback address]: Ipv6Addr::LOCALHOST
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(ip)]
- ///
- /// use std::net::Ipv6Addr;
- ///
- /// // Most IPv6 addresses are globally reachable:
- /// assert_eq!(Ipv6Addr::new(0x26, 0, 0x1c9, 0, 0, 0xafc8, 0x10, 0x1).is_global(), true);
- ///
- /// // However some addresses have been assigned a special meaning
- /// // that makes them not globally reachable. Some examples are:
- ///
- /// // The unspecified address (`::`)
- /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_global(), false);
- ///
- /// // The loopback address (`::1`)
- /// assert_eq!(Ipv6Addr::LOCALHOST.is_global(), false);
- ///
- /// // IPv4-mapped addresses (`::ffff:0:0/96`)
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), false);
- ///
- /// // Addresses reserved for benchmarking (`2001:2::/48`)
- /// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false);
- ///
- /// // Addresses reserved for documentation (`2001:db8::/32`)
- /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false);
- ///
- /// // Unique local addresses (`fc00::/7`)
- /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
- ///
- /// // Unicast addresses with link-local scope (`fe80::/10`)
- /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
- ///
- /// // For a complete overview see the IANA IPv6 Special-Purpose Address Registry.
- /// ```
- #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
- #[unstable(feature = "ip", issue = "27709")]
- #[must_use]
- #[inline]
- pub const fn is_global(&self) -> bool {
- !(self.is_unspecified()
- || self.is_loopback()
- // IPv4-mapped Address (`::ffff:0:0/96`)
- || matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
- // IPv4-IPv6 Translat. (`64:ff9b:1::/48`)
- || matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
- // Discard-Only Address Block (`100::/64`)
- || matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _])
- // IETF Protocol Assignments (`2001::/23`)
- || (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
- && !(
- // Port Control Protocol Anycast (`2001:1::1`)
- u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
- // Traversal Using Relays around NAT Anycast (`2001:1::2`)
- || u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
- // AMT (`2001:3::/32`)
- || matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _])
- // AS112-v6 (`2001:4:112::/48`)
- || matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
- // ORCHIDv2 (`2001:20::/28`)
- || matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
- ))
- || self.is_documentation()
- || self.is_unique_local()
- || self.is_unicast_link_local())
- }
-
- /// Returns [`true`] if this is a unique local address (`fc00::/7`).
- ///
- /// This property is defined in [IETF RFC 4193].
- ///
- /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(ip)]
- ///
- /// use std::net::Ipv6Addr;
- ///
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false);
- /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true);
- /// ```
- #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
- #[unstable(feature = "ip", issue = "27709")]
- #[must_use]
- #[inline]
- pub const fn is_unique_local(&self) -> bool {
- (self.segments()[0] & 0xfe00) == 0xfc00
- }
-
- /// Returns [`true`] if this is a unicast address, as defined by [IETF RFC 4291].
- /// Any address that is not a [multicast address] (`ff00::/8`) is unicast.
- ///
- /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
- /// [multicast address]: Ipv6Addr::is_multicast
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(ip)]
- ///
- /// use std::net::Ipv6Addr;
- ///
- /// // The unspecified and loopback addresses are unicast.
- /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_unicast(), true);
- /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast(), true);
- ///
- /// // Any address that is not a multicast address (`ff00::/8`) is unicast.
- /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast(), true);
- /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_unicast(), false);
- /// ```
- #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
- #[unstable(feature = "ip", issue = "27709")]
- #[must_use]
- #[inline]
- pub const fn is_unicast(&self) -> bool {
- !self.is_multicast()
- }
-
- /// Returns `true` if the address is a unicast address with link-local scope,
- /// as defined in [RFC 4291].
- ///
- /// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4].
- /// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6],
- /// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format:
- ///
- /// ```text
- /// | 10 bits | 54 bits | 64 bits |
- /// +----------+-------------------------+----------------------------+
- /// |1111111010| 0 | interface ID |
- /// +----------+-------------------------+----------------------------+
- /// ```
- /// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`,
- /// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated,
- /// and those addresses will have link-local scope.
- ///
- /// Also note that while [RFC 4291 section 2.5.3] mentions about the [loopback address] (`::1`) that "it is treated as having Link-Local scope",
- /// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it.
- ///
- /// [RFC 4291]: https://tools.ietf.org/html/rfc4291
- /// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
- /// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3
- /// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
- /// [loopback address]: Ipv6Addr::LOCALHOST
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(ip)]
- ///
- /// use std::net::Ipv6Addr;
- ///
- /// // The loopback address (`::1`) does not actually have link-local scope.
- /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false);
- ///
- /// // Only addresses in `fe80::/10` have link-local scope.
- /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false);
- /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
- ///
- /// // Addresses outside the stricter `fe80::/64` also have link-local scope.
- /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true);
- /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
- /// ```
- #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
- #[unstable(feature = "ip", issue = "27709")]
- #[must_use]
- #[inline]
- pub const fn is_unicast_link_local(&self) -> bool {
- (self.segments()[0] & 0xffc0) == 0xfe80
- }
-
- /// Returns [`true`] if this is an address reserved for documentation
- /// (`2001:db8::/32`).
- ///
- /// This property is defined in [IETF RFC 3849].
- ///
- /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(ip)]
- ///
- /// use std::net::Ipv6Addr;
- ///
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false);
- /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true);
- /// ```
- #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
- #[unstable(feature = "ip", issue = "27709")]
- #[must_use]
- #[inline]
- pub const fn is_documentation(&self) -> bool {
- (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
- }
-
- /// Returns [`true`] if this is an address reserved for benchmarking (`2001:2::/48`).
- ///
- /// This property is defined in [IETF RFC 5180], where it is mistakenly specified as covering the range `2001:0200::/48`.
- /// This is corrected in [IETF RFC Errata 1752] to `2001:0002::/48`.
- ///
- /// [IETF RFC 5180]: https://tools.ietf.org/html/rfc5180
- /// [IETF RFC Errata 1752]: https://www.rfc-editor.org/errata_search.php?eid=1752
- ///
- /// ```
- /// #![feature(ip)]
- ///
- /// use std::net::Ipv6Addr;
- ///
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc613, 0x0).is_benchmarking(), false);
- /// assert_eq!(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0).is_benchmarking(), true);
- /// ```
- #[unstable(feature = "ip", issue = "27709")]
- #[must_use]
- #[inline]
- pub const fn is_benchmarking(&self) -> bool {
- (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) && (self.segments()[2] == 0)
- }
-
- /// Returns [`true`] if the address is a globally routable unicast address.
- ///
- /// The following return false:
- ///
- /// - the loopback address
- /// - the link-local addresses
- /// - unique local addresses
- /// - the unspecified address
- /// - the address range reserved for documentation
- ///
- /// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7]
- ///
- /// ```no_rust
- /// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer
- /// be supported in new implementations (i.e., new implementations must treat this prefix as
- /// Global Unicast).
- /// ```
- ///
- /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(ip)]
- ///
- /// use std::net::Ipv6Addr;
- ///
- /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false);
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true);
- /// ```
- #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
- #[unstable(feature = "ip", issue = "27709")]
- #[must_use]
- #[inline]
- pub const fn is_unicast_global(&self) -> bool {
- self.is_unicast()
- && !self.is_loopback()
- && !self.is_unicast_link_local()
- && !self.is_unique_local()
- && !self.is_unspecified()
- && !self.is_documentation()
- && !self.is_benchmarking()
- }
-
- /// Returns the address's multicast scope if the address is multicast.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(ip)]
- ///
- /// use std::net::{Ipv6Addr, Ipv6MulticastScope};
- ///
- /// assert_eq!(
- /// Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(),
- /// Some(Ipv6MulticastScope::Global)
- /// );
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None);
- /// ```
- #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
- #[unstable(feature = "ip", issue = "27709")]
- #[must_use]
- #[inline]
- pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
- if self.is_multicast() {
- match self.segments()[0] & 0x000f {
- 1 => Some(Ipv6MulticastScope::InterfaceLocal),
- 2 => Some(Ipv6MulticastScope::LinkLocal),
- 3 => Some(Ipv6MulticastScope::RealmLocal),
- 4 => Some(Ipv6MulticastScope::AdminLocal),
- 5 => Some(Ipv6MulticastScope::SiteLocal),
- 8 => Some(Ipv6MulticastScope::OrganizationLocal),
- 14 => Some(Ipv6MulticastScope::Global),
- _ => None,
- }
- } else {
- None
- }
- }
-
- /// Returns [`true`] if this is a multicast address (`ff00::/8`).
- ///
- /// This property is defined by [IETF RFC 4291].
- ///
- /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv6Addr;
- ///
- /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true);
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false);
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(since = "1.7.0", feature = "ip_17")]
- #[must_use]
- #[inline]
- pub const fn is_multicast(&self) -> bool {
- (self.segments()[0] & 0xff00) == 0xff00
- }
-
- /// Converts this address to an [`IPv4` address] if it's an [IPv4-mapped] address,
- /// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`].
- ///
- /// `::ffff:a.b.c.d` becomes `a.b.c.d`.
- /// All addresses *not* starting with `::ffff` will return `None`.
- ///
- /// [`IPv4` address]: Ipv4Addr
- /// [IPv4-mapped]: Ipv6Addr
- /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{Ipv4Addr, Ipv6Addr};
- ///
- /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4_mapped(), None);
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4_mapped(),
- /// Some(Ipv4Addr::new(192, 10, 2, 255)));
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None);
- /// ```
- #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
- #[stable(feature = "ipv6_to_ipv4_mapped", since = "1.63.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
- match self.octets() {
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => {
- Some(Ipv4Addr::new(a, b, c, d))
- }
- _ => None,
- }
- }
-
- /// Converts this address to an [`IPv4` address] if it is either
- /// an [IPv4-compatible] address as defined in [IETF RFC 4291 section 2.5.5.1],
- /// or an [IPv4-mapped] address as defined in [IETF RFC 4291 section 2.5.5.2],
- /// otherwise returns [`None`].
- ///
- /// Note that this will return an [`IPv4` address] for the IPv6 loopback address `::1`. Use
- /// [`Ipv6Addr::to_ipv4_mapped`] to avoid this.
- ///
- /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d`. `::1` becomes `0.0.0.1`.
- /// All addresses *not* starting with either all zeroes or `::ffff` will return `None`.
- ///
- /// [`IPv4` address]: Ipv4Addr
- /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses
- /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses
- /// [IETF RFC 4291 section 2.5.5.1]: https://tools.ietf.org/html/rfc4291#section-2.5.5.1
- /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{Ipv4Addr, Ipv6Addr};
- ///
- /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None);
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(),
- /// Some(Ipv4Addr::new(192, 10, 2, 255)));
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(),
- /// Some(Ipv4Addr::new(0, 0, 0, 1)));
- /// ```
- #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn to_ipv4(&self) -> Option<Ipv4Addr> {
- if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() {
- let [a, b] = ab.to_be_bytes();
- let [c, d] = cd.to_be_bytes();
- Some(Ipv4Addr::new(a, b, c, d))
- } else {
- None
- }
- }
-
- /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped addresses, otherwise it
- /// returns self wrapped in an `IpAddr::V6`.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(ip)]
- /// use std::net::Ipv6Addr;
- ///
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false);
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).to_canonical().is_loopback(), true);
- /// ```
- #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
- #[unstable(feature = "ip", issue = "27709")]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn to_canonical(&self) -> IpAddr {
- if let Some(mapped) = self.to_ipv4_mapped() {
- return IpAddr::V4(mapped);
- }
- IpAddr::V6(*self)
- }
-
- /// Returns the sixteen eight-bit integers the IPv6 address consists of.
- ///
- /// ```
- /// use std::net::Ipv6Addr;
- ///
- /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(),
- /// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
- /// ```
- #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
- #[stable(feature = "ipv6_to_octets", since = "1.12.0")]
- #[must_use]
- #[inline]
- pub const fn octets(&self) -> [u8; 16] {
- self.octets
- }
-}
-
-/// Write an Ipv6Addr, conforming to the canonical style described by
-/// [RFC 5952](https://tools.ietf.org/html/rfc5952).
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for Ipv6Addr {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- // If there are no alignment requirements, write the IP address directly to `f`.
- // Otherwise, write it to a local buffer and then use `f.pad`.
- if f.precision().is_none() && f.width().is_none() {
- let segments = self.segments();
-
- // Special case for :: and ::1; otherwise they get written with the
- // IPv4 formatter
- if self.is_unspecified() {
- f.write_str("::")
- } else if self.is_loopback() {
- f.write_str("::1")
- } else if let Some(ipv4) = self.to_ipv4() {
- match segments[5] {
- // IPv4 Compatible address
- 0 => write!(f, "::{}", ipv4),
- // IPv4 Mapped address
- 0xffff => write!(f, "::ffff:{}", ipv4),
- _ => unreachable!(),
- }
- } else {
- #[derive(Copy, Clone, Default)]
- struct Span {
- start: usize,
- len: usize,
- }
-
- // Find the inner 0 span
- let zeroes = {
- let mut longest = Span::default();
- let mut current = Span::default();
-
- for (i, &segment) in segments.iter().enumerate() {
- if segment == 0 {
- if current.len == 0 {
- current.start = i;
- }
-
- current.len += 1;
-
- if current.len > longest.len {
- longest = current;
- }
- } else {
- current = Span::default();
- }
- }
-
- longest
- };
-
- /// Write a colon-separated part of the address
- #[inline]
- fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) -> fmt::Result {
- if let Some((first, tail)) = chunk.split_first() {
- write!(f, "{:x}", first)?;
- for segment in tail {
- f.write_char(':')?;
- write!(f, "{:x}", segment)?;
- }
- }
- Ok(())
- }
-
- if zeroes.len > 1 {
- fmt_subslice(f, &segments[..zeroes.start])?;
- f.write_str("::")?;
- fmt_subslice(f, &segments[zeroes.start + zeroes.len..])
- } else {
- fmt_subslice(f, &segments)
- }
- }
- } else {
- const LONGEST_IPV6_ADDR: &str = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff";
-
- let mut buf = DisplayBuffer::<{ LONGEST_IPV6_ADDR.len() }>::new();
- // Buffer is long enough for the longest possible IPv6 address, so this should never fail.
- write!(buf, "{}", self).unwrap();
-
- f.pad(buf.as_str())
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for Ipv6Addr {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(self, fmt)
- }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialEq<IpAddr> for Ipv6Addr {
- #[inline]
- fn eq(&self, other: &IpAddr) -> bool {
- match other {
- IpAddr::V4(_) => false,
- IpAddr::V6(v6) => self == v6,
- }
- }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialEq<Ipv6Addr> for IpAddr {
- #[inline]
- fn eq(&self, other: &Ipv6Addr) -> bool {
- match self {
- IpAddr::V4(_) => false,
- IpAddr::V6(v6) => v6 == other,
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl PartialOrd for Ipv6Addr {
- #[inline]
- fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialOrd<Ipv6Addr> for IpAddr {
- #[inline]
- fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
- match self {
- IpAddr::V4(_) => Some(Ordering::Less),
- IpAddr::V6(v6) => v6.partial_cmp(other),
- }
- }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialOrd<IpAddr> for Ipv6Addr {
- #[inline]
- fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
- match other {
- IpAddr::V4(_) => Some(Ordering::Greater),
- IpAddr::V6(v6) => self.partial_cmp(v6),
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Ord for Ipv6Addr {
- #[inline]
- fn cmp(&self, other: &Ipv6Addr) -> Ordering {
- self.segments().cmp(&other.segments())
+ Ipv4Addr::from(addr.s_addr.to_ne_bytes())
}
}
impl IntoInner<c::in6_addr> for Ipv6Addr {
fn into_inner(self) -> c::in6_addr {
- c::in6_addr { s6_addr: self.octets }
+ c::in6_addr { s6_addr: self.octets() }
}
}
impl FromInner<c::in6_addr> for Ipv6Addr {
#[inline]
fn from_inner(addr: c::in6_addr) -> Ipv6Addr {
- Ipv6Addr { octets: addr.s6_addr }
- }
-}
-
-#[stable(feature = "i128", since = "1.26.0")]
-impl From<Ipv6Addr> for u128 {
- /// Convert an `Ipv6Addr` into a host byte order `u128`.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv6Addr;
- ///
- /// let addr = Ipv6Addr::new(
- /// 0x1020, 0x3040, 0x5060, 0x7080,
- /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
- /// );
- /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr));
- /// ```
- #[inline]
- fn from(ip: Ipv6Addr) -> u128 {
- u128::from_be_bytes(ip.octets)
- }
-}
-#[stable(feature = "i128", since = "1.26.0")]
-impl From<u128> for Ipv6Addr {
- /// Convert a host byte order `u128` into an `Ipv6Addr`.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv6Addr;
- ///
- /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128);
- /// assert_eq!(
- /// Ipv6Addr::new(
- /// 0x1020, 0x3040, 0x5060, 0x7080,
- /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
- /// ),
- /// addr);
- /// ```
- #[inline]
- fn from(ip: u128) -> Ipv6Addr {
- Ipv6Addr::from(ip.to_be_bytes())
- }
-}
-
-#[stable(feature = "ipv6_from_octets", since = "1.9.0")]
-impl From<[u8; 16]> for Ipv6Addr {
- /// Creates an `Ipv6Addr` from a sixteen element byte array.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv6Addr;
- ///
- /// let addr = Ipv6Addr::from([
- /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8,
- /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8,
- /// ]);
- /// assert_eq!(
- /// Ipv6Addr::new(
- /// 0x1918, 0x1716,
- /// 0x1514, 0x1312,
- /// 0x1110, 0x0f0e,
- /// 0x0d0c, 0x0b0a
- /// ),
- /// addr
- /// );
- /// ```
- #[inline]
- fn from(octets: [u8; 16]) -> Ipv6Addr {
- Ipv6Addr { octets }
- }
-}
-
-#[stable(feature = "ipv6_from_segments", since = "1.16.0")]
-impl From<[u16; 8]> for Ipv6Addr {
- /// Creates an `Ipv6Addr` from an eight element 16-bit array.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv6Addr;
- ///
- /// let addr = Ipv6Addr::from([
- /// 525u16, 524u16, 523u16, 522u16,
- /// 521u16, 520u16, 519u16, 518u16,
- /// ]);
- /// assert_eq!(
- /// Ipv6Addr::new(
- /// 0x20d, 0x20c,
- /// 0x20b, 0x20a,
- /// 0x209, 0x208,
- /// 0x207, 0x206
- /// ),
- /// addr
- /// );
- /// ```
- #[inline]
- fn from(segments: [u16; 8]) -> Ipv6Addr {
- let [a, b, c, d, e, f, g, h] = segments;
- Ipv6Addr::new(a, b, c, d, e, f, g, h)
- }
-}
-
-#[stable(feature = "ip_from_slice", since = "1.17.0")]
-impl From<[u8; 16]> for IpAddr {
- /// Creates an `IpAddr::V6` from a sixteen element byte array.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{IpAddr, Ipv6Addr};
- ///
- /// let addr = IpAddr::from([
- /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8,
- /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8,
- /// ]);
- /// assert_eq!(
- /// IpAddr::V6(Ipv6Addr::new(
- /// 0x1918, 0x1716,
- /// 0x1514, 0x1312,
- /// 0x1110, 0x0f0e,
- /// 0x0d0c, 0x0b0a
- /// )),
- /// addr
- /// );
- /// ```
- #[inline]
- fn from(octets: [u8; 16]) -> IpAddr {
- IpAddr::V6(Ipv6Addr::from(octets))
- }
-}
-
-#[stable(feature = "ip_from_slice", since = "1.17.0")]
-impl From<[u16; 8]> for IpAddr {
- /// Creates an `IpAddr::V6` from an eight element 16-bit array.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{IpAddr, Ipv6Addr};
- ///
- /// let addr = IpAddr::from([
- /// 525u16, 524u16, 523u16, 522u16,
- /// 521u16, 520u16, 519u16, 518u16,
- /// ]);
- /// assert_eq!(
- /// IpAddr::V6(Ipv6Addr::new(
- /// 0x20d, 0x20c,
- /// 0x20b, 0x20a,
- /// 0x209, 0x208,
- /// 0x207, 0x206
- /// )),
- /// addr
- /// );
- /// ```
- #[inline]
- fn from(segments: [u16; 8]) -> IpAddr {
- IpAddr::V6(Ipv6Addr::from(segments))
+ Ipv6Addr::from(addr.s6_addr)
}
}
diff --git a/library/std/src/net/ip_addr/tests.rs b/library/std/src/net/ip_addr/tests.rs
index 7c3430b2b..ab99c0c2f 100644
--- a/library/std/src/net/ip_addr/tests.rs
+++ b/library/std/src/net/ip_addr/tests.rs
@@ -1,1039 +1,8 @@
-use crate::net::test::{sa4, sa6, tsa};
-use crate::net::*;
-use crate::str::FromStr;
-
-#[test]
-fn test_from_str_ipv4() {
- assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse());
- assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse());
- assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse());
-
- // out of range
- let none: Option<Ipv4Addr> = "256.0.0.1".parse().ok();
- assert_eq!(None, none);
- // too short
- let none: Option<Ipv4Addr> = "255.0.0".parse().ok();
- assert_eq!(None, none);
- // too long
- let none: Option<Ipv4Addr> = "255.0.0.1.2".parse().ok();
- assert_eq!(None, none);
- // no number between dots
- let none: Option<Ipv4Addr> = "255.0..1".parse().ok();
- assert_eq!(None, none);
- // octal
- let none: Option<Ipv4Addr> = "255.0.0.01".parse().ok();
- assert_eq!(None, none);
- // octal zero
- let none: Option<Ipv4Addr> = "255.0.0.00".parse().ok();
- assert_eq!(None, none);
- let none: Option<Ipv4Addr> = "255.0.00.0".parse().ok();
- assert_eq!(None, none);
-}
-
-#[test]
-fn test_from_str_ipv6() {
- assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse());
- assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse());
-
- assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse());
- assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse());
-
- assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), "2a02:6b8::11:11".parse());
-
- // too long group
- let none: Option<Ipv6Addr> = "::00000".parse().ok();
- assert_eq!(None, none);
- // too short
- let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7".parse().ok();
- assert_eq!(None, none);
- // too long
- let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:8:9".parse().ok();
- assert_eq!(None, none);
- // triple colon
- let none: Option<Ipv6Addr> = "1:2:::6:7:8".parse().ok();
- assert_eq!(None, none);
- // two double colons
- let none: Option<Ipv6Addr> = "1:2::6::8".parse().ok();
- assert_eq!(None, none);
- // `::` indicating zero groups of zeros
- let none: Option<Ipv6Addr> = "1:2:3:4::5:6:7:8".parse().ok();
- assert_eq!(None, none);
-}
-
-#[test]
-fn test_from_str_ipv4_in_ipv6() {
- assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), "::192.0.2.33".parse());
- assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), "::FFFF:192.0.2.33".parse());
- assert_eq!(
- Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)),
- "64:ff9b::192.0.2.33".parse()
- );
- assert_eq!(
- Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)),
- "2001:db8:122:c000:2:2100:192.0.2.33".parse()
- );
-
- // colon after v4
- let none: Option<Ipv4Addr> = "::127.0.0.1:".parse().ok();
- assert_eq!(None, none);
- // not enough groups
- let none: Option<Ipv6Addr> = "1:2:3:4:5:127.0.0.1".parse().ok();
- assert_eq!(None, none);
- // too many groups
- let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:127.0.0.1".parse().ok();
- assert_eq!(None, none);
-}
-
-#[test]
-fn test_from_str_socket_addr() {
- assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse());
- assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse());
- assert_eq!(
- Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)),
- "[2a02:6b8:0:1::1]:53".parse()
- );
- assert_eq!(
- Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0)),
- "[2a02:6b8:0:1::1]:53".parse()
- );
- assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), "[::127.0.0.1]:22".parse());
- assert_eq!(
- Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22, 0, 0)),
- "[::127.0.0.1]:22".parse()
- );
-
- // without port
- let none: Option<SocketAddr> = "127.0.0.1".parse().ok();
- assert_eq!(None, none);
- // without port
- let none: Option<SocketAddr> = "127.0.0.1:".parse().ok();
- assert_eq!(None, none);
- // wrong brackets around v4
- let none: Option<SocketAddr> = "[127.0.0.1]:22".parse().ok();
- assert_eq!(None, none);
- // port out of range
- let none: Option<SocketAddr> = "127.0.0.1:123456".parse().ok();
- assert_eq!(None, none);
-}
-
-#[test]
-fn ipv4_addr_to_string() {
- assert_eq!(Ipv4Addr::new(127, 0, 0, 1).to_string(), "127.0.0.1");
- // Short address
- assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1");
- // Long address
- assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127");
-
- // Test padding
- assert_eq!(&format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1 ");
- assert_eq!(&format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), " 1.1.1.1");
-}
-
-#[test]
-fn ipv6_addr_to_string() {
- // ipv4-mapped address
- let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280);
- assert_eq!(a1.to_string(), "::ffff:192.0.2.128");
-
- // ipv4-compatible address
- let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280);
- assert_eq!(a1.to_string(), "::192.0.2.128");
-
- // v6 address with no zero segments
- assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f");
-
- // longest possible IPv6 length
- assert_eq!(
- Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888).to_string(),
- "1111:2222:3333:4444:5555:6666:7777:8888"
- );
- // padding
- assert_eq!(&format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "1:2:3:4:5:6:7:8 ");
- assert_eq!(&format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), " 1:2:3:4:5:6:7:8");
-
- // reduce a single run of zeros
- assert_eq!(
- "ae::ffff:102:304",
- Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string()
- );
-
- // don't reduce just a single zero segment
- assert_eq!("1:2:3:4:5:6:0:8", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string());
-
- // 'any' address
- assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string());
-
- // loopback address
- assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string());
-
- // ends in zeros
- assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string());
-
- // two runs of zeros, second one is longer
- assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string());
-
- // two runs of zeros, equal length
- assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string());
-
- // don't prefix `0x` to each segment in `dbg!`.
- assert_eq!("1::4:5:0:0:8", &format!("{:#?}", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8)));
-}
-
-#[test]
-fn ipv4_to_ipv6() {
- assert_eq!(
- Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678),
- Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped()
- );
- assert_eq!(
- Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678),
- Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible()
- );
-}
-
-#[test]
-fn ipv6_to_ipv4_mapped() {
- assert_eq!(
- Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4_mapped(),
- Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
- );
- assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), None);
-}
-
-#[test]
-fn ipv6_to_ipv4() {
- assert_eq!(
- Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(),
- Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
- );
- assert_eq!(
- Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(),
- Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
- );
- assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None);
-}
-
-#[test]
-fn ip_properties() {
- macro_rules! ip {
- ($s:expr) => {
- IpAddr::from_str($s).unwrap()
- };
- }
-
- macro_rules! check {
- ($s:expr) => {
- check!($s, 0);
- };
-
- ($s:expr, $mask:expr) => {{
- let unspec: u8 = 1 << 0;
- let loopback: u8 = 1 << 1;
- let global: u8 = 1 << 2;
- let multicast: u8 = 1 << 3;
- let doc: u8 = 1 << 4;
- let benchmarking: u8 = 1 << 5;
-
- if ($mask & unspec) == unspec {
- assert!(ip!($s).is_unspecified());
- } else {
- assert!(!ip!($s).is_unspecified());
- }
-
- if ($mask & loopback) == loopback {
- assert!(ip!($s).is_loopback());
- } else {
- assert!(!ip!($s).is_loopback());
- }
-
- if ($mask & global) == global {
- assert!(ip!($s).is_global());
- } else {
- assert!(!ip!($s).is_global());
- }
-
- if ($mask & multicast) == multicast {
- assert!(ip!($s).is_multicast());
- } else {
- assert!(!ip!($s).is_multicast());
- }
-
- if ($mask & doc) == doc {
- assert!(ip!($s).is_documentation());
- } else {
- assert!(!ip!($s).is_documentation());
- }
-
- if ($mask & benchmarking) == benchmarking {
- assert!(ip!($s).is_benchmarking());
- } else {
- assert!(!ip!($s).is_benchmarking());
- }
- }};
- }
-
- let unspec: u8 = 1 << 0;
- let loopback: u8 = 1 << 1;
- let global: u8 = 1 << 2;
- let multicast: u8 = 1 << 3;
- let doc: u8 = 1 << 4;
- let benchmarking: u8 = 1 << 5;
-
- check!("0.0.0.0", unspec);
- check!("0.0.0.1");
- check!("0.1.0.0");
- check!("10.9.8.7");
- check!("127.1.2.3", loopback);
- check!("172.31.254.253");
- check!("169.254.253.242");
- check!("192.0.2.183", doc);
- check!("192.1.2.183", global);
- check!("192.168.254.253");
- check!("198.51.100.0", doc);
- check!("203.0.113.0", doc);
- check!("203.2.113.0", global);
- check!("224.0.0.0", global | multicast);
- check!("239.255.255.255", global | multicast);
- check!("255.255.255.255");
- // make sure benchmarking addresses are not global
- check!("198.18.0.0", benchmarking);
- check!("198.18.54.2", benchmarking);
- check!("198.19.255.255", benchmarking);
- // make sure addresses reserved for protocol assignment are not global
- check!("192.0.0.0");
- check!("192.0.0.255");
- check!("192.0.0.100");
- // make sure reserved addresses are not global
- check!("240.0.0.0");
- check!("251.54.1.76");
- check!("254.255.255.255");
- // make sure shared addresses are not global
- check!("100.64.0.0");
- check!("100.127.255.255");
- check!("100.100.100.0");
-
- check!("::", unspec);
- check!("::1", loopback);
- check!("::0.0.0.2", global);
- check!("1::", global);
- check!("fc00::");
- check!("fdff:ffff::");
- check!("fe80:ffff::");
- check!("febf:ffff::");
- check!("fec0::", global);
- check!("ff01::", global | multicast);
- check!("ff02::", global | multicast);
- check!("ff03::", global | multicast);
- check!("ff04::", global | multicast);
- check!("ff05::", global | multicast);
- check!("ff08::", global | multicast);
- check!("ff0e::", global | multicast);
- check!("2001:db8:85a3::8a2e:370:7334", doc);
- check!("2001:2::ac32:23ff:21", benchmarking);
- check!("102:304:506:708:90a:b0c:d0e:f10", global);
-}
-
-#[test]
-fn ipv4_properties() {
- macro_rules! ip {
- ($s:expr) => {
- Ipv4Addr::from_str($s).unwrap()
- };
- }
-
- macro_rules! check {
- ($s:expr) => {
- check!($s, 0);
- };
-
- ($s:expr, $mask:expr) => {{
- let unspec: u16 = 1 << 0;
- let loopback: u16 = 1 << 1;
- let private: u16 = 1 << 2;
- let link_local: u16 = 1 << 3;
- let global: u16 = 1 << 4;
- let multicast: u16 = 1 << 5;
- let broadcast: u16 = 1 << 6;
- let documentation: u16 = 1 << 7;
- let benchmarking: u16 = 1 << 8;
- let reserved: u16 = 1 << 10;
- let shared: u16 = 1 << 11;
-
- if ($mask & unspec) == unspec {
- assert!(ip!($s).is_unspecified());
- } else {
- assert!(!ip!($s).is_unspecified());
- }
-
- if ($mask & loopback) == loopback {
- assert!(ip!($s).is_loopback());
- } else {
- assert!(!ip!($s).is_loopback());
- }
-
- if ($mask & private) == private {
- assert!(ip!($s).is_private());
- } else {
- assert!(!ip!($s).is_private());
- }
-
- if ($mask & link_local) == link_local {
- assert!(ip!($s).is_link_local());
- } else {
- assert!(!ip!($s).is_link_local());
- }
-
- if ($mask & global) == global {
- assert!(ip!($s).is_global());
- } else {
- assert!(!ip!($s).is_global());
- }
-
- if ($mask & multicast) == multicast {
- assert!(ip!($s).is_multicast());
- } else {
- assert!(!ip!($s).is_multicast());
- }
-
- if ($mask & broadcast) == broadcast {
- assert!(ip!($s).is_broadcast());
- } else {
- assert!(!ip!($s).is_broadcast());
- }
-
- if ($mask & documentation) == documentation {
- assert!(ip!($s).is_documentation());
- } else {
- assert!(!ip!($s).is_documentation());
- }
-
- if ($mask & benchmarking) == benchmarking {
- assert!(ip!($s).is_benchmarking());
- } else {
- assert!(!ip!($s).is_benchmarking());
- }
-
- if ($mask & reserved) == reserved {
- assert!(ip!($s).is_reserved());
- } else {
- assert!(!ip!($s).is_reserved());
- }
-
- if ($mask & shared) == shared {
- assert!(ip!($s).is_shared());
- } else {
- assert!(!ip!($s).is_shared());
- }
- }};
- }
-
- let unspec: u16 = 1 << 0;
- let loopback: u16 = 1 << 1;
- let private: u16 = 1 << 2;
- let link_local: u16 = 1 << 3;
- let global: u16 = 1 << 4;
- let multicast: u16 = 1 << 5;
- let broadcast: u16 = 1 << 6;
- let documentation: u16 = 1 << 7;
- let benchmarking: u16 = 1 << 8;
- let reserved: u16 = 1 << 10;
- let shared: u16 = 1 << 11;
-
- check!("0.0.0.0", unspec);
- check!("0.0.0.1");
- check!("0.1.0.0");
- check!("10.9.8.7", private);
- check!("127.1.2.3", loopback);
- check!("172.31.254.253", private);
- check!("169.254.253.242", link_local);
- check!("192.0.2.183", documentation);
- check!("192.1.2.183", global);
- check!("192.168.254.253", private);
- check!("198.51.100.0", documentation);
- check!("203.0.113.0", documentation);
- check!("203.2.113.0", global);
- check!("224.0.0.0", global | multicast);
- check!("239.255.255.255", global | multicast);
- check!("255.255.255.255", broadcast);
- check!("198.18.0.0", benchmarking);
- check!("198.18.54.2", benchmarking);
- check!("198.19.255.255", benchmarking);
- check!("192.0.0.0");
- check!("192.0.0.255");
- check!("192.0.0.100");
- check!("240.0.0.0", reserved);
- check!("251.54.1.76", reserved);
- check!("254.255.255.255", reserved);
- check!("100.64.0.0", shared);
- check!("100.127.255.255", shared);
- check!("100.100.100.0", shared);
-}
-
-#[test]
-fn ipv6_properties() {
- macro_rules! ip {
- ($s:expr) => {
- Ipv6Addr::from_str($s).unwrap()
- };
- }
-
- macro_rules! check {
- ($s:expr, &[$($octet:expr),*], $mask:expr) => {
- assert_eq!($s, ip!($s).to_string());
- let octets = &[$($octet),*];
- assert_eq!(&ip!($s).octets(), octets);
- assert_eq!(Ipv6Addr::from(*octets), ip!($s));
-
- let unspecified: u32 = 1 << 0;
- let loopback: u32 = 1 << 1;
- let unique_local: u32 = 1 << 2;
- let global: u32 = 1 << 3;
- let unicast_link_local: u32 = 1 << 4;
- let unicast_global: u32 = 1 << 7;
- let documentation: u32 = 1 << 8;
- let benchmarking: u32 = 1 << 16;
- let multicast_interface_local: u32 = 1 << 9;
- let multicast_link_local: u32 = 1 << 10;
- let multicast_realm_local: u32 = 1 << 11;
- let multicast_admin_local: u32 = 1 << 12;
- let multicast_site_local: u32 = 1 << 13;
- let multicast_organization_local: u32 = 1 << 14;
- let multicast_global: u32 = 1 << 15;
- let multicast: u32 = multicast_interface_local
- | multicast_admin_local
- | multicast_global
- | multicast_link_local
- | multicast_realm_local
- | multicast_site_local
- | multicast_organization_local;
-
- if ($mask & unspecified) == unspecified {
- assert!(ip!($s).is_unspecified());
- } else {
- assert!(!ip!($s).is_unspecified());
- }
- if ($mask & loopback) == loopback {
- assert!(ip!($s).is_loopback());
- } else {
- assert!(!ip!($s).is_loopback());
- }
- if ($mask & unique_local) == unique_local {
- assert!(ip!($s).is_unique_local());
- } else {
- assert!(!ip!($s).is_unique_local());
- }
- if ($mask & global) == global {
- assert!(ip!($s).is_global());
- } else {
- assert!(!ip!($s).is_global());
- }
- if ($mask & unicast_link_local) == unicast_link_local {
- assert!(ip!($s).is_unicast_link_local());
- } else {
- assert!(!ip!($s).is_unicast_link_local());
- }
- if ($mask & unicast_global) == unicast_global {
- assert!(ip!($s).is_unicast_global());
- } else {
- assert!(!ip!($s).is_unicast_global());
- }
- if ($mask & documentation) == documentation {
- assert!(ip!($s).is_documentation());
- } else {
- assert!(!ip!($s).is_documentation());
- }
- if ($mask & benchmarking) == benchmarking {
- assert!(ip!($s).is_benchmarking());
- } else {
- assert!(!ip!($s).is_benchmarking());
- }
- if ($mask & multicast) != 0 {
- assert!(ip!($s).multicast_scope().is_some());
- assert!(ip!($s).is_multicast());
- } else {
- assert!(ip!($s).multicast_scope().is_none());
- assert!(!ip!($s).is_multicast());
- }
- if ($mask & multicast_interface_local) == multicast_interface_local {
- assert_eq!(ip!($s).multicast_scope().unwrap(),
- Ipv6MulticastScope::InterfaceLocal);
- }
- if ($mask & multicast_link_local) == multicast_link_local {
- assert_eq!(ip!($s).multicast_scope().unwrap(),
- Ipv6MulticastScope::LinkLocal);
- }
- if ($mask & multicast_realm_local) == multicast_realm_local {
- assert_eq!(ip!($s).multicast_scope().unwrap(),
- Ipv6MulticastScope::RealmLocal);
- }
- if ($mask & multicast_admin_local) == multicast_admin_local {
- assert_eq!(ip!($s).multicast_scope().unwrap(),
- Ipv6MulticastScope::AdminLocal);
- }
- if ($mask & multicast_site_local) == multicast_site_local {
- assert_eq!(ip!($s).multicast_scope().unwrap(),
- Ipv6MulticastScope::SiteLocal);
- }
- if ($mask & multicast_organization_local) == multicast_organization_local {
- assert_eq!(ip!($s).multicast_scope().unwrap(),
- Ipv6MulticastScope::OrganizationLocal);
- }
- if ($mask & multicast_global) == multicast_global {
- assert_eq!(ip!($s).multicast_scope().unwrap(),
- Ipv6MulticastScope::Global);
- }
- }
- }
-
- let unspecified: u32 = 1 << 0;
- let loopback: u32 = 1 << 1;
- let unique_local: u32 = 1 << 2;
- let global: u32 = 1 << 3;
- let unicast_link_local: u32 = 1 << 4;
- let unicast_global: u32 = 1 << 7;
- let documentation: u32 = 1 << 8;
- let benchmarking: u32 = 1 << 16;
- let multicast_interface_local: u32 = 1 << 9;
- let multicast_link_local: u32 = 1 << 10;
- let multicast_realm_local: u32 = 1 << 11;
- let multicast_admin_local: u32 = 1 << 12;
- let multicast_site_local: u32 = 1 << 13;
- let multicast_organization_local: u32 = 1 << 14;
- let multicast_global: u32 = 1 << 15;
-
- check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified);
-
- check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback);
-
- check!("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global);
-
- check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global);
-
- check!(
- "::ffff:127.0.0.1",
- &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1],
- unicast_global
- );
-
- check!(
- "64:ff9b:1::",
- &[0, 0x64, 0xff, 0x9b, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- unicast_global
- );
-
- check!("100::", &[0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
-
- check!("2001::", &[0x20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
-
- check!(
- "2001:1::1",
- &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
- global | unicast_global
- );
-
- check!(
- "2001:1::2",
- &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2],
- global | unicast_global
- );
-
- check!(
- "2001:3::",
- &[0x20, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- global | unicast_global
- );
-
- check!(
- "2001:4:112::",
- &[0x20, 1, 0, 4, 1, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- global | unicast_global
- );
-
- check!(
- "2001:20::",
- &[0x20, 1, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- global | unicast_global
- );
-
- check!("2001:30::", &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
-
- check!(
- "2001:200::",
- &[0x20, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- global | unicast_global
- );
-
- check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local);
-
- check!(
- "fdff:ffff::",
- &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- unique_local
- );
-
- check!(
- "fe80:ffff::",
- &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- unicast_link_local
- );
-
- check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local);
-
- check!(
- "febf:ffff::",
- &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- unicast_link_local
- );
-
- check!("febf::", &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local);
-
- check!(
- "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
- &[
- 0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff
- ],
- unicast_link_local
- );
-
- check!(
- "fe80::ffff:ffff:ffff:ffff",
- &[
- 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff
- ],
- unicast_link_local
- );
-
- check!(
- "fe80:0:0:1::",
- &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
- unicast_link_local
- );
-
- check!(
- "fec0::",
- &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- unicast_global | global
- );
-
- check!(
- "ff01::",
- &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- multicast_interface_local | global
- );
-
- check!(
- "ff02::",
- &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- multicast_link_local | global
- );
-
- check!(
- "ff03::",
- &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- multicast_realm_local | global
- );
-
- check!(
- "ff04::",
- &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- multicast_admin_local | global
- );
-
- check!(
- "ff05::",
- &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- multicast_site_local | global
- );
-
- check!(
- "ff08::",
- &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- multicast_organization_local | global
- );
-
- check!(
- "ff0e::",
- &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- multicast_global | global
- );
-
- check!(
- "2001:db8:85a3::8a2e:370:7334",
- &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34],
- documentation
- );
-
- check!(
- "2001:2::ac32:23ff:21",
- &[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21],
- benchmarking
- );
-
- check!(
- "102:304:506:708:90a:b0c:d0e:f10",
- &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
- global | unicast_global
- );
-}
+use crate::net::test::{sa4, tsa};
+use crate::net::Ipv4Addr;
#[test]
fn to_socket_addr_socketaddr() {
let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345);
assert_eq!(Ok(vec![a]), tsa(a));
}
-
-#[test]
-fn test_ipv4_to_int() {
- let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
- assert_eq!(u32::from(a), 0x11223344);
-}
-
-#[test]
-fn test_int_to_ipv4() {
- let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
- assert_eq!(Ipv4Addr::from(0x11223344), a);
-}
-
-#[test]
-fn test_ipv6_to_int() {
- let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
- assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128);
-}
-
-#[test]
-fn test_int_to_ipv6() {
- let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
- assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a);
-}
-
-#[test]
-fn ipv4_from_constructors() {
- assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1));
- assert!(Ipv4Addr::LOCALHOST.is_loopback());
- assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0));
- assert!(Ipv4Addr::UNSPECIFIED.is_unspecified());
- assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255));
- assert!(Ipv4Addr::BROADCAST.is_broadcast());
-}
-
-#[test]
-fn ipv6_from_constructors() {
- assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
- assert!(Ipv6Addr::LOCALHOST.is_loopback());
- assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
- assert!(Ipv6Addr::UNSPECIFIED.is_unspecified());
-}
-
-#[test]
-fn ipv4_from_octets() {
- assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1))
-}
-
-#[test]
-fn ipv6_from_segments() {
- let from_u16s =
- Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
- let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff);
- assert_eq!(new, from_u16s);
-}
-
-#[test]
-fn ipv6_from_octets() {
- let from_u16s =
- Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
- let from_u8s = Ipv6Addr::from([
- 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
- 0xff,
- ]);
- assert_eq!(from_u16s, from_u8s);
-}
-
-#[test]
-fn cmp() {
- let v41 = Ipv4Addr::new(100, 64, 3, 3);
- let v42 = Ipv4Addr::new(192, 0, 2, 2);
- let v61 = "2001:db8:f00::1002".parse::<Ipv6Addr>().unwrap();
- let v62 = "2001:db8:f00::2001".parse::<Ipv6Addr>().unwrap();
- assert!(v41 < v42);
- assert!(v61 < v62);
-
- assert_eq!(v41, IpAddr::V4(v41));
- assert_eq!(v61, IpAddr::V6(v61));
- assert!(v41 != IpAddr::V4(v42));
- assert!(v61 != IpAddr::V6(v62));
-
- assert!(v41 < IpAddr::V4(v42));
- assert!(v61 < IpAddr::V6(v62));
- assert!(IpAddr::V4(v41) < v42);
- assert!(IpAddr::V6(v61) < v62);
-
- assert!(v41 < IpAddr::V6(v61));
- assert!(IpAddr::V4(v41) < v61);
-}
-
-#[test]
-fn is_v4() {
- let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3));
- assert!(ip.is_ipv4());
- assert!(!ip.is_ipv6());
-}
-
-#[test]
-fn is_v6() {
- let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678));
- assert!(!ip.is_ipv4());
- assert!(ip.is_ipv6());
-}
-
-#[test]
-fn ipv4_const() {
- // test that the methods of `Ipv4Addr` are usable in a const context
-
- const IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1);
- assert_eq!(IP_ADDRESS, Ipv4Addr::LOCALHOST);
-
- const OCTETS: [u8; 4] = IP_ADDRESS.octets();
- assert_eq!(OCTETS, [127, 0, 0, 1]);
-
- const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified();
- assert!(!IS_UNSPECIFIED);
-
- const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback();
- assert!(IS_LOOPBACK);
-
- const IS_PRIVATE: bool = IP_ADDRESS.is_private();
- assert!(!IS_PRIVATE);
-
- const IS_LINK_LOCAL: bool = IP_ADDRESS.is_link_local();
- assert!(!IS_LINK_LOCAL);
-
- const IS_GLOBAL: bool = IP_ADDRESS.is_global();
- assert!(!IS_GLOBAL);
-
- const IS_SHARED: bool = IP_ADDRESS.is_shared();
- assert!(!IS_SHARED);
-
- const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking();
- assert!(!IS_BENCHMARKING);
-
- const IS_RESERVED: bool = IP_ADDRESS.is_reserved();
- assert!(!IS_RESERVED);
-
- const IS_MULTICAST: bool = IP_ADDRESS.is_multicast();
- assert!(!IS_MULTICAST);
-
- const IS_BROADCAST: bool = IP_ADDRESS.is_broadcast();
- assert!(!IS_BROADCAST);
-
- const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation();
- assert!(!IS_DOCUMENTATION);
-
- const IP_V6_COMPATIBLE: Ipv6Addr = IP_ADDRESS.to_ipv6_compatible();
- assert_eq!(
- IP_V6_COMPATIBLE,
- Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1])
- );
-
- const IP_V6_MAPPED: Ipv6Addr = IP_ADDRESS.to_ipv6_mapped();
- assert_eq!(
- IP_V6_MAPPED,
- Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1])
- );
-}
-
-#[test]
-fn ipv6_const() {
- // test that the methods of `Ipv6Addr` are usable in a const context
-
- const IP_ADDRESS: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
- assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST);
-
- const SEGMENTS: [u16; 8] = IP_ADDRESS.segments();
- assert_eq!(SEGMENTS, [0, 0, 0, 0, 0, 0, 0, 1]);
-
- const OCTETS: [u8; 16] = IP_ADDRESS.octets();
- assert_eq!(OCTETS, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
-
- const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified();
- assert!(!IS_UNSPECIFIED);
-
- const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback();
- assert!(IS_LOOPBACK);
-
- const IS_GLOBAL: bool = IP_ADDRESS.is_global();
- assert!(!IS_GLOBAL);
-
- const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local();
- assert!(!IS_UNIQUE_LOCAL);
-
- const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local();
- assert!(!IS_UNICAST_LINK_LOCAL);
-
- const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation();
- assert!(!IS_DOCUMENTATION);
-
- const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking();
- assert!(!IS_BENCHMARKING);
-
- const IS_UNICAST_GLOBAL: bool = IP_ADDRESS.is_unicast_global();
- assert!(!IS_UNICAST_GLOBAL);
-
- const MULTICAST_SCOPE: Option<Ipv6MulticastScope> = IP_ADDRESS.multicast_scope();
- assert_eq!(MULTICAST_SCOPE, None);
-
- const IS_MULTICAST: bool = IP_ADDRESS.is_multicast();
- assert!(!IS_MULTICAST);
-
- const IP_V4: Option<Ipv4Addr> = IP_ADDRESS.to_ipv4();
- assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1));
-}
-
-#[test]
-fn ip_const() {
- // test that the methods of `IpAddr` are usable in a const context
-
- const IP_ADDRESS: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST);
-
- const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified();
- assert!(!IS_UNSPECIFIED);
-
- const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback();
- assert!(IS_LOOPBACK);
-
- const IS_GLOBAL: bool = IP_ADDRESS.is_global();
- assert!(!IS_GLOBAL);
-
- const IS_MULTICAST: bool = IP_ADDRESS.is_multicast();
- assert!(!IS_MULTICAST);
-
- const IS_IP_V4: bool = IP_ADDRESS.is_ipv4();
- assert!(IS_IP_V4);
-
- const IS_IP_V6: bool = IP_ADDRESS.is_ipv6();
- assert!(!IS_IP_V6);
-}
-
-#[test]
-fn structural_match() {
- // test that all IP types can be structurally matched upon
-
- const IPV4: Ipv4Addr = Ipv4Addr::LOCALHOST;
- match IPV4 {
- Ipv4Addr::LOCALHOST => {}
- _ => unreachable!(),
- }
-
- const IPV6: Ipv6Addr = Ipv6Addr::LOCALHOST;
- match IPV6 {
- Ipv6Addr::LOCALHOST => {}
- _ => unreachable!(),
- }
-
- const IP: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST);
- match IP {
- IpAddr::V4(Ipv4Addr::LOCALHOST) => {}
- _ => unreachable!(),
- }
-}
diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs
index 19d90e7ec..bcab15db3 100644
--- a/library/std/src/net/mod.rs
+++ b/library/std/src/net/mod.rs
@@ -26,8 +26,6 @@ use crate::io::{self, ErrorKind};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::ip_addr::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::parser::AddrParseError;
-#[stable(feature = "rust1", since = "1.0.0")]
pub use self::socket_addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
#[unstable(feature = "tcplistener_into_incoming", issue = "88339")]
pub use self::tcp::IntoIncoming;
@@ -35,10 +33,10 @@ pub use self::tcp::IntoIncoming;
pub use self::tcp::{Incoming, TcpListener, TcpStream};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::udp::UdpSocket;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::net::AddrParseError;
-mod display_buffer;
mod ip_addr;
-mod parser;
mod socket_addr;
mod tcp;
#[cfg(test)]
diff --git a/library/std/src/net/parser.rs b/library/std/src/net/parser.rs
deleted file mode 100644
index a38031c48..000000000
--- a/library/std/src/net/parser.rs
+++ /dev/null
@@ -1,500 +0,0 @@
-//! A private parser implementation of IPv4, IPv6, and socket addresses.
-//!
-//! This module is "publicly exported" through the `FromStr` implementations
-//! below.
-
-#[cfg(test)]
-mod tests;
-
-use crate::error::Error;
-use crate::fmt;
-use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
-use crate::str::FromStr;
-
-trait ReadNumberHelper: crate::marker::Sized {
- const ZERO: Self;
- fn checked_mul(&self, other: u32) -> Option<Self>;
- fn checked_add(&self, other: u32) -> Option<Self>;
-}
-
-macro_rules! impl_helper {
- ($($t:ty)*) => ($(impl ReadNumberHelper for $t {
- const ZERO: Self = 0;
- #[inline]
- fn checked_mul(&self, other: u32) -> Option<Self> {
- Self::checked_mul(*self, other.try_into().ok()?)
- }
- #[inline]
- fn checked_add(&self, other: u32) -> Option<Self> {
- Self::checked_add(*self, other.try_into().ok()?)
- }
- })*)
-}
-
-impl_helper! { u8 u16 u32 }
-
-struct Parser<'a> {
- // Parsing as ASCII, so can use byte array.
- state: &'a [u8],
-}
-
-impl<'a> Parser<'a> {
- fn new(input: &'a [u8]) -> Parser<'a> {
- Parser { state: input }
- }
-
- /// Run a parser, and restore the pre-parse state if it fails.
- fn read_atomically<T, F>(&mut self, inner: F) -> Option<T>
- where
- F: FnOnce(&mut Parser<'_>) -> Option<T>,
- {
- let state = self.state;
- let result = inner(self);
- if result.is_none() {
- self.state = state;
- }
- result
- }
-
- /// Run a parser, but fail if the entire input wasn't consumed.
- /// Doesn't run atomically.
- fn parse_with<T, F>(&mut self, inner: F, kind: AddrKind) -> Result<T, AddrParseError>
- where
- F: FnOnce(&mut Parser<'_>) -> Option<T>,
- {
- let result = inner(self);
- if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(kind))
- }
-
- /// Peek the next character from the input
- fn peek_char(&self) -> Option<char> {
- self.state.first().map(|&b| char::from(b))
- }
-
- /// Read the next character from the input
- fn read_char(&mut self) -> Option<char> {
- self.state.split_first().map(|(&b, tail)| {
- self.state = tail;
- char::from(b)
- })
- }
-
- #[must_use]
- /// Read the next character from the input if it matches the target.
- fn read_given_char(&mut self, target: char) -> Option<()> {
- self.read_atomically(|p| {
- p.read_char().and_then(|c| if c == target { Some(()) } else { None })
- })
- }
-
- /// Helper for reading separators in an indexed loop. Reads the separator
- /// character iff index > 0, then runs the parser. When used in a loop,
- /// the separator character will only be read on index > 0 (see
- /// read_ipv4_addr for an example)
- fn read_separator<T, F>(&mut self, sep: char, index: usize, inner: F) -> Option<T>
- where
- F: FnOnce(&mut Parser<'_>) -> Option<T>,
- {
- self.read_atomically(move |p| {
- if index > 0 {
- p.read_given_char(sep)?;
- }
- inner(p)
- })
- }
-
- // Read a number off the front of the input in the given radix, stopping
- // at the first non-digit character or eof. Fails if the number has more
- // digits than max_digits or if there is no number.
- fn read_number<T: ReadNumberHelper>(
- &mut self,
- radix: u32,
- max_digits: Option<usize>,
- allow_zero_prefix: bool,
- ) -> Option<T> {
- self.read_atomically(move |p| {
- let mut result = T::ZERO;
- let mut digit_count = 0;
- let has_leading_zero = p.peek_char() == Some('0');
-
- while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) {
- result = result.checked_mul(radix)?;
- result = result.checked_add(digit)?;
- digit_count += 1;
- if let Some(max_digits) = max_digits {
- if digit_count > max_digits {
- return None;
- }
- }
- }
-
- if digit_count == 0 {
- None
- } else if !allow_zero_prefix && has_leading_zero && digit_count > 1 {
- None
- } else {
- Some(result)
- }
- })
- }
-
- /// Read an IPv4 address.
- fn read_ipv4_addr(&mut self) -> Option<Ipv4Addr> {
- self.read_atomically(|p| {
- let mut groups = [0; 4];
-
- for (i, slot) in groups.iter_mut().enumerate() {
- *slot = p.read_separator('.', i, |p| {
- // Disallow octal number in IP string.
- // https://tools.ietf.org/html/rfc6943#section-3.1.1
- p.read_number(10, Some(3), false)
- })?;
- }
-
- Some(groups.into())
- })
- }
-
- /// Read an IPv6 Address.
- fn read_ipv6_addr(&mut self) -> Option<Ipv6Addr> {
- /// Read a chunk of an IPv6 address into `groups`. Returns the number
- /// of groups read, along with a bool indicating if an embedded
- /// trailing IPv4 address was read. Specifically, read a series of
- /// colon-separated IPv6 groups (0x0000 - 0xFFFF), with an optional
- /// trailing embedded IPv4 address.
- fn read_groups(p: &mut Parser<'_>, groups: &mut [u16]) -> (usize, bool) {
- let limit = groups.len();
-
- for (i, slot) in groups.iter_mut().enumerate() {
- // Try to read a trailing embedded IPv4 address. There must be
- // at least two groups left.
- if i < limit - 1 {
- let ipv4 = p.read_separator(':', i, |p| p.read_ipv4_addr());
-
- if let Some(v4_addr) = ipv4 {
- let [one, two, three, four] = v4_addr.octets();
- groups[i + 0] = u16::from_be_bytes([one, two]);
- groups[i + 1] = u16::from_be_bytes([three, four]);
- return (i + 2, true);
- }
- }
-
- let group = p.read_separator(':', i, |p| p.read_number(16, Some(4), true));
-
- match group {
- Some(g) => *slot = g,
- None => return (i, false),
- }
- }
- (groups.len(), false)
- }
-
- self.read_atomically(|p| {
- // Read the front part of the address; either the whole thing, or up
- // to the first ::
- let mut head = [0; 8];
- let (head_size, head_ipv4) = read_groups(p, &mut head);
-
- if head_size == 8 {
- return Some(head.into());
- }
-
- // IPv4 part is not allowed before `::`
- if head_ipv4 {
- return None;
- }
-
- // Read `::` if previous code parsed less than 8 groups.
- // `::` indicates one or more groups of 16 bits of zeros.
- p.read_given_char(':')?;
- p.read_given_char(':')?;
-
- // Read the back part of the address. The :: must contain at least one
- // set of zeroes, so our max length is 7.
- let mut tail = [0; 7];
- let limit = 8 - (head_size + 1);
- let (tail_size, _) = read_groups(p, &mut tail[..limit]);
-
- // Concat the head and tail of the IP address
- head[(8 - tail_size)..8].copy_from_slice(&tail[..tail_size]);
-
- Some(head.into())
- })
- }
-
- /// Read an IP Address, either IPv4 or IPv6.
- fn read_ip_addr(&mut self) -> Option<IpAddr> {
- self.read_ipv4_addr().map(IpAddr::V4).or_else(move || self.read_ipv6_addr().map(IpAddr::V6))
- }
-
- /// Read a `:` followed by a port in base 10.
- fn read_port(&mut self) -> Option<u16> {
- self.read_atomically(|p| {
- p.read_given_char(':')?;
- p.read_number(10, None, true)
- })
- }
-
- /// Read a `%` followed by a scope ID in base 10.
- fn read_scope_id(&mut self) -> Option<u32> {
- self.read_atomically(|p| {
- p.read_given_char('%')?;
- p.read_number(10, None, true)
- })
- }
-
- /// Read an IPv4 address with a port.
- fn read_socket_addr_v4(&mut self) -> Option<SocketAddrV4> {
- self.read_atomically(|p| {
- let ip = p.read_ipv4_addr()?;
- let port = p.read_port()?;
- Some(SocketAddrV4::new(ip, port))
- })
- }
-
- /// Read an IPv6 address with a port.
- fn read_socket_addr_v6(&mut self) -> Option<SocketAddrV6> {
- self.read_atomically(|p| {
- p.read_given_char('[')?;
- let ip = p.read_ipv6_addr()?;
- let scope_id = p.read_scope_id().unwrap_or(0);
- p.read_given_char(']')?;
-
- let port = p.read_port()?;
- Some(SocketAddrV6::new(ip, port, 0, scope_id))
- })
- }
-
- /// Read an IP address with a port
- fn read_socket_addr(&mut self) -> Option<SocketAddr> {
- self.read_socket_addr_v4()
- .map(SocketAddr::V4)
- .or_else(|| self.read_socket_addr_v6().map(SocketAddr::V6))
- }
-}
-
-impl IpAddr {
- /// Parse an IP address from a slice of bytes.
- ///
- /// ```
- /// #![feature(addr_parse_ascii)]
- ///
- /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
- ///
- /// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
- /// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
- ///
- /// assert_eq!(IpAddr::parse_ascii(b"127.0.0.1"), Ok(localhost_v4));
- /// assert_eq!(IpAddr::parse_ascii(b"::1"), Ok(localhost_v6));
- /// ```
- #[unstable(feature = "addr_parse_ascii", issue = "101035")]
- pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
- Parser::new(b).parse_with(|p| p.read_ip_addr(), AddrKind::Ip)
- }
-}
-
-#[stable(feature = "ip_addr", since = "1.7.0")]
-impl FromStr for IpAddr {
- type Err = AddrParseError;
- fn from_str(s: &str) -> Result<IpAddr, AddrParseError> {
- Self::parse_ascii(s.as_bytes())
- }
-}
-
-impl Ipv4Addr {
- /// Parse an IPv4 address from a slice of bytes.
- ///
- /// ```
- /// #![feature(addr_parse_ascii)]
- ///
- /// use std::net::Ipv4Addr;
- ///
- /// let localhost = Ipv4Addr::new(127, 0, 0, 1);
- ///
- /// assert_eq!(Ipv4Addr::parse_ascii(b"127.0.0.1"), Ok(localhost));
- /// ```
- #[unstable(feature = "addr_parse_ascii", issue = "101035")]
- pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
- // don't try to parse if too long
- if b.len() > 15 {
- Err(AddrParseError(AddrKind::Ipv4))
- } else {
- Parser::new(b).parse_with(|p| p.read_ipv4_addr(), AddrKind::Ipv4)
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl FromStr for Ipv4Addr {
- type Err = AddrParseError;
- fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
- Self::parse_ascii(s.as_bytes())
- }
-}
-
-impl Ipv6Addr {
- /// Parse an IPv6 address from a slice of bytes.
- ///
- /// ```
- /// #![feature(addr_parse_ascii)]
- ///
- /// use std::net::Ipv6Addr;
- ///
- /// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
- ///
- /// assert_eq!(Ipv6Addr::parse_ascii(b"::1"), Ok(localhost));
- /// ```
- #[unstable(feature = "addr_parse_ascii", issue = "101035")]
- pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
- Parser::new(b).parse_with(|p| p.read_ipv6_addr(), AddrKind::Ipv6)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl FromStr for Ipv6Addr {
- type Err = AddrParseError;
- fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> {
- Self::parse_ascii(s.as_bytes())
- }
-}
-
-impl SocketAddrV4 {
- /// Parse an IPv4 socket address from a slice of bytes.
- ///
- /// ```
- /// #![feature(addr_parse_ascii)]
- ///
- /// use std::net::{Ipv4Addr, SocketAddrV4};
- ///
- /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
- ///
- /// assert_eq!(SocketAddrV4::parse_ascii(b"127.0.0.1:8080"), Ok(socket));
- /// ```
- #[unstable(feature = "addr_parse_ascii", issue = "101035")]
- pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
- Parser::new(b).parse_with(|p| p.read_socket_addr_v4(), AddrKind::SocketV4)
- }
-}
-
-#[stable(feature = "socket_addr_from_str", since = "1.5.0")]
-impl FromStr for SocketAddrV4 {
- type Err = AddrParseError;
- fn from_str(s: &str) -> Result<SocketAddrV4, AddrParseError> {
- Self::parse_ascii(s.as_bytes())
- }
-}
-
-impl SocketAddrV6 {
- /// Parse an IPv6 socket address from a slice of bytes.
- ///
- /// ```
- /// #![feature(addr_parse_ascii)]
- ///
- /// use std::net::{Ipv6Addr, SocketAddrV6};
- ///
- /// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
- ///
- /// assert_eq!(SocketAddrV6::parse_ascii(b"[2001:db8::1]:8080"), Ok(socket));
- /// ```
- #[unstable(feature = "addr_parse_ascii", issue = "101035")]
- pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
- Parser::new(b).parse_with(|p| p.read_socket_addr_v6(), AddrKind::SocketV6)
- }
-}
-
-#[stable(feature = "socket_addr_from_str", since = "1.5.0")]
-impl FromStr for SocketAddrV6 {
- type Err = AddrParseError;
- fn from_str(s: &str) -> Result<SocketAddrV6, AddrParseError> {
- Self::parse_ascii(s.as_bytes())
- }
-}
-
-impl SocketAddr {
- /// Parse a socket address from a slice of bytes.
- ///
- /// ```
- /// #![feature(addr_parse_ascii)]
- ///
- /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
- ///
- /// let socket_v4 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
- /// let socket_v6 = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 8080);
- ///
- /// assert_eq!(SocketAddr::parse_ascii(b"127.0.0.1:8080"), Ok(socket_v4));
- /// assert_eq!(SocketAddr::parse_ascii(b"[::1]:8080"), Ok(socket_v6));
- /// ```
- #[unstable(feature = "addr_parse_ascii", issue = "101035")]
- pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
- Parser::new(b).parse_with(|p| p.read_socket_addr(), AddrKind::Socket)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl FromStr for SocketAddr {
- type Err = AddrParseError;
- fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> {
- Self::parse_ascii(s.as_bytes())
- }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-enum AddrKind {
- Ip,
- Ipv4,
- Ipv6,
- Socket,
- SocketV4,
- SocketV6,
-}
-
-/// An error which can be returned when parsing an IP address or a socket address.
-///
-/// This error is used as the error type for the [`FromStr`] implementation for
-/// [`IpAddr`], [`Ipv4Addr`], [`Ipv6Addr`], [`SocketAddr`], [`SocketAddrV4`], and
-/// [`SocketAddrV6`].
-///
-/// # Potential causes
-///
-/// `AddrParseError` may be thrown because the provided string does not parse as the given type,
-/// often because it includes information only handled by a different address type.
-///
-/// ```should_panic
-/// use std::net::IpAddr;
-/// let _foo: IpAddr = "127.0.0.1:8080".parse().expect("Cannot handle the socket port");
-/// ```
-///
-/// [`IpAddr`] doesn't handle the port. Use [`SocketAddr`] instead.
-///
-/// ```
-/// use std::net::SocketAddr;
-///
-/// // No problem, the `panic!` message has disappeared.
-/// let _foo: SocketAddr = "127.0.0.1:8080".parse().expect("unreachable panic");
-/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct AddrParseError(AddrKind);
-
-#[stable(feature = "addr_parse_error_error", since = "1.4.0")]
-impl fmt::Display for AddrParseError {
- #[allow(deprecated, deprecated_in_future)]
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt.write_str(self.description())
- }
-}
-
-#[stable(feature = "addr_parse_error_error", since = "1.4.0")]
-impl Error for AddrParseError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- match self.0 {
- AddrKind::Ip => "invalid IP address syntax",
- AddrKind::Ipv4 => "invalid IPv4 address syntax",
- AddrKind::Ipv6 => "invalid IPv6 address syntax",
- AddrKind::Socket => "invalid socket address syntax",
- AddrKind::SocketV4 => "invalid IPv4 socket address syntax",
- AddrKind::SocketV6 => "invalid IPv6 socket address syntax",
- }
- }
-}
diff --git a/library/std/src/net/parser/tests.rs b/library/std/src/net/parser/tests.rs
deleted file mode 100644
index 6d2d48eca..000000000
--- a/library/std/src/net/parser/tests.rs
+++ /dev/null
@@ -1,149 +0,0 @@
-// FIXME: These tests are all excellent candidates for AFL fuzz testing
-use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
-use crate::str::FromStr;
-
-const PORT: u16 = 8080;
-const SCOPE_ID: u32 = 1337;
-
-const IPV4: Ipv4Addr = Ipv4Addr::new(192, 168, 0, 1);
-const IPV4_STR: &str = "192.168.0.1";
-const IPV4_STR_PORT: &str = "192.168.0.1:8080";
-const IPV4_STR_WITH_OCTAL: &str = "0127.0.0.1";
-const IPV4_STR_WITH_HEX: &str = "0x10.0.0.1";
-
-const IPV6: Ipv6Addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0xc0a8, 0x1);
-const IPV6_STR_FULL: &str = "2001:db8:0:0:0:0:c0a8:1";
-const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1";
-const IPV6_STR_V4: &str = "2001:db8::192.168.0.1";
-const IPV6_STR_V4_WITH_OCTAL: &str = "2001:db8::0127.0.0.1";
-const IPV6_STR_V4_WITH_HEX: &str = "2001:db8::0x10.0.0.1";
-const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080";
-const IPV6_STR_PORT_SCOPE_ID: &str = "[2001:db8::c0a8:1%1337]:8080";
-
-#[test]
-fn parse_ipv4() {
- let result: Ipv4Addr = IPV4_STR.parse().unwrap();
- assert_eq!(result, IPV4);
-
- assert!(Ipv4Addr::from_str(IPV4_STR_PORT).is_err());
- assert!(Ipv4Addr::from_str(IPV4_STR_WITH_OCTAL).is_err());
- assert!(Ipv4Addr::from_str(IPV4_STR_WITH_HEX).is_err());
- assert!(Ipv4Addr::from_str(IPV6_STR_FULL).is_err());
- assert!(Ipv4Addr::from_str(IPV6_STR_COMPRESS).is_err());
- assert!(Ipv4Addr::from_str(IPV6_STR_V4).is_err());
- assert!(Ipv4Addr::from_str(IPV6_STR_PORT).is_err());
-}
-
-#[test]
-fn parse_ipv6() {
- let result: Ipv6Addr = IPV6_STR_FULL.parse().unwrap();
- assert_eq!(result, IPV6);
-
- let result: Ipv6Addr = IPV6_STR_COMPRESS.parse().unwrap();
- assert_eq!(result, IPV6);
-
- let result: Ipv6Addr = IPV6_STR_V4.parse().unwrap();
- assert_eq!(result, IPV6);
-
- assert!(Ipv6Addr::from_str(IPV6_STR_V4_WITH_OCTAL).is_err());
- assert!(Ipv6Addr::from_str(IPV6_STR_V4_WITH_HEX).is_err());
- assert!(Ipv6Addr::from_str(IPV4_STR).is_err());
- assert!(Ipv6Addr::from_str(IPV4_STR_PORT).is_err());
- assert!(Ipv6Addr::from_str(IPV6_STR_PORT).is_err());
-}
-
-#[test]
-fn parse_ip() {
- let result: IpAddr = IPV4_STR.parse().unwrap();
- assert_eq!(result, IpAddr::from(IPV4));
-
- let result: IpAddr = IPV6_STR_FULL.parse().unwrap();
- assert_eq!(result, IpAddr::from(IPV6));
-
- let result: IpAddr = IPV6_STR_COMPRESS.parse().unwrap();
- assert_eq!(result, IpAddr::from(IPV6));
-
- let result: IpAddr = IPV6_STR_V4.parse().unwrap();
- assert_eq!(result, IpAddr::from(IPV6));
-
- assert!(IpAddr::from_str(IPV4_STR_PORT).is_err());
- assert!(IpAddr::from_str(IPV6_STR_PORT).is_err());
-}
-
-#[test]
-fn parse_socket_v4() {
- let result: SocketAddrV4 = IPV4_STR_PORT.parse().unwrap();
- assert_eq!(result, SocketAddrV4::new(IPV4, PORT));
-
- assert!(SocketAddrV4::from_str(IPV4_STR).is_err());
- assert!(SocketAddrV4::from_str(IPV6_STR_FULL).is_err());
- assert!(SocketAddrV4::from_str(IPV6_STR_COMPRESS).is_err());
- assert!(SocketAddrV4::from_str(IPV6_STR_V4).is_err());
- assert!(SocketAddrV4::from_str(IPV6_STR_PORT).is_err());
-}
-
-#[test]
-fn parse_socket_v6() {
- assert_eq!(IPV6_STR_PORT.parse(), Ok(SocketAddrV6::new(IPV6, PORT, 0, 0)));
- assert_eq!(IPV6_STR_PORT_SCOPE_ID.parse(), Ok(SocketAddrV6::new(IPV6, PORT, 0, SCOPE_ID)));
-
- assert!(SocketAddrV6::from_str(IPV4_STR).is_err());
- assert!(SocketAddrV6::from_str(IPV4_STR_PORT).is_err());
- assert!(SocketAddrV6::from_str(IPV6_STR_FULL).is_err());
- assert!(SocketAddrV6::from_str(IPV6_STR_COMPRESS).is_err());
- assert!(SocketAddrV6::from_str(IPV6_STR_V4).is_err());
-}
-
-#[test]
-fn parse_socket() {
- let result: SocketAddr = IPV4_STR_PORT.parse().unwrap();
- assert_eq!(result, SocketAddr::from((IPV4, PORT)));
-
- let result: SocketAddr = IPV6_STR_PORT.parse().unwrap();
- assert_eq!(result, SocketAddr::from((IPV6, PORT)));
-
- assert!(SocketAddr::from_str(IPV4_STR).is_err());
- assert!(SocketAddr::from_str(IPV6_STR_FULL).is_err());
- assert!(SocketAddr::from_str(IPV6_STR_COMPRESS).is_err());
- assert!(SocketAddr::from_str(IPV6_STR_V4).is_err());
-}
-
-#[test]
-fn ipv6_corner_cases() {
- let result: Ipv6Addr = "1::".parse().unwrap();
- assert_eq!(result, Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0));
-
- let result: Ipv6Addr = "1:1::".parse().unwrap();
- assert_eq!(result, Ipv6Addr::new(1, 1, 0, 0, 0, 0, 0, 0));
-
- let result: Ipv6Addr = "::1".parse().unwrap();
- assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
-
- let result: Ipv6Addr = "::1:1".parse().unwrap();
- assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 1, 1));
-
- let result: Ipv6Addr = "::".parse().unwrap();
- assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
-
- let result: Ipv6Addr = "::192.168.0.1".parse().unwrap();
- assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc0a8, 0x1));
-
- let result: Ipv6Addr = "::1:192.168.0.1".parse().unwrap();
- assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 1, 0xc0a8, 0x1));
-
- let result: Ipv6Addr = "1:1:1:1:1:1:192.168.0.1".parse().unwrap();
- assert_eq!(result, Ipv6Addr::new(1, 1, 1, 1, 1, 1, 0xc0a8, 0x1));
-}
-
-// Things that might not seem like failures but are
-#[test]
-fn ipv6_corner_failures() {
- // No IP address before the ::
- assert!(Ipv6Addr::from_str("1:192.168.0.1::").is_err());
-
- // :: must have at least 1 set of zeroes
- assert!(Ipv6Addr::from_str("1:1:1:1::1:1:1:1").is_err());
-
- // Need brackets for a port
- assert!(SocketAddrV6::from_str("1:1:1:1:1:1:1:1:8080").is_err());
-}
diff --git a/library/std/src/net/socket_addr.rs b/library/std/src/net/socket_addr.rs
index 33b0dfa03..421fed907 100644
--- a/library/std/src/net/socket_addr.rs
+++ b/library/std/src/net/socket_addr.rs
@@ -1,9 +1,7 @@
+// Tests for this module
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
-use crate::cmp::Ordering;
-use crate::fmt::{self, Write};
-use crate::hash;
use crate::io;
use crate::iter;
use crate::mem;
@@ -15,533 +13,23 @@ use crate::sys_common::net::LookupHost;
use crate::sys_common::{FromInner, IntoInner};
use crate::vec;
-use super::display_buffer::DisplayBuffer;
-
-/// An internet socket address, either IPv4 or IPv6.
-///
-/// Internet socket addresses consist of an [IP address], a 16-bit port number, as well
-/// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and
-/// [`SocketAddrV6`]'s respective documentation for more details.
-///
-/// The size of a `SocketAddr` instance may vary depending on the target operating
-/// system.
-///
-/// [IP address]: IpAddr
-///
-/// # Examples
-///
-/// ```
-/// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
-///
-/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
-///
-/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket));
-/// assert_eq!(socket.port(), 8080);
-/// assert_eq!(socket.is_ipv4(), true);
-/// ```
-#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub enum SocketAddr {
- /// An IPv4 socket address.
- #[stable(feature = "rust1", since = "1.0.0")]
- V4(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV4),
- /// An IPv6 socket address.
- #[stable(feature = "rust1", since = "1.0.0")]
- V6(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV6),
-}
-
-/// An IPv4 socket address.
-///
-/// IPv4 socket addresses consist of an [`IPv4` address] and a 16-bit port number, as
-/// stated in [IETF RFC 793].
-///
-/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses.
-///
-/// The size of a `SocketAddrV4` struct may vary depending on the target operating
-/// system. Do not assume that this type has the same memory layout as the underlying
-/// system representation.
-///
-/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793
-/// [`IPv4` address]: Ipv4Addr
-///
-/// # Examples
-///
-/// ```
-/// use std::net::{Ipv4Addr, SocketAddrV4};
-///
-/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
-///
-/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket));
-/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
-/// assert_eq!(socket.port(), 8080);
-/// ```
-#[derive(Copy, Clone, Eq, PartialEq)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct SocketAddrV4 {
- ip: Ipv4Addr,
- port: u16,
-}
-
-/// An IPv6 socket address.
-///
-/// IPv6 socket addresses consist of an [`IPv6` address], a 16-bit port number, as well
-/// as fields containing the traffic class, the flow label, and a scope identifier
-/// (see [IETF RFC 2553, Section 3.3] for more details).
-///
-/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses.
-///
-/// The size of a `SocketAddrV6` struct may vary depending on the target operating
-/// system. Do not assume that this type has the same memory layout as the underlying
-/// system representation.
-///
-/// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
-/// [`IPv6` address]: Ipv6Addr
-///
-/// # Examples
-///
-/// ```
-/// use std::net::{Ipv6Addr, SocketAddrV6};
-///
-/// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
-///
-/// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket));
-/// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1));
-/// assert_eq!(socket.port(), 8080);
-/// ```
-#[derive(Copy, Clone, Eq, PartialEq)]
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct SocketAddrV6 {
- ip: Ipv6Addr,
- port: u16,
- flowinfo: u32,
- scope_id: u32,
-}
-
-impl SocketAddr {
- /// Creates a new socket address from an [IP address] and a port number.
- ///
- /// [IP address]: IpAddr
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
- ///
- /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
- /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
- /// assert_eq!(socket.port(), 8080);
- /// ```
- #[stable(feature = "ip_addr", since = "1.7.0")]
- #[must_use]
- #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
- pub const fn new(ip: IpAddr, port: u16) -> SocketAddr {
- match ip {
- IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)),
- IpAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)),
- }
- }
-
- /// Returns the IP address associated with this socket address.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
- ///
- /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
- /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
- /// ```
- #[must_use]
- #[stable(feature = "ip_addr", since = "1.7.0")]
- #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
- pub const fn ip(&self) -> IpAddr {
- match *self {
- SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()),
- SocketAddr::V6(ref a) => IpAddr::V6(*a.ip()),
- }
- }
-
- /// Changes the IP address associated with this socket address.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
- ///
- /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
- /// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
- /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
- /// ```
- #[stable(feature = "sockaddr_setters", since = "1.9.0")]
- pub fn set_ip(&mut self, new_ip: IpAddr) {
- // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away.
- match (self, new_ip) {
- (&mut SocketAddr::V4(ref mut a), IpAddr::V4(new_ip)) => a.set_ip(new_ip),
- (&mut SocketAddr::V6(ref mut a), IpAddr::V6(new_ip)) => a.set_ip(new_ip),
- (self_, new_ip) => *self_ = Self::new(new_ip, self_.port()),
- }
- }
-
- /// Returns the port number associated with this socket address.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
- ///
- /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
- /// assert_eq!(socket.port(), 8080);
- /// ```
- #[must_use]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
- pub const fn port(&self) -> u16 {
- match *self {
- SocketAddr::V4(ref a) => a.port(),
- SocketAddr::V6(ref a) => a.port(),
- }
- }
-
- /// Changes the port number associated with this socket address.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
- ///
- /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
- /// socket.set_port(1025);
- /// assert_eq!(socket.port(), 1025);
- /// ```
- #[stable(feature = "sockaddr_setters", since = "1.9.0")]
- pub fn set_port(&mut self, new_port: u16) {
- match *self {
- SocketAddr::V4(ref mut a) => a.set_port(new_port),
- SocketAddr::V6(ref mut a) => a.set_port(new_port),
- }
- }
-
- /// Returns [`true`] if the [IP address] in this `SocketAddr` is an
- /// [`IPv4` address], and [`false`] otherwise.
- ///
- /// [IP address]: IpAddr
- /// [`IPv4` address]: IpAddr::V4
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
- ///
- /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
- /// assert_eq!(socket.is_ipv4(), true);
- /// assert_eq!(socket.is_ipv6(), false);
- /// ```
- #[must_use]
- #[stable(feature = "sockaddr_checker", since = "1.16.0")]
- #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
- pub const fn is_ipv4(&self) -> bool {
- matches!(*self, SocketAddr::V4(_))
- }
-
- /// Returns [`true`] if the [IP address] in this `SocketAddr` is an
- /// [`IPv6` address], and [`false`] otherwise.
- ///
- /// [IP address]: IpAddr
- /// [`IPv6` address]: IpAddr::V6
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{IpAddr, Ipv6Addr, SocketAddr};
- ///
- /// let socket = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080);
- /// assert_eq!(socket.is_ipv4(), false);
- /// assert_eq!(socket.is_ipv6(), true);
- /// ```
- #[must_use]
- #[stable(feature = "sockaddr_checker", since = "1.16.0")]
- #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
- pub const fn is_ipv6(&self) -> bool {
- matches!(*self, SocketAddr::V6(_))
- }
-}
-
-impl SocketAddrV4 {
- /// Creates a new socket address from an [`IPv4` address] and a port number.
- ///
- /// [`IPv4` address]: Ipv4Addr
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{SocketAddrV4, Ipv4Addr};
- ///
- /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[must_use]
- #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
- pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
- SocketAddrV4 { ip, port }
- }
-
- /// Returns the IP address associated with this socket address.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{SocketAddrV4, Ipv4Addr};
- ///
- /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
- /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
- /// ```
- #[must_use]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
- pub const fn ip(&self) -> &Ipv4Addr {
- &self.ip
- }
-
- /// Changes the IP address associated with this socket address.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{SocketAddrV4, Ipv4Addr};
- ///
- /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
- /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1));
- /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1));
- /// ```
- #[stable(feature = "sockaddr_setters", since = "1.9.0")]
- pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
- self.ip = new_ip;
- }
-
- /// Returns the port number associated with this socket address.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{SocketAddrV4, Ipv4Addr};
- ///
- /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
- /// assert_eq!(socket.port(), 8080);
- /// ```
- #[must_use]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
- pub const fn port(&self) -> u16 {
- self.port
- }
-
- /// Changes the port number associated with this socket address.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{SocketAddrV4, Ipv4Addr};
- ///
- /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
- /// socket.set_port(4242);
- /// assert_eq!(socket.port(), 4242);
- /// ```
- #[stable(feature = "sockaddr_setters", since = "1.9.0")]
- pub fn set_port(&mut self, new_port: u16) {
- self.port = new_port;
- }
-}
-
-impl SocketAddrV6 {
- /// Creates a new socket address from an [`IPv6` address], a 16-bit port number,
- /// and the `flowinfo` and `scope_id` fields.
- ///
- /// For more information on the meaning and layout of the `flowinfo` and `scope_id`
- /// parameters, see [IETF RFC 2553, Section 3.3].
- ///
- /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
- /// [`IPv6` address]: Ipv6Addr
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{SocketAddrV6, Ipv6Addr};
- ///
- /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[must_use]
- #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
- pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 {
- SocketAddrV6 { ip, port, flowinfo, scope_id }
- }
-
- /// Returns the IP address associated with this socket address.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{SocketAddrV6, Ipv6Addr};
- ///
- /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
- /// assert_eq!(socket.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
- /// ```
- #[must_use]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
- pub const fn ip(&self) -> &Ipv6Addr {
- &self.ip
- }
-
- /// Changes the IP address associated with this socket address.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{SocketAddrV6, Ipv6Addr};
- ///
- /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
- /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
- /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
- /// ```
- #[stable(feature = "sockaddr_setters", since = "1.9.0")]
- pub fn set_ip(&mut self, new_ip: Ipv6Addr) {
- self.ip = new_ip;
- }
-
- /// Returns the port number associated with this socket address.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{SocketAddrV6, Ipv6Addr};
- ///
- /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
- /// assert_eq!(socket.port(), 8080);
- /// ```
- #[must_use]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
- pub const fn port(&self) -> u16 {
- self.port
- }
-
- /// Changes the port number associated with this socket address.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{SocketAddrV6, Ipv6Addr};
- ///
- /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
- /// socket.set_port(4242);
- /// assert_eq!(socket.port(), 4242);
- /// ```
- #[stable(feature = "sockaddr_setters", since = "1.9.0")]
- pub fn set_port(&mut self, new_port: u16) {
- self.port = new_port;
- }
-
- /// Returns the flow information associated with this address.
- ///
- /// This information corresponds to the `sin6_flowinfo` field in C's `netinet/in.h`,
- /// as specified in [IETF RFC 2553, Section 3.3].
- /// It combines information about the flow label and the traffic class as specified
- /// in [IETF RFC 2460], respectively [Section 6] and [Section 7].
- ///
- /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
- /// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460
- /// [Section 6]: https://tools.ietf.org/html/rfc2460#section-6
- /// [Section 7]: https://tools.ietf.org/html/rfc2460#section-7
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{SocketAddrV6, Ipv6Addr};
- ///
- /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
- /// assert_eq!(socket.flowinfo(), 10);
- /// ```
- #[must_use]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
- pub const fn flowinfo(&self) -> u32 {
- self.flowinfo
- }
-
- /// Changes the flow information associated with this socket address.
- ///
- /// See [`SocketAddrV6::flowinfo`]'s documentation for more details.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{SocketAddrV6, Ipv6Addr};
- ///
- /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
- /// socket.set_flowinfo(56);
- /// assert_eq!(socket.flowinfo(), 56);
- /// ```
- #[stable(feature = "sockaddr_setters", since = "1.9.0")]
- pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
- self.flowinfo = new_flowinfo;
- }
-
- /// Returns the scope ID associated with this address.
- ///
- /// This information corresponds to the `sin6_scope_id` field in C's `netinet/in.h`,
- /// as specified in [IETF RFC 2553, Section 3.3].
- ///
- /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{SocketAddrV6, Ipv6Addr};
- ///
- /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
- /// assert_eq!(socket.scope_id(), 78);
- /// ```
- #[must_use]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
- pub const fn scope_id(&self) -> u32 {
- self.scope_id
- }
-
- /// Changes the scope ID associated with this socket address.
- ///
- /// See [`SocketAddrV6::scope_id`]'s documentation for more details.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::{SocketAddrV6, Ipv6Addr};
- ///
- /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
- /// socket.set_scope_id(42);
- /// assert_eq!(socket.scope_id(), 42);
- /// ```
- #[stable(feature = "sockaddr_setters", since = "1.9.0")]
- pub fn set_scope_id(&mut self, new_scope_id: u32) {
- self.scope_id = new_scope_id;
- }
-}
+pub use core::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
impl FromInner<c::sockaddr_in> for SocketAddrV4 {
fn from_inner(addr: c::sockaddr_in) -> SocketAddrV4 {
- SocketAddrV4 { ip: Ipv4Addr::from_inner(addr.sin_addr), port: u16::from_be(addr.sin_port) }
+ SocketAddrV4::new(Ipv4Addr::from_inner(addr.sin_addr), u16::from_be(addr.sin_port))
}
}
impl FromInner<c::sockaddr_in6> for SocketAddrV6 {
fn from_inner(addr: c::sockaddr_in6) -> SocketAddrV6 {
- SocketAddrV6 {
- ip: Ipv6Addr::from_inner(addr.sin6_addr),
- port: u16::from_be(addr.sin6_port),
- flowinfo: addr.sin6_flowinfo,
- scope_id: addr.sin6_scope_id,
- }
+ SocketAddrV6::new(
+ Ipv6Addr::from_inner(addr.sin6_addr),
+ u16::from_be(addr.sin6_port),
+ addr.sin6_flowinfo,
+ addr.sin6_scope_id,
+ )
}
}
@@ -549,8 +37,8 @@ impl IntoInner<c::sockaddr_in> for SocketAddrV4 {
fn into_inner(self) -> c::sockaddr_in {
c::sockaddr_in {
sin_family: c::AF_INET as c::sa_family_t,
- sin_port: self.port.to_be(),
- sin_addr: self.ip.into_inner(),
+ sin_port: self.port().to_be(),
+ sin_addr: self.ip().into_inner(),
..unsafe { mem::zeroed() }
}
}
@@ -560,162 +48,15 @@ impl IntoInner<c::sockaddr_in6> for SocketAddrV6 {
fn into_inner(self) -> c::sockaddr_in6 {
c::sockaddr_in6 {
sin6_family: c::AF_INET6 as c::sa_family_t,
- sin6_port: self.port.to_be(),
- sin6_addr: self.ip.into_inner(),
- sin6_flowinfo: self.flowinfo,
- sin6_scope_id: self.scope_id,
+ sin6_port: self.port().to_be(),
+ sin6_addr: self.ip().into_inner(),
+ sin6_flowinfo: self.flowinfo(),
+ sin6_scope_id: self.scope_id(),
..unsafe { mem::zeroed() }
}
}
}
-#[stable(feature = "ip_from_ip", since = "1.16.0")]
-impl From<SocketAddrV4> for SocketAddr {
- /// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`].
- fn from(sock4: SocketAddrV4) -> SocketAddr {
- SocketAddr::V4(sock4)
- }
-}
-
-#[stable(feature = "ip_from_ip", since = "1.16.0")]
-impl From<SocketAddrV6> for SocketAddr {
- /// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`].
- fn from(sock6: SocketAddrV6) -> SocketAddr {
- SocketAddr::V6(sock6)
- }
-}
-
-#[stable(feature = "addr_from_into_ip", since = "1.17.0")]
-impl<I: Into<IpAddr>> From<(I, u16)> for SocketAddr {
- /// Converts a tuple struct (Into<[`IpAddr`]>, `u16`) into a [`SocketAddr`].
- ///
- /// This conversion creates a [`SocketAddr::V4`] for an [`IpAddr::V4`]
- /// and creates a [`SocketAddr::V6`] for an [`IpAddr::V6`].
- ///
- /// `u16` is treated as port of the newly created [`SocketAddr`].
- fn from(pieces: (I, u16)) -> SocketAddr {
- SocketAddr::new(pieces.0.into(), pieces.1)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for SocketAddr {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match *self {
- SocketAddr::V4(ref a) => a.fmt(f),
- SocketAddr::V6(ref a) => a.fmt(f),
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for SocketAddr {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(self, fmt)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for SocketAddrV4 {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- // If there are no alignment requirements, write the socket address directly to `f`.
- // Otherwise, write it to a local buffer and then use `f.pad`.
- if f.precision().is_none() && f.width().is_none() {
- write!(f, "{}:{}", self.ip(), self.port())
- } else {
- const LONGEST_IPV4_SOCKET_ADDR: &str = "255.255.255.255:65536";
-
- let mut buf = DisplayBuffer::<{ LONGEST_IPV4_SOCKET_ADDR.len() }>::new();
- // Buffer is long enough for the longest possible IPv4 socket address, so this should never fail.
- write!(buf, "{}:{}", self.ip(), self.port()).unwrap();
-
- f.pad(buf.as_str())
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for SocketAddrV4 {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(self, fmt)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for SocketAddrV6 {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- // If there are no alignment requirements, write the socket address directly to `f`.
- // Otherwise, write it to a local buffer and then use `f.pad`.
- if f.precision().is_none() && f.width().is_none() {
- match self.scope_id() {
- 0 => write!(f, "[{}]:{}", self.ip(), self.port()),
- scope_id => write!(f, "[{}%{}]:{}", self.ip(), scope_id, self.port()),
- }
- } else {
- const LONGEST_IPV6_SOCKET_ADDR: &str =
- "[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%4294967296]:65536";
-
- let mut buf = DisplayBuffer::<{ LONGEST_IPV6_SOCKET_ADDR.len() }>::new();
- match self.scope_id() {
- 0 => write!(buf, "[{}]:{}", self.ip(), self.port()),
- scope_id => write!(buf, "[{}%{}]:{}", self.ip(), scope_id, self.port()),
- }
- // Buffer is long enough for the longest possible IPv6 socket address, so this should never fail.
- .unwrap();
-
- f.pad(buf.as_str())
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for SocketAddrV6 {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(self, fmt)
- }
-}
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl PartialOrd for SocketAddrV4 {
- fn partial_cmp(&self, other: &SocketAddrV4) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl PartialOrd for SocketAddrV6 {
- fn partial_cmp(&self, other: &SocketAddrV6) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl Ord for SocketAddrV4 {
- fn cmp(&self, other: &SocketAddrV4) -> Ordering {
- self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
- }
-}
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl Ord for SocketAddrV6 {
- fn cmp(&self, other: &SocketAddrV6) -> Ordering {
- self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl hash::Hash for SocketAddrV4 {
- fn hash<H: hash::Hasher>(&self, s: &mut H) {
- (self.port, self.ip).hash(s)
- }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl hash::Hash for SocketAddrV6 {
- fn hash<H: hash::Hasher>(&self, s: &mut H) {
- (self.port, &self.ip, self.flowinfo, self.scope_id).hash(s)
- }
-}
-
/// A trait for objects which can be converted or resolved to one or more
/// [`SocketAddr`] values.
///
diff --git a/library/std/src/net/socket_addr/tests.rs b/library/std/src/net/socket_addr/tests.rs
index 15211f819..dfc6dabbe 100644
--- a/library/std/src/net/socket_addr/tests.rs
+++ b/library/std/src/net/socket_addr/tests.rs
@@ -64,11 +64,11 @@ fn ipv4_socket_addr_to_string() {
// Test padding.
assert_eq!(
- &format!("{:16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)),
+ format!("{:16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)),
"1.1.1.1:53 "
);
assert_eq!(
- &format!("{:>16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)),
+ format!("{:>16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)),
" 1.1.1.1:53"
);
}
@@ -111,11 +111,11 @@ fn ipv6_socket_addr_to_string() {
// Test padding.
assert_eq!(
- &format!("{:22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)),
+ format!("{:22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)),
"[1:2:3:4:5:6:7:8]:9 "
);
assert_eq!(
- &format!("{:>22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)),
+ format!("{:>22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)),
" [1:2:3:4:5:6:7:8]:9"
);
}
diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs
index 69b72a81c..ac09a8059 100644
--- a/library/std/src/net/tcp.rs
+++ b/library/std/src/net/tcp.rs
@@ -829,7 +829,7 @@ impl TcpListener {
/// }
///
/// fn main() -> std::io::Result<()> {
- /// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
+ /// let listener = TcpListener::bind("127.0.0.1:80")?;
///
/// for stream in listener.incoming() {
/// match stream {
diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs
index 8c0adcfb0..e019bc0b6 100644
--- a/library/std/src/net/tcp/tests.rs
+++ b/library/std/src/net/tcp/tests.rs
@@ -670,7 +670,10 @@ fn debug() {
// FIXME: re-enabled openbsd tests once their socket timeout code
// no longer has rounding errors.
// VxWorks ignores SO_SNDTIMEO.
-#[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)]
+#[cfg_attr(
+ any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks", target_os = "nto"),
+ ignore
+)]
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
#[test]
fn timeouts() {
diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs
index f82904ffb..892fe2ba8 100644
--- a/library/std/src/net/udp/tests.rs
+++ b/library/std/src/net/udp/tests.rs
@@ -180,7 +180,10 @@ fn debug() {
// FIXME: re-enabled openbsd/netbsd tests once their socket timeout code
// no longer has rounding errors.
// VxWorks ignores SO_SNDTIMEO.
-#[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)]
+#[cfg_attr(
+ any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks", target_os = "nto"),
+ ignore
+)]
#[test]
fn timeouts() {
let addr = next_test_ip4();
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index c41e093a7..99a4e0b51 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -9,7 +9,7 @@ use crate::fs;
use crate::io;
use crate::marker::PhantomData;
use crate::mem::forget;
-#[cfg(not(any(target_arch = "wasm32", target_env = "sgx")))]
+#[cfg(not(any(target_arch = "wasm32", target_env = "sgx", target_os = "hermit")))]
use crate::sys::cvt;
use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -89,7 +89,7 @@ impl OwnedFd {
impl BorrowedFd<'_> {
/// Creates a new `OwnedFd` instance that shares the same underlying file
/// description as the existing `BorrowedFd` instance.
- #[cfg(not(target_arch = "wasm32"))]
+ #[cfg(not(any(target_arch = "wasm32", target_os = "hermit")))]
#[stable(feature = "io_safety", since = "1.63.0")]
pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
// We want to atomically duplicate this file descriptor and set the
@@ -112,7 +112,7 @@ impl BorrowedFd<'_> {
/// Creates a new `OwnedFd` instance that shares the same underlying file
/// description as the existing `BorrowedFd` instance.
- #[cfg(target_arch = "wasm32")]
+ #[cfg(any(target_arch = "wasm32", target_os = "hermit"))]
#[stable(feature = "io_safety", since = "1.63.0")]
pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
Err(crate::io::const_io_error!(
@@ -174,7 +174,10 @@ impl Drop for OwnedFd {
// 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.
+ #[cfg(not(target_os = "hermit"))]
let _ = libc::close(self.fd);
+ #[cfg(target_os = "hermit")]
+ let _ = hermit_abi::close(self.fd);
}
}
}
@@ -396,6 +399,14 @@ impl<T: AsFd> AsFd for crate::sync::Arc<T> {
}
}
+#[stable(feature = "asfd_rc", since = "1.69.0")]
+impl<T: AsFd> AsFd for crate::rc::Rc<T> {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ (**self).as_fd()
+ }
+}
+
#[stable(feature = "asfd_ptrs", since = "1.64.0")]
impl<T: AsFd> AsFd for Box<T> {
#[inline]
diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs
index f92a05066..592e072ad 100644
--- a/library/std/src/os/fd/raw.rs
+++ b/library/std/src/os/fd/raw.rs
@@ -4,6 +4,9 @@
use crate::fs;
use crate::io;
+#[cfg(target_os = "hermit")]
+use crate::os::hermit::io::OwnedFd;
+#[cfg(not(target_os = "hermit"))]
use crate::os::raw;
#[cfg(all(doc, not(target_arch = "wasm32")))]
use crate::os::unix::io::AsFd;
@@ -12,11 +15,18 @@ use crate::os::unix::io::OwnedFd;
#[cfg(target_os = "wasi")]
use crate::os::wasi::io::OwnedFd;
use crate::sys_common::{AsInner, IntoInner};
+#[cfg(target_os = "hermit")]
+use hermit_abi as libc;
/// Raw file descriptors.
#[rustc_allowed_through_unstable_modules]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg(not(target_os = "hermit"))]
pub type RawFd = raw::c_int;
+#[rustc_allowed_through_unstable_modules]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg(target_os = "hermit")]
+pub type RawFd = i32;
/// A trait to extract the raw file descriptor from an underlying object.
///
@@ -244,6 +254,14 @@ impl<T: AsRawFd> AsRawFd for crate::sync::Arc<T> {
}
}
+#[stable(feature = "asfd_rc", since = "1.69.0")]
+impl<T: AsRawFd> AsRawFd for crate::rc::Rc<T> {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ (**self).as_raw_fd()
+ }
+}
+
#[stable(feature = "asrawfd_ptrs", since = "1.63.0")]
impl<T: AsRawFd> AsRawFd for Box<T> {
#[inline]
diff --git a/library/std/src/os/fuchsia/raw.rs b/library/std/src/os/fuchsia/raw.rs
index 060d6e86b..ea6b94f2f 100644
--- a/library/std/src/os/fuchsia/raw.rs
+++ b/library/std/src/os/fuchsia/raw.rs
@@ -24,12 +24,7 @@ pub type pthread_t = c_ulong;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
-#[cfg(any(
- target_arch = "x86",
- target_arch = "le32",
- target_arch = "powerpc",
- target_arch = "arm"
-))]
+#[cfg(any(target_arch = "x86", target_arch = "powerpc", target_arch = "arm"))]
mod arch {
use crate::os::raw::{c_long, c_short, c_uint};
diff --git a/library/std/src/os/hermit/io/mod.rs b/library/std/src/os/hermit/io/mod.rs
new file mode 100644
index 000000000..524dfae0d
--- /dev/null
+++ b/library/std/src/os/hermit/io/mod.rs
@@ -0,0 +1,13 @@
+#![stable(feature = "os_fd", since = "1.66.0")]
+
+mod net;
+#[path = "../../fd/owned.rs"]
+mod owned;
+#[path = "../../fd/raw.rs"]
+mod raw;
+
+// Export the types and traits for the public API.
+#[stable(feature = "os_fd", since = "1.66.0")]
+pub use owned::*;
+#[stable(feature = "os_fd", since = "1.66.0")]
+pub use raw::*;
diff --git a/library/std/src/os/hermit/io/net.rs b/library/std/src/os/hermit/io/net.rs
new file mode 100644
index 000000000..8f3802d78
--- /dev/null
+++ b/library/std/src/os/hermit/io/net.rs
@@ -0,0 +1,46 @@
+use crate::os::hermit::io::OwnedFd;
+use crate::os::hermit::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use crate::sys_common::{self, AsInner, FromInner, IntoInner};
+use crate::{net, sys};
+
+macro_rules! impl_as_raw_fd {
+ ($($t:ident)*) => {$(
+ #[stable(feature = "rust1", since = "1.0.0")]
+ impl AsRawFd for net::$t {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().socket().as_raw_fd()
+ }
+ }
+ )*};
+}
+impl_as_raw_fd! { TcpStream TcpListener UdpSocket }
+
+macro_rules! impl_from_raw_fd {
+ ($($t:ident)*) => {$(
+ #[stable(feature = "from_raw_os", since = "1.1.0")]
+ impl FromRawFd for net::$t {
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
+ unsafe {
+ let socket = sys::net::Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)));
+ net::$t::from_inner(sys_common::net::$t::from_inner(socket))
+ }
+ }
+ }
+ )*};
+}
+impl_from_raw_fd! { TcpStream TcpListener UdpSocket }
+
+macro_rules! impl_into_raw_fd {
+ ($($t:ident)*) => {$(
+ #[stable(feature = "into_raw_os", since = "1.4.0")]
+ impl IntoRawFd for net::$t {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_socket().into_inner().into_inner().into_raw_fd()
+ }
+ }
+ )*};
+}
+impl_into_raw_fd! { TcpStream TcpListener UdpSocket }
diff --git a/library/std/src/os/hermit/mod.rs b/library/std/src/os/hermit/mod.rs
index 4657b545a..89b1b8319 100644
--- a/library/std/src/os/hermit/mod.rs
+++ b/library/std/src/os/hermit/mod.rs
@@ -1,6 +1,11 @@
#![stable(feature = "rust1", since = "1.0.0")]
+#[allow(unused_extern_crates)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub extern crate hermit_abi as abi;
+
pub mod ffi;
+pub mod io;
/// A prelude for conveniently writing platform-specific code.
///
diff --git a/library/std/src/os/l4re/raw.rs b/library/std/src/os/l4re/raw.rs
index 699e8be33..b3f7439f8 100644
--- a/library/std/src/os/l4re/raw.rs
+++ b/library/std/src/os/l4re/raw.rs
@@ -26,7 +26,6 @@ pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
#[cfg(any(
target_arch = "x86",
- target_arch = "le32",
target_arch = "m68k",
target_arch = "powerpc",
target_arch = "sparc",
diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs
index c73791d14..f46028c3a 100644
--- a/library/std/src/os/linux/raw.rs
+++ b/library/std/src/os/linux/raw.rs
@@ -26,7 +26,6 @@ pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
#[cfg(any(
target_arch = "x86",
- target_arch = "le32",
target_arch = "m68k",
target_arch = "powerpc",
target_arch = "sparc",
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index 42773805c..b148d8a00 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -60,16 +60,6 @@ pub mod windows {}
all(target_vendor = "fortanix", target_env = "sgx")
)
)))]
-#[cfg(target_os = "hermit")]
-#[path = "hermit/mod.rs"]
-pub mod unix;
-#[cfg(not(all(
- doc,
- any(
- all(target_arch = "wasm32", not(target_os = "wasi")),
- all(target_vendor = "fortanix", target_env = "sgx")
- )
-)))]
#[cfg(all(not(target_os = "hermit"), any(unix, doc)))]
pub mod unix;
@@ -123,6 +113,8 @@ pub mod freebsd;
pub mod fuchsia;
#[cfg(target_os = "haiku")]
pub mod haiku;
+#[cfg(target_os = "hermit")]
+pub mod hermit;
#[cfg(target_os = "horizon")]
pub mod horizon;
#[cfg(target_os = "illumos")]
@@ -135,6 +127,8 @@ pub mod l4re;
pub mod macos;
#[cfg(target_os = "netbsd")]
pub mod netbsd;
+#[cfg(target_os = "nto")]
+pub mod nto;
#[cfg(target_os = "openbsd")]
pub mod openbsd;
#[cfg(target_os = "redox")]
diff --git a/library/std/src/os/net/mod.rs b/library/std/src/os/net/mod.rs
index 5ec267c41..b7046dd7c 100644
--- a/library/std/src/os/net/mod.rs
+++ b/library/std/src/os/net/mod.rs
@@ -1,4 +1,13 @@
//! OS-specific networking functionality.
+// See cfg macros in `library/std/src/os/mod.rs` for why these platforms must
+// be special-cased during rustdoc generation.
+#[cfg(not(all(
+ doc,
+ any(
+ all(target_arch = "wasm32", not(target_os = "wasi")),
+ all(target_vendor = "fortanix", target_env = "sgx")
+ )
+)))]
#[cfg(any(target_os = "linux", target_os = "android", doc))]
pub(super) mod linux_ext;
diff --git a/library/std/src/os/nto/fs.rs b/library/std/src/os/nto/fs.rs
new file mode 100644
index 000000000..8f915b08c
--- /dev/null
+++ b/library/std/src/os/nto/fs.rs
@@ -0,0 +1,92 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atim.tv_sec as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atim.tv_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtim.tv_sec as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtim.tv_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctim.tv_sec as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctim.tv_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/library/std/src/os/nto/mod.rs b/library/std/src/os/nto/mod.rs
new file mode 100644
index 000000000..3e591dace
--- /dev/null
+++ b/library/std/src/os/nto/mod.rs
@@ -0,0 +1,4 @@
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub(super) mod raw;
diff --git a/library/std/src/os/nto/raw.rs b/library/std/src/os/nto/raw.rs
new file mode 100644
index 000000000..90e9ad546
--- /dev/null
+++ b/library/std/src/os/nto/raw.rs
@@ -0,0 +1,40 @@
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::c_int;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = u32;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_int;
+
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, time_t};
+
+mod arch {
+ use crate::os::raw::c_long;
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = i64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = i32;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u32;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = i64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = c_long;
+}
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index 3fc6cc44c..a0e664acd 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -17,6 +17,10 @@ use crate::sealed::Sealed;
#[allow(unused_imports)]
use io::{Read, Write};
+// Tests for this module
+#[cfg(test)]
+mod tests;
+
/// Unix-specific extensions to [`fs::File`].
#[stable(feature = "file_offset", since = "1.15.0")]
pub trait FileExt {
@@ -54,6 +58,16 @@ pub trait FileExt {
#[stable(feature = "file_offset", since = "1.15.0")]
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
+ /// Like `read_at`, except that it reads into a slice of buffers.
+ ///
+ /// Data is copied to fill each buffer in order, with the final buffer
+ /// written to possibly being only partially filled. This method must behave
+ /// equivalently to a single call to read with concatenated buffers.
+ #[unstable(feature = "unix_file_vectored_at", issue = "89517")]
+ fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
+ io::default_read_vectored(|b| self.read_at(b, offset), bufs)
+ }
+
/// Reads the exact number of byte required to fill `buf` from the given offset.
///
/// The offset is relative to the start of the file and thus independent
@@ -155,6 +169,16 @@ pub trait FileExt {
#[stable(feature = "file_offset", since = "1.15.0")]
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
+ /// Like `write_at`, except that it writes from a slice of buffers.
+ ///
+ /// Data is copied from each buffer in order, with the final buffer read
+ /// from possibly being only partially consumed. This method must behave as
+ /// a call to `write_at` with the buffers concatenated would.
+ #[unstable(feature = "unix_file_vectored_at", issue = "89517")]
+ fn write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result<usize> {
+ io::default_write_vectored(|b| self.write_at(b, offset), bufs)
+ }
+
/// Attempts to write an entire buffer starting from a given offset.
///
/// The offset is relative to the start of the file and thus independent
@@ -218,9 +242,15 @@ impl FileExt for fs::File {
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
self.as_inner().read_at(buf, offset)
}
+ fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
+ self.as_inner().read_vectored_at(bufs, offset)
+ }
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
self.as_inner().write_at(buf, offset)
}
+ fn write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result<usize> {
+ self.as_inner().write_vectored_at(bufs, offset)
+ }
}
/// Unix-specific extensions to [`fs::Permissions`].
diff --git a/library/std/src/os/unix/fs/tests.rs b/library/std/src/os/unix/fs/tests.rs
new file mode 100644
index 000000000..67f607bd4
--- /dev/null
+++ b/library/std/src/os/unix/fs/tests.rs
@@ -0,0 +1,57 @@
+use super::*;
+
+#[test]
+fn read_vectored_at() {
+ let msg = b"preadv is working!";
+ let dir = crate::sys_common::io::test::tmpdir();
+
+ let filename = dir.join("preadv.txt");
+ {
+ let mut file = fs::File::create(&filename).unwrap();
+ file.write_all(msg).unwrap();
+ }
+ {
+ let file = fs::File::open(&filename).unwrap();
+ let mut buf0 = [0; 4];
+ let mut buf1 = [0; 3];
+
+ let mut iovec = [io::IoSliceMut::new(&mut buf0), io::IoSliceMut::new(&mut buf1)];
+
+ let n = file.read_vectored_at(&mut iovec, 4).unwrap();
+
+ assert!(n == 4 || n == 7);
+ assert_eq!(&buf0, b"dv i");
+
+ if n == 7 {
+ assert_eq!(&buf1, b"s w");
+ }
+ }
+}
+
+#[test]
+fn write_vectored_at() {
+ let msg = b"pwritev is not working!";
+ let dir = crate::sys_common::io::test::tmpdir();
+
+ let filename = dir.join("preadv.txt");
+ {
+ let mut file = fs::File::create(&filename).unwrap();
+ file.write_all(msg).unwrap();
+ }
+ let expected = {
+ let file = fs::File::options().write(true).open(&filename).unwrap();
+ let buf0 = b" ";
+ let buf1 = b"great ";
+
+ let iovec = [io::IoSlice::new(buf0), io::IoSlice::new(buf1)];
+
+ let n = file.write_vectored_at(&iovec, 11).unwrap();
+
+ assert!(n == 4 || n == 11);
+
+ if n == 4 { b"pwritev is working!" } else { b"pwritev is great !" }
+ };
+
+ let content = fs::read(&filename).unwrap();
+ assert_eq!(&content, expected);
+}
diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs
index f97fa0fb0..eb2d7ce11 100644
--- a/library/std/src/os/unix/mod.rs
+++ b/library/std/src/os/unix/mod.rs
@@ -65,6 +65,8 @@ mod platform {
pub use crate::os::macos::*;
#[cfg(target_os = "netbsd")]
pub use crate::os::netbsd::*;
+ #[cfg(target_os = "nto")]
+ pub use crate::os::nto::*;
#[cfg(target_os = "openbsd")]
pub use crate::os::openbsd::*;
#[cfg(target_os = "redox")]
@@ -95,7 +97,8 @@ pub mod thread;
target_os = "watchos",
target_os = "macos",
target_os = "netbsd",
- target_os = "openbsd"
+ target_os = "openbsd",
+ target_os = "nto",
))]
pub mod ucred;
diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs
index f758f88d0..272b4f5dc 100644
--- a/library/std/src/os/unix/net/datagram.rs
+++ b/library/std/src/os/unix/net/datagram.rs
@@ -19,7 +19,8 @@ use crate::{fmt, io};
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
- target_os = "haiku"
+ target_os = "haiku",
+ target_os = "nto",
))]
use libc::MSG_NOSIGNAL;
#[cfg(not(any(
@@ -29,7 +30,8 @@ use libc::MSG_NOSIGNAL;
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
- target_os = "haiku"
+ target_os = "haiku",
+ target_os = "nto",
)))]
const MSG_NOSIGNAL: libc::c_int = 0x0;
diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs
index 37fcfa844..f8c29a6d3 100644
--- a/library/std/src/os/unix/net/tests.rs
+++ b/library/std/src/os/unix/net/tests.rs
@@ -167,6 +167,7 @@ fn long_path() {
}
#[test]
+#[cfg(not(target_os = "nto"))]
fn timeouts() {
let dir = tmpdir();
let socket_path = dir.path().join("sock");
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
index 09b2bfe39..729c63d18 100644
--- a/library/std/src/os/unix/process.rs
+++ b/library/std/src/os/unix/process.rs
@@ -12,15 +12,23 @@ use crate::sealed::Sealed;
use crate::sys;
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
-#[cfg(not(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon")))]
-type UserId = u32;
-#[cfg(not(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon")))]
-type GroupId = u32;
-
-#[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))]
-type UserId = u16;
-#[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))]
-type GroupId = u16;
+use cfg_if::cfg_if;
+
+cfg_if! {
+ if #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))] {
+ type UserId = u16;
+ type GroupId = u16;
+ } else if #[cfg(target_os = "nto")] {
+ // Both IDs are signed, see `sys/target_nto.h` of the QNX Neutrino SDP.
+ // Only positive values should be used, see e.g.
+ // https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/s/setuid.html
+ type UserId = i32;
+ type GroupId = i32;
+ } else {
+ type UserId = u32;
+ type GroupId = u32;
+ }
+}
/// Unix-specific extensions to the [`process::Command`] builder.
///
diff --git a/library/std/src/os/unix/ucred.rs b/library/std/src/os/unix/ucred.rs
index ae4faf27b..95967eac2 100644
--- a/library/std/src/os/unix/ucred.rs
+++ b/library/std/src/os/unix/ucred.rs
@@ -79,7 +79,8 @@ pub mod impl_linux {
target_os = "dragonfly",
target_os = "freebsd",
target_os = "openbsd",
- target_os = "netbsd"
+ target_os = "netbsd",
+ target_os = "nto",
))]
pub mod impl_bsd {
use super::UCred;
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index b0db3112e..e59f32af7 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -95,13 +95,16 @@ impl Default for Hook {
static HOOK: RwLock<Hook> = RwLock::new(Hook::Default);
-/// Registers a custom panic hook, replacing any that was previously registered.
+/// Registers a custom panic hook, replacing the previously registered hook.
///
/// The panic hook is invoked when a thread panics, but before the panic runtime
/// is invoked. As such, the hook will run with both the aborting and unwinding
-/// runtimes. The default hook prints a message to standard error and generates
-/// a backtrace if requested, but this behavior can be customized with the
-/// `set_hook` and [`take_hook`] functions.
+/// runtimes.
+///
+/// The default hook, which is registered at startup, prints a message to standard error and
+/// generates a backtrace if requested. This behavior can be customized using the `set_hook` function.
+/// The current hook can be retrieved while reinstating the default hook with the [`take_hook`]
+/// function.
///
/// [`take_hook`]: ./fn.take_hook.html
///
@@ -143,13 +146,14 @@ pub fn set_hook(hook: Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>) {
drop(old);
}
-/// Unregisters the current panic hook, returning it.
+/// Unregisters the current panic hook and returns it, registering the default hook
+/// in its place.
///
/// *See also the function [`set_hook`].*
///
/// [`set_hook`]: ./fn.set_hook.html
///
-/// If no custom hook is registered, the default hook will be returned.
+/// If the default hook is registered it will be returned, but remain registered.
///
/// # Panics
///
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 4778114b4..cd6b393a2 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -2531,6 +2531,8 @@ impl Path {
/// Creates an owned [`PathBuf`] with `path` adjoined to `self`.
///
+ /// If `path` is absolute, it replaces the current path.
+ ///
/// See [`PathBuf::push`] for more details on what it means to adjoin a path.
///
/// # Examples
@@ -2539,6 +2541,7 @@ impl Path {
/// use std::path::{Path, PathBuf};
///
/// assert_eq!(Path::new("/etc").join("passwd"), PathBuf::from("/etc/passwd"));
+ /// assert_eq!(Path::new("/etc").join("/bin/sh"), PathBuf::from("/bin/sh"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
@@ -2685,6 +2688,7 @@ impl Path {
/// escapes the path please use [`Debug`] instead.
///
/// [`Display`]: fmt::Display
+ /// [`Debug`]: fmt::Debug
///
/// # Examples
///
diff --git a/library/std/src/personality/emcc.rs b/library/std/src/personality/emcc.rs
index f942bdf18..cb52ae89b 100644
--- a/library/std/src/personality/emcc.rs
+++ b/library/std/src/personality/emcc.rs
@@ -1,7 +1,7 @@
//! On Emscripten Rust panics are wrapped in C++ exceptions, so we just forward
//! to `__gxx_personality_v0` which is provided by Emscripten.
-use libc::c_int;
+use crate::ffi::c_int;
use unwind as uw;
// This is required by the compiler to exist (e.g., it's a lang item), but it's
diff --git a/library/std/src/personality/gcc.rs b/library/std/src/personality/gcc.rs
index 5fc1b91a1..41c0fe725 100644
--- a/library/std/src/personality/gcc.rs
+++ b/library/std/src/personality/gcc.rs
@@ -37,7 +37,8 @@
//! and the last personality routine transfers control to the catch block.
use super::dwarf::eh::{self, EHAction, EHContext};
-use libc::{c_int, uintptr_t};
+use crate::ffi::c_int;
+use libc::uintptr_t;
use unwind as uw;
// Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index d6e9da187..6f78811a1 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -587,8 +587,10 @@ mod prim_pointer {}
/// There are two syntactic forms for creating an array:
///
/// * A list with each element, i.e., `[x, y, z]`.
-/// * A repeat expression `[x; N]`, which produces an array with `N` copies of `x`.
-/// The type of `x` must be [`Copy`].
+/// * A repeat expression `[expr; N]` where `N` is how many times to repeat `expr` in the array. `expr` must either be:
+///
+/// * A value of a type implementing the [`Copy`] trait
+/// * A `const` value
///
/// Note that `[expr; 0]` is allowed, and produces an empty array.
/// This will still evaluate `expr`, however, and immediately drop the resulting value, so
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 62ce2cb33..1952e19e6 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1416,7 +1416,7 @@ impl From<fs::File> for Stdio {
/// use std::fs::File;
/// use std::process::Command;
///
- /// // With the `foo.txt` file containing `Hello, world!"
+ /// // With the `foo.txt` file containing "Hello, world!"
/// let file = File::open("foo.txt").unwrap();
///
/// let reverse = Command::new("rev")
diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs
index 4a1530530..7e85d6a06 100644
--- a/library/std/src/sync/lazy_lock.rs
+++ b/library/std/src/sync/lazy_lock.rs
@@ -1,8 +1,21 @@
-use crate::cell::Cell;
+use crate::cell::UnsafeCell;
use crate::fmt;
+use crate::mem::ManuallyDrop;
use crate::ops::Deref;
use crate::panic::{RefUnwindSafe, UnwindSafe};
-use crate::sync::OnceLock;
+use crate::sync::Once;
+
+use super::once::ExclusiveState;
+
+// We use the state of a Once as discriminant value. Upon creation, the state is
+// "incomplete" and `f` contains the initialization closure. In the first call to
+// `call_once`, `f` is taken and run. If it succeeds, `value` is set and the state
+// is changed to "complete". If it panics, the Once is poisoned, so none of the
+// two fields is initialized.
+union Data<T, F> {
+ value: ManuallyDrop<T>,
+ f: ManuallyDrop<F>,
+}
/// A value which is initialized on the first access.
///
@@ -43,16 +56,17 @@ use crate::sync::OnceLock;
/// ```
#[unstable(feature = "once_cell", issue = "74465")]
pub struct LazyLock<T, F = fn() -> T> {
- cell: OnceLock<T>,
- init: Cell<Option<F>>,
+ once: Once,
+ data: UnsafeCell<Data<T, F>>,
}
+
impl<T, F: FnOnce() -> T> LazyLock<T, F> {
/// Creates a new lazy value with the given initializing
/// function.
#[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub const fn new(f: F) -> LazyLock<T, F> {
- LazyLock { cell: OnceLock::new(), init: Cell::new(Some(f)) }
+ LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) }
}
/// Forces the evaluation of this lazy value and
@@ -74,10 +88,50 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
#[inline]
#[unstable(feature = "once_cell", issue = "74465")]
pub fn force(this: &LazyLock<T, F>) -> &T {
- this.cell.get_or_init(|| match this.init.take() {
- Some(f) => f(),
- None => panic!("Lazy instance has previously been poisoned"),
- })
+ this.once.call_once(|| {
+ // SAFETY: `call_once` only runs this closure once, ever.
+ let data = unsafe { &mut *this.data.get() };
+ let f = unsafe { ManuallyDrop::take(&mut data.f) };
+ let value = f();
+ data.value = ManuallyDrop::new(value);
+ });
+
+ // SAFETY:
+ // There are four possible scenarios:
+ // * the closure was called and initialized `value`.
+ // * the closure was called and panicked, so this point is never reached.
+ // * the closure was not called, but a previous call initialized `value`.
+ // * the closure was not called because the Once is poisoned, so this point
+ // is never reached.
+ // So `value` has definitely been initialized and will not be modified again.
+ unsafe { &*(*this.data.get()).value }
+ }
+}
+
+impl<T, F> LazyLock<T, F> {
+ /// Get the inner value if it has already been initialized.
+ fn get(&self) -> Option<&T> {
+ if self.once.is_completed() {
+ // SAFETY:
+ // The closure has been run successfully, so `value` has been initialized
+ // and will not be modified again.
+ Some(unsafe { &*(*self.data.get()).value })
+ } else {
+ None
+ }
+ }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T, F> Drop for LazyLock<T, F> {
+ fn drop(&mut self) {
+ match self.once.state() {
+ ExclusiveState::Incomplete => unsafe { ManuallyDrop::drop(&mut self.data.get_mut().f) },
+ ExclusiveState::Complete => unsafe {
+ ManuallyDrop::drop(&mut self.data.get_mut().value)
+ },
+ ExclusiveState::Poisoned => {}
+ }
}
}
@@ -103,23 +157,23 @@ impl<T: Default> Default for LazyLock<T> {
#[unstable(feature = "once_cell", issue = "74465")]
impl<T: fmt::Debug, F> fmt::Debug for LazyLock<T, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Lazy").field("cell", &self.cell).finish_non_exhaustive()
+ match self.get() {
+ Some(v) => f.debug_tuple("LazyLock").field(v).finish(),
+ None => f.write_str("LazyLock(Uninit)"),
+ }
}
}
// We never create a `&F` from a `&LazyLock<T, F>` so it is fine
// to not impl `Sync` for `F`
-// we do create a `&mut Option<F>` in `force`, but this is
-// properly synchronized, so it only happens once
-// so it also does not contribute to this impl.
#[unstable(feature = "once_cell", issue = "74465")]
-unsafe impl<T, F: Send> Sync for LazyLock<T, F> where OnceLock<T>: Sync {}
+unsafe impl<T: Sync + Send, F: Send> Sync for LazyLock<T, F> {}
// auto-derived `Send` impl is OK.
#[unstable(feature = "once_cell", issue = "74465")]
-impl<T, F: UnwindSafe> RefUnwindSafe for LazyLock<T, F> where OnceLock<T>: RefUnwindSafe {}
+impl<T: RefUnwindSafe + UnwindSafe, F: UnwindSafe> RefUnwindSafe for LazyLock<T, F> {}
#[unstable(feature = "once_cell", issue = "74465")]
-impl<T, F: UnwindSafe> UnwindSafe for LazyLock<T, F> where OnceLock<T>: UnwindSafe {}
+impl<T: UnwindSafe, F: UnwindSafe> UnwindSafe for LazyLock<T, F> {}
#[cfg(test)]
mod tests;
diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs
index ba20bab87..4edc95617 100644
--- a/library/std/src/sync/mod.rs
+++ b/library/std/src/sync/mod.rs
@@ -186,7 +186,7 @@ mod condvar;
mod lazy_lock;
mod mpmc;
mod mutex;
-mod once;
+pub(crate) mod once;
mod once_lock;
mod poison;
mod remutex;
diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs
index c1e3e48b0..c6bb09b04 100644
--- a/library/std/src/sync/mpmc/array.rs
+++ b/library/std/src/sync/mpmc/array.rs
@@ -319,19 +319,10 @@ impl<T> Channel<T> {
) -> Result<(), SendTimeoutError<T>> {
let token = &mut Token::default();
loop {
- // Try sending a message several times.
- let backoff = Backoff::new();
- loop {
- if self.start_send(token) {
- let res = unsafe { self.write(token, msg) };
- return res.map_err(SendTimeoutError::Disconnected);
- }
-
- if backoff.is_completed() {
- break;
- } else {
- backoff.spin_light();
- }
+ // Try sending a message.
+ if self.start_send(token) {
+ let res = unsafe { self.write(token, msg) };
+ return res.map_err(SendTimeoutError::Disconnected);
}
if let Some(d) = deadline {
@@ -379,6 +370,7 @@ impl<T> Channel<T> {
pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
let token = &mut Token::default();
loop {
+ // Try receiving a message.
if self.start_recv(token) {
let res = unsafe { self.read(token) };
return res.map_err(|_| RecvTimeoutError::Disconnected);
diff --git a/library/std/src/sync/mpmc/utils.rs b/library/std/src/sync/mpmc/utils.rs
index cfe42750d..d053d69e2 100644
--- a/library/std/src/sync/mpmc/utils.rs
+++ b/library/std/src/sync/mpmc/utils.rs
@@ -105,10 +105,8 @@ impl Backoff {
/// Backs off using lightweight spinning.
///
- /// This method should be used for:
- /// - Retrying an operation because another thread made progress. i.e. on CAS failure.
- /// - Waiting for an operation to complete by spinning optimistically for a few iterations
- /// before falling back to parking the thread (see `Backoff::is_completed`).
+ /// This method should be used for retrying an operation because another thread made
+ /// progress. i.e. on CAS failure.
#[inline]
pub fn spin_light(&self) {
let step = self.step.get().min(SPIN_LIMIT);
@@ -134,10 +132,4 @@ impl Backoff {
self.step.set(self.step.get() + 1);
}
-
- /// Returns `true` if quadratic backoff has completed and parking the thread is advised.
- #[inline]
- pub fn is_completed(&self) -> bool {
- self.step.get() > SPIN_LIMIT
- }
}
diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs
index 0f25417d6..1b17c3108 100644
--- a/library/std/src/sync/once.rs
+++ b/library/std/src/sync/once.rs
@@ -43,6 +43,12 @@ pub struct OnceState {
pub(crate) inner: sys::OnceState,
}
+pub(crate) enum ExclusiveState {
+ Incomplete,
+ Poisoned,
+ Complete,
+}
+
/// Initialization value for static [`Once`] values.
///
/// # Examples
@@ -248,6 +254,16 @@ impl Once {
pub fn is_completed(&self) -> bool {
self.inner.is_completed()
}
+
+ /// Returns the current state of the `Once` instance.
+ ///
+ /// Since this takes a mutable reference, no initialization can currently
+ /// be running, so the state must be either "incomplete", "poisoned" or
+ /// "complete".
+ #[inline]
+ pub(crate) fn state(&mut self) -> ExclusiveState {
+ self.inner.state()
+ }
}
#[stable(feature = "std_debug", since = "1.16.0")]
diff --git a/library/std/src/sys/common/alloc.rs b/library/std/src/sys/common/alloc.rs
index 3edbe7280..403a5e627 100644
--- a/library/std/src/sys/common/alloc.rs
+++ b/library/std/src/sys/common/alloc.rs
@@ -7,6 +7,7 @@ use crate::ptr;
#[cfg(any(
target_arch = "x86",
target_arch = "arm",
+ target_arch = "m68k",
target_arch = "mips",
target_arch = "powerpc",
target_arch = "powerpc64",
diff --git a/library/std/src/sys/hermit/args.rs b/library/std/src/sys/hermit/args.rs
index afcae6c90..220a76e4b 100644
--- a/library/std/src/sys/hermit/args.rs
+++ b/library/std/src/sys/hermit/args.rs
@@ -1,6 +1,6 @@
use crate::ffi::{c_char, CStr, OsString};
use crate::fmt;
-use crate::os::unix::ffi::OsStringExt;
+use crate::os::hermit::ffi::OsStringExt;
use crate::ptr;
use crate::sync::atomic::{
AtomicIsize, AtomicPtr,
diff --git a/library/std/src/sys/hermit/fd.rs b/library/std/src/sys/hermit/fd.rs
index c400f5f2c..3a2cdd301 100644
--- a/library/std/src/sys/hermit/fd.rs
+++ b/library/std/src/sys/hermit/fd.rs
@@ -1,36 +1,23 @@
#![unstable(reason = "not public", issue = "none", feature = "fd")]
use crate::io::{self, Read};
-use crate::mem;
+use crate::os::hermit::io::{FromRawFd, OwnedFd, RawFd};
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};
+
+use crate::os::hermit::io::*;
#[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 +26,8 @@ impl FileDesc {
}
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 +56,45 @@ impl<'a> Read for &'a FileDesc {
}
}
-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()
+ }
+}
+
+impl IntoRawFd for FileDesc {
+ fn into_raw_fd(self) -> RawFd {
+ self.fd.into_raw_fd()
}
}
diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs
index 6fb92c037..c966f2177 100644
--- a/library/std/src/sys/hermit/fs.rs
+++ b/library/std/src/sys/hermit/fs.rs
@@ -3,14 +3,17 @@ use crate::fmt;
use crate::hash::{Hash, Hasher};
use crate::io::{self, Error, ErrorKind};
use crate::io::{BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
+use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
use crate::path::{Path, PathBuf};
use crate::sys::common::small_c_string::run_path_with_cstr;
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::abi::{
+ self, O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY,
+};
use crate::sys::hermit::fd::FileDesc;
use crate::sys::time::SystemTime;
use crate::sys::unsupported;
+use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
pub use crate::sys_common::fs::{copy, try_exists};
//pub use crate::sys_common::fs::remove_dir_all;
@@ -283,7 +286,7 @@ impl 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> {
@@ -363,6 +366,54 @@ impl DirBuilder {
}
}
+impl AsInner<FileDesc> for File {
+ fn as_inner(&self) -> &FileDesc {
+ &self.0
+ }
+}
+
+impl AsInnerMut<FileDesc> for File {
+ fn as_inner_mut(&mut self) -> &mut FileDesc {
+ &mut self.0
+ }
+}
+
+impl IntoInner<FileDesc> for File {
+ fn into_inner(self) -> FileDesc {
+ self.0
+ }
+}
+
+impl FromInner<FileDesc> for File {
+ fn from_inner(file_desc: FileDesc) -> Self {
+ Self(file_desc)
+ }
+}
+
+impl AsFd for File {
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.0.as_fd()
+ }
+}
+
+impl AsRawFd for File {
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.as_raw_fd()
+ }
+}
+
+impl IntoRawFd for File {
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_raw_fd()
+ }
+}
+
+impl FromRawFd for File {
+ unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+ Self(FromRawFd::from_raw_fd(raw_fd))
+ }
+}
+
pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
unsupported()
}
diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs
index 6811fadb0..d34a4cfed 100644
--- a/library/std/src/sys/hermit/mod.rs
+++ b/library/std/src/sys/hermit/mod.rs
@@ -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;
@@ -57,9 +57,7 @@ pub mod locks {
}
use crate::io::ErrorKind;
-
-#[allow(unused_extern_crates)]
-pub extern crate hermit_abi as abi;
+use crate::os::hermit::abi;
pub fn unsupported<T>() -> crate::io::Result<T> {
Err(unsupported_err())
@@ -72,11 +70,6 @@ pub fn unsupported_err() -> crate::io::Error {
)
}
-#[no_mangle]
-pub extern "C" fn floor(x: f64) -> f64 {
- unsafe { intrinsics::floorf64(x) }
-}
-
pub fn abort_internal() -> ! {
unsafe {
abi::abort();
@@ -131,25 +124,72 @@ pub unsafe extern "C" fn runtime_entry(
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,
+ }
+ }
}
diff --git a/library/std/src/sys/hermit/net.rs b/library/std/src/sys/hermit/net.rs
index 8a13879d8..5fb6281aa 100644
--- a/library/std/src/sys/hermit/net.rs
+++ b/library/std/src/sys/hermit/net.rs
@@ -1,490 +1,353 @@
-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::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd};
+use crate::sys::hermit::fd::FileDesc;
+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;
-/// 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
- }
-}
+use core::ffi::c_int;
-impl Drop for Socket {
- fn drop(&mut self) {
- let _ = abi::tcpstream::close(self.0);
- }
-}
+#[allow(unused_extern_crates)]
+pub extern crate hermit_abi as netc;
-// 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>);
-
-impl TcpStream {
- pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
- let addr = addr?;
-
- 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 use crate::sys::{cvt, cvt_r};
- 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 type wrlen_t = usize;
- 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 cvt_gai(err: i32) -> io::Result<()> {
+ if err == 0 {
+ return Ok(());
}
- 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"))
- }
+ let detail = "";
- 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")
- })?;
+ Err(io::Error::new(
+ io::ErrorKind::Uncategorized,
+ &format!("failed to lookup address information: {detail}")[..],
+ ))
+}
- Ok(duration.map(|d| Duration::from_millis(d)))
+/// Checks whether the HermitCore's socket interface has been started already, and
+/// if not, starts it.
+pub fn init() {
+ if unsafe { netc::network_init() } < 0 {
+ panic!("Unable to initialize network interface");
}
+}
- 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")
- })?;
+#[derive(Debug)]
+pub struct Socket(FileDesc);
- Ok(duration.map(|d| Duration::from_millis(d)))
+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)
}
- 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"))
+ 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) }))
}
- pub fn read(&self, buffer: &mut [u8]) -> io::Result<usize> {
- self.read_vectored(&mut [IoSliceMut::new(buffer)])
+ pub fn new_pair(_fam: i32, _ty: i32) -> io::Result<(Socket, Socket)> {
+ unimplemented!()
}
- 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")
- })?;
+ 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)?;
- if ret != 0 {
- size += ret;
- }
+ 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),
}
- Ok(size)
- }
-
- #[inline]
- pub fn is_read_vectored(&self) -> bool {
- true
- }
-
- pub fn write(&self, buffer: &[u8]) -> io::Result<usize> {
- self.write_vectored(&[IoSlice::new(buffer)])
- }
+ let mut pollfd = netc::pollfd { fd: self.as_raw_fd(), events: netc::POLLOUT, revents: 0 };
- pub fn write_vectored(&self, ioslice: &[IoSlice<'_>]) -> io::Result<usize> {
- let mut size: usize = 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")
- })?;
+ if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
+ return Err(io::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout",
+ ));
}
- Ok(size)
- }
-
- #[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"))?;
+ let start = Instant::now();
- 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"));
+ loop {
+ let elapsed = start.elapsed();
+ if elapsed >= timeout {
+ return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out"));
}
- };
-
- Ok(saddr)
- }
-
- pub fn socket_addr(&self) -> io::Result<SocketAddr> {
- unsupported()
- }
-
- 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"))
- }
-
- pub fn duplicate(&self) -> io::Result<TcpStream> {
- Ok(self.clone())
- }
-
- pub fn set_linger(&self, _linger: Option<Duration>) -> io::Result<()> {
- unsupported()
- }
-
- pub fn linger(&self) -> io::Result<Option<Duration>> {
- unsupported()
- }
-
- 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 nodelay(&self) -> io::Result<bool> {
- abi::tcpstream::nodelay(*self.0.as_inner())
- .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "nodelay failed"))
- }
-
- 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")
- })
- }
-}
-
-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"));
+ 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;
}
- };
-
- 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()
+ 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 only_v6(&self) -> io::Result<bool> {
- unsupported()
+ 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 take_error(&self) -> io::Result<Option<io::Error>> {
- unsupported()
+ 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_nonblocking(&self, _: bool) -> io::Result<()> {
- unsupported()
+ 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)
}
-}
-impl fmt::Debug for TcpListener {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- Ok(())
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.recv_with_flags(buf, 0)
}
-}
-
-pub struct UdpSocket(abi::Handle);
-impl UdpSocket {
- pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
- unsupported()
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.recv_with_flags(buf, netc::MSG_PEEK)
}
- pub fn peer_addr(&self) -> io::Result<SocketAddr> {
- unsupported()
- }
+ pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+ let mut size: isize = 0;
- pub fn socket_addr(&self) -> io::Result<SocketAddr> {
- unsupported()
- }
+ for i in bufs.iter_mut() {
+ let ret: isize =
+ cvt(unsafe { netc::read(self.0.as_raw_fd(), i.as_mut_ptr(), i.len()) })?;
- pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
- unsupported()
- }
+ if ret != 0 {
+ size += ret;
+ }
+ }
- pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
- unsupported()
+ Ok(size.try_into().unwrap())
}
- pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
- unsupported()
+ #[inline]
+ pub fn is_read_vectored(&self) -> bool {
+ true
}
- pub fn duplicate(&self) -> io::Result<UdpSocket> {
- unsupported()
- }
+ 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;
- pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
- unsupported()
+ 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 set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
- unsupported()
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_with_flags(buf, 0)
}
- pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
- unsupported()
+ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_with_flags(buf, netc::MSG_PEEK)
}
- pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
- unsupported()
+ 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 set_broadcast(&self, _: bool) -> io::Result<()> {
- unsupported()
- }
+ pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+ let mut size: isize = 0;
- pub fn broadcast(&self) -> io::Result<bool> {
- unsupported()
- }
+ for i in bufs.iter() {
+ size += cvt(unsafe { netc::write(self.0.as_raw_fd(), i.as_ptr(), i.len()) })?;
+ }
- pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
- unsupported()
+ Ok(size.try_into().unwrap())
}
- pub fn multicast_loop_v4(&self) -> io::Result<bool> {
- unsupported()
+ pub fn is_write_vectored(&self) -> bool {
+ true
}
- pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
- unsupported()
- }
+ 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 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 },
+ };
- pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
- unsupported()
+ setsockopt(self, netc::SOL_SOCKET, kind, timeout)
}
- pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
- 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 multicast_loop_v6(&self) -> io::Result<bool> {
- unsupported()
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ 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 join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
- unsupported()
- }
+ 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 join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
- unsupported()
+ setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger)
}
- pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
- unsupported()
- }
+ pub fn linger(&self) -> io::Result<Option<Duration>> {
+ let val: netc::linger = getsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER)?;
- pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
- unsupported()
+ Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64)))
}
- pub fn set_ttl(&self, _: u32) -> io::Result<()> {
- unsupported()
+ 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 ttl(&self) -> io::Result<u32> {
- unsupported()
+ pub fn nodelay(&self) -> io::Result<bool> {
+ let raw: i32 = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?;
+ Ok(raw != 0)
+ }
+
+ 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,
+ )
+ })
+ .map(drop)
}
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()
+ unimplemented!()
}
- pub fn send(&self, _: &[u8]) -> io::Result<usize> {
- unsupported()
- }
-
- pub fn connect(&self, _: io::Result<&SocketAddr>) -> 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 UdpSocket {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- Ok(())
+impl AsInner<FileDesc> for Socket {
+ fn as_inner(&self) -> &FileDesc {
+ &self.0
}
}
-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 {}
-}
diff --git a/library/std/src/sys/hermit/os.rs b/library/std/src/sys/hermit/os.rs
index 8f927df85..e53dbae61 100644
--- a/library/std/src/sys/hermit/os.rs
+++ b/library/std/src/sys/hermit/os.rs
@@ -4,7 +4,7 @@ use crate::ffi::{CStr, OsStr, OsString};
use crate::fmt;
use crate::io;
use crate::marker::PhantomData;
-use crate::os::unix::ffi::OsStringExt;
+use crate::os::hermit::ffi::OsStringExt;
use crate::path::{self, PathBuf};
use crate::str;
use crate::sync::Mutex;
diff --git a/library/std/src/sys/hermit/thread.rs b/library/std/src/sys/hermit/thread.rs
index 8f65544a9..2507f7069 100644
--- a/library/std/src/sys/hermit/thread.rs
+++ b/library/std/src/sys/hermit/thread.rs
@@ -27,10 +27,10 @@ impl Thread {
p: Box<dyn FnOnce()>,
core_id: isize,
) -> io::Result<Thread> {
- let p = Box::into_raw(box p);
+ let p = Box::into_raw(Box::new(p));
let tid = abi::spawn2(
thread_start,
- p as usize,
+ p.expose_addr(),
abi::Priority::into(abi::NORMAL_PRIO),
stack,
core_id,
diff --git a/library/std/src/sys/hermit/thread_local_dtor.rs b/library/std/src/sys/hermit/thread_local_dtor.rs
index 9b683fce1..613266b95 100644
--- a/library/std/src/sys/hermit/thread_local_dtor.rs
+++ b/library/std/src/sys/hermit/thread_local_dtor.rs
@@ -5,32 +5,23 @@
// The this solution works like the implementation of macOS and
// doesn't additional OS support
-use crate::cell::Cell;
-use crate::ptr;
+use crate::mem;
#[thread_local]
-static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut());
-
-type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
+static mut DTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
- if DTORS.get().is_null() {
- let v: Box<List> = box Vec::new();
- DTORS.set(Box::into_raw(v));
- }
-
- let list: &mut List = &mut *DTORS.get();
+ let list = &mut DTORS;
list.push((t, dtor));
}
// every thread call this function to run through all possible destructors
pub unsafe fn run_dtors() {
- let mut ptr = DTORS.replace(ptr::null_mut());
- while !ptr.is_null() {
- let list = Box::from_raw(ptr);
- for (ptr, dtor) in list.into_iter() {
+ let mut list = mem::take(&mut DTORS);
+ while !list.is_empty() {
+ for (ptr, dtor) in list {
dtor(ptr);
}
- ptr = DTORS.replace(ptr::null_mut());
+ list = mem::take(&mut DTORS);
}
}
diff --git a/library/std/src/sys/hermit/time.rs b/library/std/src/sys/hermit/time.rs
index c17e6c8af..32ddc4346 100644
--- a/library/std/src/sys/hermit/time.rs
+++ b/library/std/src/sys/hermit/time.rs
@@ -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 @@ impl Hash for Timespec {
}
#[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)
}
}
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-pub struct SystemTime {
- t: Timespec,
+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")
+ }
}
-pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
+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(Timespec);
+
+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)?))
}
}
diff --git a/library/std/src/sys/itron/thread.rs b/library/std/src/sys/itron/thread.rs
index 19350b83f..ae0f71853 100644
--- a/library/std/src/sys/itron/thread.rs
+++ b/library/std/src/sys/itron/thread.rs
@@ -247,7 +247,7 @@ impl Thread {
// [FINISHED → JOINED]
// To synchronize with the child task's memory accesses to
// `inner` up to the point of the assignment of `FINISHED`,
- // `Ordering::Acquire` must be used for the above `swap` call`.
+ // `Ordering::Acquire` must be used for the above `swap` call.
}
_ => unsafe { hint::unreachable_unchecked() },
}
diff --git a/library/std/src/sys/itron/thread_parking.rs b/library/std/src/sys/itron/thread_parking.rs
new file mode 100644
index 000000000..fe9934439
--- /dev/null
+++ b/library/std/src/sys/itron/thread_parking.rs
@@ -0,0 +1,37 @@
+use super::abi;
+use super::error::expect_success_aborting;
+use super::time::with_tmos;
+use crate::time::Duration;
+
+pub type ThreadId = abi::ID;
+
+pub use super::task::current_task_id_aborting as current;
+
+pub fn park(_hint: usize) {
+ match unsafe { abi::slp_tsk() } {
+ abi::E_OK | abi::E_RLWAI => {}
+ err => {
+ expect_success_aborting(err, &"slp_tsk");
+ }
+ }
+}
+
+pub fn park_timeout(dur: Duration, _hint: usize) {
+ match with_tmos(dur, |tmo| unsafe { abi::tslp_tsk(tmo) }) {
+ abi::E_OK | abi::E_RLWAI | abi::E_TMOUT => {}
+ err => {
+ expect_success_aborting(err, &"tslp_tsk");
+ }
+ }
+}
+
+pub fn unpark(id: ThreadId, _hint: usize) {
+ match unsafe { abi::wup_tsk(id) } {
+ // It is allowed to try to wake up a destroyed or unrelated task, so we ignore all
+ // errors that could result from that situation.
+ abi::E_OK | abi::E_NOEXS | abi::E_OBJ | abi::E_QOVR => {}
+ err => {
+ expect_success_aborting(err, &"wup_tsk");
+ }
+ }
+}
diff --git a/library/std/src/sys/itron/wait_flag.rs b/library/std/src/sys/itron/wait_flag.rs
deleted file mode 100644
index e432edd20..000000000
--- a/library/std/src/sys/itron/wait_flag.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-use crate::mem::MaybeUninit;
-use crate::time::Duration;
-
-use super::{
- abi,
- error::{expect_success, fail},
- time::with_tmos,
-};
-
-const CLEAR: abi::FLGPTN = 0;
-const RAISED: abi::FLGPTN = 1;
-
-/// A thread parking primitive that is not susceptible to race conditions,
-/// but provides no atomic ordering guarantees and allows only one `raise` per wait.
-pub struct WaitFlag {
- flag: abi::ID,
-}
-
-impl WaitFlag {
- /// Creates a new wait flag.
- pub fn new() -> WaitFlag {
- let flag = expect_success(
- unsafe {
- abi::acre_flg(&abi::T_CFLG {
- flgatr: abi::TA_FIFO | abi::TA_WSGL | abi::TA_CLR,
- iflgptn: CLEAR,
- })
- },
- &"acre_flg",
- );
-
- WaitFlag { flag }
- }
-
- /// Wait for the wait flag to be raised.
- pub fn wait(&self) {
- let mut token = MaybeUninit::uninit();
- expect_success(
- unsafe { abi::wai_flg(self.flag, RAISED, abi::TWF_ORW, token.as_mut_ptr()) },
- &"wai_flg",
- );
- }
-
- /// Wait for the wait flag to be raised or the timeout to occur.
- ///
- /// Returns whether the flag was raised (`true`) or the operation timed out (`false`).
- pub fn wait_timeout(&self, dur: Duration) -> bool {
- let mut token = MaybeUninit::uninit();
- let res = with_tmos(dur, |tmout| unsafe {
- abi::twai_flg(self.flag, RAISED, abi::TWF_ORW, token.as_mut_ptr(), tmout)
- });
-
- match res {
- abi::E_OK => true,
- abi::E_TMOUT => false,
- error => fail(error, &"twai_flg"),
- }
- }
-
- /// Raise the wait flag.
- ///
- /// Calls to this function should be balanced with the number of successful waits.
- pub fn raise(&self) {
- expect_success(unsafe { abi::set_flg(self.flag, RAISED) }, &"set_flg");
- }
-}
-
-impl Drop for WaitFlag {
- fn drop(&mut self) {
- expect_success(unsafe { abi::del_flg(self.flag) }, &"del_flg");
- }
-}
diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs
index 5867979a2..923d27fd9 100644
--- a/library/std/src/sys/solid/mod.rs
+++ b/library/std/src/sys/solid/mod.rs
@@ -13,9 +13,9 @@ mod itron {
pub(super) mod spin;
pub(super) mod task;
pub mod thread;
+ pub mod thread_parking;
pub(super) mod time;
use super::unsupported;
- pub mod wait_flag;
}
pub mod alloc;
@@ -43,8 +43,8 @@ pub use self::itron::thread;
pub mod memchr;
pub mod thread_local_dtor;
pub mod thread_local_key;
+pub use self::itron::thread_parking;
pub mod time;
-pub use self::itron::wait_flag;
mod rwlock;
diff --git a/library/std/src/sys/solid/thread_local_dtor.rs b/library/std/src/sys/solid/thread_local_dtor.rs
index 973564570..bad14bb37 100644
--- a/library/std/src/sys/solid/thread_local_dtor.rs
+++ b/library/std/src/sys/solid/thread_local_dtor.rs
@@ -5,43 +5,35 @@
use super::{abi, itron::task};
use crate::cell::Cell;
-use crate::ptr;
+use crate::mem;
#[thread_local]
-static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut());
+static REGISTERED: Cell<bool> = Cell::new(false);
-type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
+#[thread_local]
+static mut DTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
- if DTORS.get().is_null() {
+ if !REGISTERED.get() {
let tid = task::current_task_id_aborting();
- let v: Box<List> = box Vec::new();
- DTORS.set(Box::into_raw(v));
-
// Register `tls_dtor` to make sure the TLS destructors are called
// for tasks created by other means than `std::thread`
unsafe { abi::SOLID_TLS_AddDestructor(tid as i32, tls_dtor) };
+ REGISTERED.set(true);
}
- let list: &mut List = unsafe { &mut *DTORS.get() };
+ let list = unsafe { &mut DTORS };
list.push((t, dtor));
}
pub unsafe fn run_dtors() {
- let ptr = DTORS.get();
- if !ptr.is_null() {
- // Swap the destructor list, call all registered destructors,
- // and repeat this until the list becomes permanently empty.
- while let Some(list) = Some(crate::mem::replace(unsafe { &mut *ptr }, Vec::new()))
- .filter(|list| !list.is_empty())
- {
- for (ptr, dtor) in list.into_iter() {
- unsafe { dtor(ptr) };
- }
+ let mut list = mem::take(unsafe { &mut DTORS });
+ while !list.is_empty() {
+ for (ptr, dtor) in list {
+ unsafe { dtor(ptr) };
}
- // Drop the destructor list
- unsafe { Box::from_raw(DTORS.replace(ptr::null_mut())) };
+ list = mem::take(unsafe { &mut DTORS });
}
}
diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs
index a342f0f5e..3d79058b3 100644
--- a/library/std/src/sys/unix/args.rs
+++ b/library/std/src/sys/unix/args.rs
@@ -69,7 +69,8 @@ impl DoubleEndedIterator for Args {
target_os = "fuchsia",
target_os = "redox",
target_os = "vxworks",
- target_os = "horizon"
+ target_os = "horizon",
+ target_os = "nto",
))]
mod imp {
use super::Args;
@@ -141,12 +142,28 @@ mod imp {
// list.
let argv = ARGV.load(Ordering::Relaxed);
let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) };
- (0..argc)
- .map(|i| {
- let cstr = CStr::from_ptr(*argv.offset(i) as *const libc::c_char);
- OsStringExt::from_vec(cstr.to_bytes().to_vec())
- })
- .collect()
+ let mut args = Vec::with_capacity(argc as usize);
+ for i in 0..argc {
+ let ptr = *argv.offset(i) as *const libc::c_char;
+
+ // Some C commandline parsers (e.g. GLib and Qt) are replacing already
+ // handled arguments in `argv` with `NULL` and move them to the end. That
+ // means that `argc` might be bigger than the actual number of non-`NULL`
+ // pointers in `argv` at this point.
+ //
+ // To handle this we simply stop iterating at the first `NULL` argument.
+ //
+ // `argv` is also guaranteed to be `NULL`-terminated so any non-`NULL` arguments
+ // after the first `NULL` can safely be ignored.
+ if ptr.is_null() {
+ break;
+ }
+
+ let cstr = CStr::from_ptr(ptr);
+ args.push(OsStringExt::from_vec(cstr.to_bytes().to_vec()));
+ }
+
+ args
}
}
}
diff --git a/library/std/src/sys/unix/env.rs b/library/std/src/sys/unix/env.rs
index c9ba661c8..1a9276f11 100644
--- a/library/std/src/sys/unix/env.rs
+++ b/library/std/src/sys/unix/env.rs
@@ -185,6 +185,17 @@ pub mod os {
pub const EXE_EXTENSION: &str = "";
}
+#[cfg(target_os = "nto")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "nto";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
#[cfg(target_os = "redox")]
pub mod os {
pub const FAMILY: &str = "unix";
diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs
index dbaa3c33e..9874af4d3 100644
--- a/library/std/src/sys/unix/fd.rs
+++ b/library/std/src/sys/unix/fd.rs
@@ -53,7 +53,12 @@ const fn max_iov() -> usize {
libc::IOV_MAX as usize
}
-#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
+#[cfg(any(
+ target_os = "android",
+ target_os = "emscripten",
+ target_os = "linux",
+ target_os = "nto",
+))]
const fn max_iov() -> usize {
libc::UIO_MAXIOV as usize
}
@@ -67,6 +72,7 @@ const fn max_iov() -> usize {
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
+ target_os = "nto",
target_os = "openbsd",
target_os = "horizon",
target_os = "watchos",
@@ -92,7 +98,7 @@ impl FileDesc {
let ret = cvt(unsafe {
libc::readv(
self.as_raw_fd(),
- bufs.as_ptr() as *const libc::iovec,
+ bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec,
cmp::min(bufs.len(), max_iov()) as libc::c_int,
)
})?;
@@ -101,7 +107,7 @@ impl FileDesc {
#[cfg(any(target_os = "espidf", target_os = "horizon"))]
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- return crate::io::default_read_vectored(|b| self.read(b), bufs);
+ io::default_read_vectored(|b| self.read(b), bufs)
}
#[inline]
@@ -147,6 +153,95 @@ impl FileDesc {
Ok(())
}
+ #[cfg(any(
+ target_os = "emscripten",
+ target_os = "freebsd",
+ target_os = "fuchsia",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "netbsd",
+ ))]
+ pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
+ let ret = cvt(unsafe {
+ libc::preadv(
+ self.as_raw_fd(),
+ bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec,
+ cmp::min(bufs.len(), max_iov()) as libc::c_int,
+ offset as _,
+ )
+ })?;
+ Ok(ret as usize)
+ }
+
+ #[cfg(not(any(
+ target_os = "android",
+ target_os = "emscripten",
+ target_os = "freebsd",
+ target_os = "fuchsia",
+ target_os = "illumos",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ )))]
+ pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
+ io::default_read_vectored(|b| self.read_at(b, offset), bufs)
+ }
+
+ // We support some old Android versions that do not have `preadv` in libc,
+ // so we use weak linkage and fallback to a direct syscall if not available.
+ //
+ // On 32-bit targets, we don't want to deal with weird ABI issues around
+ // passing 64-bits parameters to syscalls, so we fallback to the default
+ // implementation if `preadv` is not available.
+ #[cfg(all(target_os = "android", target_pointer_width = "64"))]
+ pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
+ super::weak::syscall! {
+ fn preadv(
+ fd: libc::c_int,
+ iovec: *const libc::iovec,
+ n_iovec: libc::c_int,
+ offset: off64_t
+ ) -> isize
+ }
+
+ let ret = cvt(unsafe {
+ preadv(
+ self.as_raw_fd(),
+ bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec,
+ cmp::min(bufs.len(), max_iov()) as libc::c_int,
+ offset as _,
+ )
+ })?;
+ Ok(ret as usize)
+ }
+
+ // We support old MacOS and iOS versions that do not have `preadv`. There is
+ // no `syscall` possible in these platform.
+ #[cfg(any(
+ all(target_os = "android", target_pointer_width = "32"),
+ target_os = "ios",
+ target_os = "macos",
+ ))]
+ pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
+ super::weak::weak!(fn preadv64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize);
+
+ match preadv64.get() {
+ Some(preadv) => {
+ let ret = cvt(unsafe {
+ preadv(
+ self.as_raw_fd(),
+ bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec,
+ cmp::min(bufs.len(), max_iov()) as libc::c_int,
+ offset as _,
+ )
+ })?;
+ Ok(ret as usize)
+ }
+ None => io::default_read_vectored(|b| self.read_at(b, offset), bufs),
+ }
+ }
+
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
libc::write(
@@ -172,7 +267,7 @@ impl FileDesc {
#[cfg(any(target_os = "espidf", target_os = "horizon"))]
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
- return crate::io::default_write_vectored(|b| self.write(b), bufs);
+ io::default_write_vectored(|b| self.write(b), bufs)
}
#[inline]
@@ -197,9 +292,93 @@ impl FileDesc {
}
}
- #[cfg(target_os = "linux")]
- pub fn get_cloexec(&self) -> io::Result<bool> {
- unsafe { Ok((cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) }
+ #[cfg(any(
+ target_os = "emscripten",
+ target_os = "freebsd",
+ target_os = "fuchsia",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "netbsd",
+ ))]
+ pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
+ let ret = cvt(unsafe {
+ libc::pwritev(
+ self.as_raw_fd(),
+ bufs.as_ptr() as *const libc::iovec,
+ cmp::min(bufs.len(), max_iov()) as libc::c_int,
+ offset as _,
+ )
+ })?;
+ Ok(ret as usize)
+ }
+
+ #[cfg(not(any(
+ target_os = "android",
+ target_os = "emscripten",
+ target_os = "freebsd",
+ target_os = "fuchsia",
+ target_os = "illumos",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ )))]
+ pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
+ io::default_write_vectored(|b| self.write_at(b, offset), bufs)
+ }
+
+ // We support some old Android versions that do not have `pwritev` in libc,
+ // so we use weak linkage and fallback to a direct syscall if not available.
+ //
+ // On 32-bit targets, we don't want to deal with weird ABI issues around
+ // passing 64-bits parameters to syscalls, so we fallback to the default
+ // implementation if `pwritev` is not available.
+ #[cfg(all(target_os = "android", target_pointer_width = "64"))]
+ pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
+ super::weak::syscall! {
+ fn pwritev(
+ fd: libc::c_int,
+ iovec: *const libc::iovec,
+ n_iovec: libc::c_int,
+ offset: off64_t
+ ) -> isize
+ }
+
+ let ret = cvt(unsafe {
+ pwritev(
+ self.as_raw_fd(),
+ bufs.as_ptr() as *const libc::iovec,
+ cmp::min(bufs.len(), max_iov()) as libc::c_int,
+ offset as _,
+ )
+ })?;
+ Ok(ret as usize)
+ }
+
+ // We support old MacOS and iOS versions that do not have `pwritev`. There is
+ // no `syscall` possible in these platform.
+ #[cfg(any(
+ all(target_os = "android", target_pointer_width = "32"),
+ target_os = "ios",
+ target_os = "macos",
+ ))]
+ pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
+ super::weak::weak!(fn pwritev64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize);
+
+ match pwritev64.get() {
+ Some(pwritev) => {
+ let ret = cvt(unsafe {
+ pwritev(
+ self.as_raw_fd(),
+ bufs.as_ptr() as *const libc::iovec,
+ cmp::min(bufs.len(), max_iov()) as libc::c_int,
+ offset as _,
+ )
+ })?;
+ Ok(ret as usize)
+ }
+ None => io::default_write_vectored(|b| self.write_at(b, offset), bufs),
+ }
}
#[cfg(not(any(
@@ -212,7 +391,8 @@ impl FileDesc {
target_os = "linux",
target_os = "haiku",
target_os = "redox",
- target_os = "vxworks"
+ target_os = "vxworks",
+ target_os = "nto",
)))]
pub fn set_cloexec(&self) -> io::Result<()> {
unsafe {
@@ -230,7 +410,8 @@ impl FileDesc {
target_os = "linux",
target_os = "haiku",
target_os = "redox",
- target_os = "vxworks"
+ target_os = "vxworks",
+ target_os = "nto",
))]
pub fn set_cloexec(&self) -> io::Result<()> {
unsafe {
@@ -284,6 +465,10 @@ impl<'a> Read for &'a FileDesc {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**self).read(buf)
}
+
+ fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
+ (**self).read_buf(cursor)
+ }
}
impl AsInner<OwnedFd> for FileDesc {
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 8e1f35d6c..7566fafda 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -13,7 +13,8 @@ use crate::mem;
target_os = "solaris",
target_os = "fuchsia",
target_os = "redox",
- target_os = "illumos"
+ target_os = "illumos",
+ target_os = "nto",
))]
use crate::mem::MaybeUninit;
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
@@ -54,7 +55,8 @@ use libc::fstatat64;
target_os = "solaris",
target_os = "fuchsia",
target_os = "redox",
- target_os = "illumos"
+ target_os = "illumos",
+ target_os = "nto",
))]
use libc::readdir as readdir64;
#[cfg(target_os = "linux")]
@@ -69,7 +71,8 @@ use libc::readdir64_r;
target_os = "illumos",
target_os = "l4re",
target_os = "fuchsia",
- target_os = "redox"
+ target_os = "redox",
+ target_os = "nto",
)))]
use libc::readdir_r as readdir64_r;
#[cfg(target_os = "android")]
@@ -277,7 +280,8 @@ unsafe impl Sync for Dir {}
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
- target_os = "redox"
+ target_os = "redox",
+ target_os = "nto",
))]
pub struct DirEntry {
dir: Arc<InnerReadDir>,
@@ -297,11 +301,12 @@ pub struct DirEntry {
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
- target_os = "redox"
+ target_os = "redox",
+ target_os = "nto",
))]
struct dirent64_min {
d_ino: u64,
- #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
+ #[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "nto")))]
d_type: u8,
}
@@ -311,7 +316,8 @@ struct dirent64_min {
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
- target_os = "redox"
+ target_os = "redox",
+ target_os = "nto",
)))]
pub struct DirEntry {
dir: Arc<InnerReadDir>,
@@ -438,7 +444,7 @@ impl FileAttr {
}
}
-#[cfg(not(target_os = "netbsd"))]
+#[cfg(not(any(target_os = "netbsd", target_os = "nto")))]
impl FileAttr {
#[cfg(not(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon")))]
pub fn modified(&self) -> io::Result<SystemTime> {
@@ -524,6 +530,21 @@ impl FileAttr {
}
}
+#[cfg(target_os = "nto")]
+impl FileAttr {
+ pub fn modified(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::new(self.stat.st_mtim.tv_sec, self.stat.st_mtim.tv_nsec))
+ }
+
+ pub fn accessed(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::new(self.stat.st_atim.tv_sec, self.stat.st_atim.tv_nsec))
+ }
+
+ pub fn created(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::new(self.stat.st_ctim.tv_sec, self.stat.st_ctim.tv_nsec))
+ }
+}
+
impl AsInner<stat64> for FileAttr {
fn as_inner(&self) -> &stat64 {
&self.stat
@@ -603,7 +624,8 @@ impl Iterator for ReadDir {
target_os = "solaris",
target_os = "fuchsia",
target_os = "redox",
- target_os = "illumos"
+ target_os = "illumos",
+ target_os = "nto",
))]
fn next(&mut self) -> Option<io::Result<DirEntry>> {
if self.end_of_stream {
@@ -686,7 +708,11 @@ impl Iterator for ReadDir {
let entry = dirent64_min {
d_ino: *offset_ptr!(entry_ptr, d_ino) as u64,
- #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
+ #[cfg(not(any(
+ target_os = "solaris",
+ target_os = "illumos",
+ target_os = "nto",
+ )))]
d_type: *offset_ptr!(entry_ptr, d_type) as u8,
};
@@ -705,7 +731,8 @@ impl Iterator for ReadDir {
target_os = "solaris",
target_os = "fuchsia",
target_os = "redox",
- target_os = "illumos"
+ target_os = "illumos",
+ target_os = "nto",
)))]
fn next(&mut self) -> Option<io::Result<DirEntry>> {
if self.end_of_stream {
@@ -794,7 +821,8 @@ impl DirEntry {
target_os = "solaris",
target_os = "illumos",
target_os = "haiku",
- target_os = "vxworks"
+ target_os = "vxworks",
+ target_os = "nto",
))]
pub fn file_type(&self) -> io::Result<FileType> {
self.metadata().map(|m| m.file_type())
@@ -804,7 +832,8 @@ impl DirEntry {
target_os = "solaris",
target_os = "illumos",
target_os = "haiku",
- target_os = "vxworks"
+ target_os = "vxworks",
+ target_os = "nto",
)))]
pub fn file_type(&self) -> io::Result<FileType> {
match self.entry.d_type {
@@ -834,7 +863,8 @@ impl DirEntry {
target_os = "redox",
target_os = "vxworks",
target_os = "espidf",
- target_os = "horizon"
+ target_os = "horizon",
+ target_os = "nto",
))]
pub fn ino(&self) -> u64 {
self.entry.d_ino as u64
@@ -887,7 +917,8 @@ impl DirEntry {
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
- target_os = "redox"
+ target_os = "redox",
+ target_os = "nto",
)))]
fn name_cstr(&self) -> &CStr {
unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
@@ -898,7 +929,8 @@ impl DirEntry {
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
- target_os = "redox"
+ target_os = "redox",
+ target_os = "nto",
))]
fn name_cstr(&self) -> &CStr {
&self.name
@@ -1051,7 +1083,8 @@ impl File {
target_os = "linux",
target_os = "android",
target_os = "netbsd",
- target_os = "openbsd"
+ target_os = "openbsd",
+ target_os = "nto",
))]
unsafe fn os_datasync(fd: c_int) -> c_int {
libc::fdatasync(fd)
@@ -1065,6 +1098,7 @@ impl File {
target_os = "netbsd",
target_os = "openbsd",
target_os = "watchos",
+ target_os = "nto",
)))]
unsafe fn os_datasync(fd: c_int) -> c_int {
libc::fsync(fd)
@@ -1098,6 +1132,10 @@ impl File {
self.0.read_buf(cursor)
}
+ pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
+ self.0.read_vectored_at(bufs, offset)
+ }
+
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
@@ -1115,6 +1153,10 @@ impl File {
self.0.write_at(buf, offset)
}
+ pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
+ self.0.write_vectored_at(bufs, offset)
+ }
+
pub fn flush(&self) -> io::Result<()> {
Ok(())
}
@@ -1750,13 +1792,25 @@ pub fn chroot(dir: &Path) -> io::Result<()> {
pub use remove_dir_impl::remove_dir_all;
// Fallback for REDOX, ESP-ID, Horizon, and Miri
-#[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", miri))]
+#[cfg(any(
+ target_os = "redox",
+ target_os = "espidf",
+ target_os = "horizon",
+ target_os = "nto",
+ miri
+))]
mod remove_dir_impl {
pub use crate::sys_common::fs::remove_dir_all;
}
// Modern implementation using openat(), unlinkat() and fdopendir()
-#[cfg(not(any(target_os = "redox", target_os = "espidf", target_os = "horizon", miri)))]
+#[cfg(not(any(
+ target_os = "redox",
+ target_os = "espidf",
+ target_os = "horizon",
+ target_os = "nto",
+ miri
+)))]
mod remove_dir_impl {
use super::{lstat, Dir, DirEntry, InnerReadDir, ReadDir};
use crate::ffi::CStr;
diff --git a/library/std/src/sys/unix/locks/pthread_condvar.rs b/library/std/src/sys/unix/locks/pthread_condvar.rs
index 6be1abc2b..192fa216d 100644
--- a/library/std/src/sys/unix/locks/pthread_condvar.rs
+++ b/library/std/src/sys/unix/locks/pthread_condvar.rs
@@ -2,7 +2,10 @@ use crate::cell::UnsafeCell;
use crate::ptr;
use crate::sync::atomic::{AtomicPtr, Ordering::Relaxed};
use crate::sys::locks::{pthread_mutex, Mutex};
+#[cfg(not(target_os = "nto"))]
use crate::sys::time::TIMESPEC_MAX;
+#[cfg(target_os = "nto")]
+use crate::sys::time::TIMESPEC_MAX_CAPPED;
use crate::sys_common::lazy_box::{LazyBox, LazyInit};
use crate::time::Duration;
@@ -132,10 +135,18 @@ impl Condvar {
let mutex = pthread_mutex::raw(mutex);
self.verify(mutex);
+ #[cfg(not(target_os = "nto"))]
let timeout = Timespec::now(libc::CLOCK_MONOTONIC)
.checked_add_duration(&dur)
.and_then(|t| t.to_timespec())
.unwrap_or(TIMESPEC_MAX);
+
+ #[cfg(target_os = "nto")]
+ let timeout = Timespec::now(libc::CLOCK_MONOTONIC)
+ .checked_add_duration(&dur)
+ .and_then(|t| t.to_timespec_capped())
+ .unwrap_or(TIMESPEC_MAX_CAPPED);
+
let r = libc::pthread_cond_timedwait(raw(self), mutex, &timeout);
assert!(r == libc::ETIMEDOUT || r == 0);
r == 0
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 30a96be14..68c9520cc 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -329,7 +329,7 @@ pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> {
// do so. In 1003.1-2004 this was fixed.
//
// glibc's implementation did the flush, unsafely, before glibc commit
-// 91e7cf982d01 `abort: Do not flush stdio streams [BZ #15436]' by Florian
+// 91e7cf982d01 `abort: Do not flush stdio streams [BZ #15436]` by Florian
// Weimer. According to glibc's NEWS:
//
// The abort function terminates the process immediately, without flushing
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index c86f80972..8e05b618d 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -78,6 +78,7 @@ impl Socket {
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
+ target_os = "nto",
))] {
// On platforms that support it we pass the SOCK_CLOEXEC
// flag to atomically create the socket and set it as
@@ -115,6 +116,7 @@ impl Socket {
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
+ target_os = "nto",
))] {
// Like above, set cloexec atomically
cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?;
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 2f2663db6..21b035fb3 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -62,6 +62,7 @@ extern "C" {
link_name = "__errno"
)]
#[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")]
+ #[cfg_attr(target_os = "nto", link_name = "__get_errno_ptr")]
#[cfg_attr(
any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "watchos"),
link_name = "__error"
@@ -361,6 +362,17 @@ pub fn current_exe() -> io::Result<PathBuf> {
}
}
+#[cfg(target_os = "nto")]
+pub fn current_exe() -> io::Result<PathBuf> {
+ let mut e = crate::fs::read("/proc/self/exefile")?;
+ // Current versions of QNX Neutrino provide a null-terminated path.
+ // Ensure the trailing null byte is not returned here.
+ if let Some(0) = e.last() {
+ e.pop();
+ }
+ Ok(PathBuf::from(OsString::from_vec(e)))
+}
+
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
pub fn current_exe() -> io::Result<PathBuf> {
unsafe {
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 3bc17b775..ceaff5966 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -18,6 +18,7 @@ use crate::sys::weak::raw_syscall;
target_os = "freebsd",
all(target_os = "linux", target_env = "gnu"),
all(target_os = "linux", target_env = "musl"),
+ target_os = "nto",
))]
use crate::sys::weak::weak;
@@ -30,6 +31,15 @@ use libc::{c_int, pid_t};
#[cfg(not(any(target_os = "vxworks", target_os = "l4re")))]
use libc::{gid_t, uid_t};
+cfg_if::cfg_if! {
+ if #[cfg(all(target_os = "nto", target_env = "nto71"))] {
+ use crate::thread;
+ use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t};
+ // arbitrary number of tries:
+ const MAX_FORKSPAWN_TRIES: u32 = 4;
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////
@@ -140,11 +150,31 @@ impl Command {
// Attempts to fork the process. If successful, returns Ok((0, -1))
// in the child, and Ok((child_pid, -1)) in the parent.
- #[cfg(not(target_os = "linux"))]
+ #[cfg(not(any(target_os = "linux", all(target_os = "nto", target_env = "nto71"))))]
unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
cvt(libc::fork()).map(|res| (res, -1))
}
+ // On QNX Neutrino, fork can fail with EBADF in case "another thread might have opened
+ // or closed a file descriptor while the fork() was occurring".
+ // Documentation says "... or try calling fork() again". This is what we do here.
+ // See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html
+ #[cfg(all(target_os = "nto", target_env = "nto71"))]
+ unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
+ use crate::sys::os::errno;
+
+ let mut tries_left = MAX_FORKSPAWN_TRIES;
+ loop {
+ let r = libc::fork();
+ if r == -1 as libc::pid_t && tries_left > 0 && errno() as libc::c_int == libc::EBADF {
+ thread::yield_now();
+ tries_left -= 1;
+ } else {
+ return cvt(r).map(|res| (res, -1));
+ }
+ }
+ }
+
// Attempts to fork the process. If successful, returns Ok((0, -1))
// in the child, and Ok((child_pid, child_pidfd)) in the parent.
#[cfg(target_os = "linux")]
@@ -389,6 +419,7 @@ impl Command {
target_os = "freebsd",
all(target_os = "linux", target_env = "gnu"),
all(target_os = "linux", target_env = "musl"),
+ target_os = "nto",
)))]
fn posix_spawn(
&mut self,
@@ -405,6 +436,7 @@ impl Command {
target_os = "freebsd",
all(target_os = "linux", target_env = "gnu"),
all(target_os = "linux", target_env = "musl"),
+ target_os = "nto",
))]
fn posix_spawn(
&mut self,
@@ -436,6 +468,34 @@ impl Command {
}
}
+ // On QNX Neutrino, posix_spawnp can fail with EBADF in case "another thread might have opened
+ // or closed a file descriptor while the posix_spawn() was occurring".
+ // Documentation says "... or try calling posix_spawn() again". This is what we do here.
+ // See also http://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/p/posix_spawn.html
+ #[cfg(all(target_os = "nto", target_env = "nto71"))]
+ unsafe fn retrying_libc_posix_spawnp(
+ pid: *mut pid_t,
+ file: *const c_char,
+ file_actions: *const posix_spawn_file_actions_t,
+ attrp: *const posix_spawnattr_t,
+ argv: *const *mut c_char,
+ envp: *const *mut c_char,
+ ) -> i32 {
+ let mut tries_left = MAX_FORKSPAWN_TRIES;
+ loop {
+ match libc::posix_spawnp(pid, file, file_actions, attrp, argv, envp) {
+ libc::EBADF if tries_left > 0 => {
+ thread::yield_now();
+ tries_left -= 1;
+ continue;
+ }
+ r => {
+ return r;
+ }
+ }
+ }
+ }
+
// Solaris, glibc 2.29+, and musl 1.24+ can set a new working directory,
// and maybe others will gain this non-POSIX function too. We'll check
// for this weak symbol as soon as it's needed, so we can return early
@@ -555,7 +615,12 @@ impl Command {
// Make sure we synchronize access to the global `environ` resource
let _env_lock = sys::os::env_read_lock();
let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _);
- cvt_nz(libc::posix_spawnp(
+
+ #[cfg(not(target_os = "nto"))]
+ let spawn_fn = libc::posix_spawnp;
+ #[cfg(target_os = "nto")]
+ let spawn_fn = retrying_libc_posix_spawnp;
+ cvt_nz(spawn_fn(
&mut p.pid,
self.get_program_cstr().as_ptr(),
file_actions.0.as_ptr(),
@@ -760,7 +825,7 @@ fn signal_string(signal: i32) -> &'static str {
)
))]
libc::SIGSTKFLT => " (SIGSTKFLT)",
- #[cfg(target_os = "linux")]
+ #[cfg(any(target_os = "linux", target_os = "nto"))]
libc::SIGPWR => " (SIGPWR)",
#[cfg(any(
target_os = "macos",
@@ -769,7 +834,8 @@ fn signal_string(signal: i32) -> &'static str {
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
- target_os = "dragonfly"
+ target_os = "dragonfly",
+ target_os = "nto",
))]
libc::SIGEMT => " (SIGEMT)",
#[cfg(any(
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 2a1830d06..15070b1f6 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -9,7 +9,7 @@ use crate::time::Duration;
#[cfg(all(target_os = "linux", target_env = "gnu"))]
use crate::sys::weak::dlsym;
-#[cfg(any(target_os = "solaris", target_os = "illumos"))]
+#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))]
use crate::sys::weak::weak;
#[cfg(not(any(target_os = "l4re", target_os = "vxworks", target_os = "espidf")))]
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
@@ -49,7 +49,7 @@ unsafe impl Sync for Thread {}
impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
- let p = Box::into_raw(box p);
+ let p = Box::into_raw(Box::new(p));
let mut native: libc::pthread_t = mem::zeroed();
let mut attr: libc::pthread_attr_t = mem::zeroed();
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
@@ -173,7 +173,7 @@ impl Thread {
}
}
- #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+ #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))]
pub fn set_name(name: &CStr) {
weak! {
fn pthread_setname_np(
@@ -381,6 +381,17 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
}
Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
+ } else if #[cfg(target_os = "nto")] {
+ unsafe {
+ use libc::_syspage_ptr;
+ if _syspage_ptr.is_null() {
+ Err(io::const_io_error!(io::ErrorKind::NotFound, "No syspage available"))
+ } else {
+ let cpus = (*_syspage_ptr).num_cpu;
+ NonZeroUsize::new(cpus as usize)
+ .ok_or(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"))
+ }
+ }
} else if #[cfg(target_os = "haiku")] {
// system_info cpu_count field gets the static data set at boot time with `smp_set_num_cpus`
// `get_system_info` calls then `smp_get_num_cpus`
diff --git a/library/std/src/sys/unix/thread_local_dtor.rs b/library/std/src/sys/unix/thread_local_dtor.rs
index d7fd2130f..236d2f2ee 100644
--- a/library/std/src/sys/unix/thread_local_dtor.rs
+++ b/library/std/src/sys/unix/thread_local_dtor.rs
@@ -11,13 +11,7 @@
// Note, however, that we run on lots older linuxes, as well as cross
// compiling from a newer linux to an older linux, so we also have a
// fallback implementation to use as well.
-#[cfg(any(
- target_os = "linux",
- target_os = "fuchsia",
- target_os = "redox",
- target_os = "emscripten"
-))]
-#[cfg_attr(target_family = "wasm", allow(unused))] // might remain unused depending on target details (e.g. wasm32-unknown-emscripten)
+#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox"))]
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
use crate::mem;
use crate::sys_common::thread_local_dtor::register_dtor_fallback;
@@ -57,44 +51,40 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
#[cfg(target_os = "macos")]
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
use crate::cell::Cell;
+ use crate::mem;
use crate::ptr;
#[thread_local]
static REGISTERED: Cell<bool> = Cell::new(false);
+
+ #[thread_local]
+ static mut DTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
+
if !REGISTERED.get() {
_tlv_atexit(run_dtors, ptr::null_mut());
REGISTERED.set(true);
}
- type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
-
- #[thread_local]
- static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut());
- if DTORS.get().is_null() {
- let v: Box<List> = box Vec::new();
- DTORS.set(Box::into_raw(v));
- }
-
extern "C" {
fn _tlv_atexit(dtor: unsafe extern "C" fn(*mut u8), arg: *mut u8);
}
- let list: &mut List = &mut *DTORS.get();
+ let list = &mut DTORS;
list.push((t, dtor));
unsafe extern "C" fn run_dtors(_: *mut u8) {
- let mut ptr = DTORS.replace(ptr::null_mut());
- while !ptr.is_null() {
- let list = Box::from_raw(ptr);
- for (ptr, dtor) in list.into_iter() {
+ let mut list = mem::take(&mut DTORS);
+ while !list.is_empty() {
+ for (ptr, dtor) in list {
dtor(ptr);
}
- ptr = DTORS.replace(ptr::null_mut());
+ list = mem::take(&mut DTORS);
}
}
}
-#[cfg(any(target_os = "vxworks", target_os = "horizon"))]
+#[cfg(any(target_os = "vxworks", target_os = "horizon", target_os = "emscripten"))]
+#[cfg_attr(target_family = "wasm", allow(unused))] // might remain unused depending on target details (e.g. wasm32-unknown-emscripten)
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
use crate::sys_common::thread_local_dtor::register_dtor_fallback;
register_dtor_fallback(t, dtor);
diff --git a/library/std/src/sys/unix/thread_parking/pthread.rs b/library/std/src/sys/unix/thread_parking/pthread.rs
index 082d25e68..43046ed07 100644
--- a/library/std/src/sys/unix/thread_parking/pthread.rs
+++ b/library/std/src/sys/unix/thread_parking/pthread.rs
@@ -6,7 +6,10 @@ use crate::pin::Pin;
use crate::ptr::addr_of_mut;
use crate::sync::atomic::AtomicUsize;
use crate::sync::atomic::Ordering::SeqCst;
+#[cfg(not(target_os = "nto"))]
use crate::sys::time::TIMESPEC_MAX;
+#[cfg(target_os = "nto")]
+use crate::sys::time::TIMESPEC_MAX_CAPPED;
use crate::time::Duration;
const EMPTY: usize = 0;
@@ -80,8 +83,14 @@ unsafe fn wait_timeout(
(Timespec::now(libc::CLOCK_MONOTONIC), dur)
};
+ #[cfg(not(target_os = "nto"))]
let timeout =
now.checked_add_duration(&dur).and_then(|t| t.to_timespec()).unwrap_or(TIMESPEC_MAX);
+ #[cfg(target_os = "nto")]
+ let timeout = now
+ .checked_add_duration(&dur)
+ .and_then(|t| t.to_timespec_capped())
+ .unwrap_or(TIMESPEC_MAX_CAPPED);
let r = libc::pthread_cond_timedwait(cond, lock, &timeout);
debug_assert!(r == libc::ETIMEDOUT || r == 0);
}
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index 2daad981b..0f11de8f5 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -9,6 +9,14 @@ pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
pub const TIMESPEC_MAX: libc::timespec =
libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 };
+// This additional constant is only used when calling
+// `libc::pthread_cond_timedwait`.
+#[cfg(target_os = "nto")]
+pub(super) const TIMESPEC_MAX_CAPPED: libc::timespec = libc::timespec {
+ tv_sec: (u64::MAX / NSEC_PER_SEC) as i64,
+ tv_nsec: (u64::MAX % NSEC_PER_SEC) as i64,
+};
+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(0)]
@@ -144,6 +152,20 @@ impl Timespec {
tv_nsec: self.tv_nsec.0.try_into().ok()?,
})
}
+
+ // On QNX Neutrino, the maximum timespec for e.g. pthread_cond_timedwait
+ // is 2^64 nanoseconds
+ #[cfg(target_os = "nto")]
+ pub(super) fn to_timespec_capped(&self) -> Option<libc::timespec> {
+ // Check if timeout in nanoseconds would fit into an u64
+ if (self.tv_nsec.0 as u64)
+ .checked_add((self.tv_sec as u64).checked_mul(NSEC_PER_SEC)?)
+ .is_none()
+ {
+ return None;
+ }
+ self.to_timespec()
+ }
}
impl From<libc::timespec> for Timespec {
diff --git a/library/std/src/sys/unsupported/once.rs b/library/std/src/sys/unsupported/once.rs
index b4bb4975f..11fde1888 100644
--- a/library/std/src/sys/unsupported/once.rs
+++ b/library/std/src/sys/unsupported/once.rs
@@ -1,5 +1,6 @@
use crate::cell::Cell;
use crate::sync as public;
+use crate::sync::once::ExclusiveState;
pub struct Once {
state: Cell<State>,
@@ -44,6 +45,16 @@ impl Once {
self.state.get() == State::Complete
}
+ #[inline]
+ pub(crate) fn state(&mut self) -> ExclusiveState {
+ match self.state.get() {
+ State::Incomplete => ExclusiveState::Incomplete,
+ State::Poisoned => ExclusiveState::Poisoned,
+ State::Complete => ExclusiveState::Complete,
+ _ => unreachable!("invalid Once state"),
+ }
+ }
+
#[cold]
#[track_caller]
pub fn call(&self, ignore_poisoning: bool, f: &mut impl FnMut(&public::OnceState)) {
diff --git a/library/std/src/sys/wasi/os.rs b/library/std/src/sys/wasi/os.rs
index f5513e999..9919dc708 100644
--- a/library/std/src/sys/wasi/os.rs
+++ b/library/std/src/sys/wasi/os.rs
@@ -21,6 +21,7 @@ mod libc {
extern "C" {
pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char;
pub fn chdir(dir: *const c_char) -> c_int;
+ pub fn __wasilibc_get_environ() -> *mut *mut c_char;
}
}
@@ -161,7 +162,12 @@ impl Iterator for Env {
pub fn env() -> Env {
unsafe {
let _guard = env_read_lock();
- let mut environ = libc::environ;
+
+ // Use `__wasilibc_get_environ` instead of `environ` here so that we
+ // don't require wasi-libc to eagerly initialize the environment
+ // variables.
+ let mut environ = libc::__wasilibc_get_environ();
+
let mut result = Vec::new();
if !environ.is_null() {
while !(*environ).is_null() {
diff --git a/library/std/src/sys/windows/args.rs b/library/std/src/sys/windows/args.rs
index 6741ae46d..30356fa85 100644
--- a/library/std/src/sys/windows/args.rs
+++ b/library/std/src/sys/windows/args.rs
@@ -270,7 +270,7 @@ pub(crate) fn make_bat_command_line(
// It is necessary to surround the command in an extra pair of quotes,
// hence the trailing quote here. It will be closed after all arguments
// have been added.
- let mut cmd: Vec<u16> = "cmd.exe /c \"".encode_utf16().collect();
+ let mut cmd: Vec<u16> = "cmd.exe /d /c \"".encode_utf16().collect();
// Push the script name surrounded by its quote pair.
cmd.push(b'"' as u16);
@@ -290,6 +290,15 @@ pub(crate) fn make_bat_command_line(
// reconstructed by the batch script by default.
for arg in args {
cmd.push(' ' as u16);
+ // Make sure to always quote special command prompt characters, including:
+ // * Characters `cmd /?` says require quotes.
+ // * `%` for environment variables, as in `%TMP%`.
+ // * `|<>` pipe/redirect characters.
+ const SPECIAL: &[u8] = b"\t &()[]{}^=;!'+,`~%|<>";
+ let force_quotes = match arg {
+ Arg::Regular(arg) if !force_quotes => arg.bytes().iter().any(|c| SPECIAL.contains(c)),
+ _ => force_quotes,
+ };
append_arg(&mut cmd, arg, force_quotes)?;
}
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index f58dcf128..5d150eca0 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -6,13 +6,15 @@
use crate::ffi::CStr;
use crate::mem;
-use crate::os::raw::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ushort};
+use crate::os::raw::{c_char, c_long, c_longlong, c_uint, c_ulong, c_ushort};
use crate::os::windows::io::{BorrowedHandle, HandleOrInvalid, HandleOrNull};
use crate::ptr;
use core::ffi::NonZero_c_ulong;
use libc::{c_void, size_t, wchar_t};
+pub use crate::os::raw::c_int;
+
#[path = "c/errors.rs"] // c.rs is included from two places so we need to specify this
mod errors;
pub use errors::*;
@@ -47,16 +49,19 @@ pub type ACCESS_MASK = DWORD;
pub type LPBOOL = *mut BOOL;
pub type LPBYTE = *mut BYTE;
+pub type LPCCH = *const CHAR;
pub type LPCSTR = *const CHAR;
+pub type LPCWCH = *const WCHAR;
pub type LPCWSTR = *const WCHAR;
+pub type LPCVOID = *const c_void;
pub type LPDWORD = *mut DWORD;
pub type LPHANDLE = *mut HANDLE;
pub type LPOVERLAPPED = *mut OVERLAPPED;
pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION;
pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES;
pub type LPSTARTUPINFO = *mut STARTUPINFO;
+pub type LPSTR = *mut CHAR;
pub type LPVOID = *mut c_void;
-pub type LPCVOID = *const c_void;
pub type LPWCH = *mut WCHAR;
pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW;
pub type LPWSADATA = *mut WSADATA;
@@ -132,6 +137,10 @@ pub const MAX_PATH: usize = 260;
pub const FILE_TYPE_PIPE: u32 = 3;
+pub const CP_UTF8: DWORD = 65001;
+pub const MB_ERR_INVALID_CHARS: DWORD = 0x08;
+pub const WC_ERR_INVALID_CHARS: DWORD = 0x80;
+
#[repr(C)]
#[derive(Copy)]
pub struct WIN32_FIND_DATAW {
@@ -539,14 +548,6 @@ pub struct SYMBOLIC_LINK_REPARSE_BUFFER {
pub PathBuffer: WCHAR,
}
-/// NB: Use carefully! In general using this as a reference is likely to get the
-/// provenance wrong for the `PathBuffer` field!
-#[repr(C)]
-pub struct FILE_NAME_INFO {
- pub FileNameLength: DWORD,
- pub FileName: [WCHAR; 1],
-}
-
#[repr(C)]
pub struct MOUNT_POINT_REPARSE_BUFFER {
pub SubstituteNameOffset: c_ushort,
@@ -1155,6 +1156,25 @@ extern "system" {
lpFilePart: *mut LPWSTR,
) -> DWORD;
pub fn GetFileAttributesW(lpFileName: LPCWSTR) -> DWORD;
+
+ pub fn MultiByteToWideChar(
+ CodePage: UINT,
+ dwFlags: DWORD,
+ lpMultiByteStr: LPCCH,
+ cbMultiByte: c_int,
+ lpWideCharStr: LPWSTR,
+ cchWideChar: c_int,
+ ) -> c_int;
+ pub fn WideCharToMultiByte(
+ CodePage: UINT,
+ dwFlags: DWORD,
+ lpWideCharStr: LPCWCH,
+ cchWideChar: c_int,
+ lpMultiByteStr: LPSTR,
+ cbMultiByte: c_int,
+ lpDefaultChar: LPCCH,
+ lpUsedDefaultChar: LPBOOL,
+ ) -> c_int;
}
#[link(name = "ws2_32")]
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index 378098038..d2c597664 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -1266,7 +1266,12 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> {
// If the fallback fails for any reason we return the original error.
match File::open(path, &opts) {
Ok(file) => file.file_attr(),
- Err(e) if e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as _) => {
+ Err(e)
+ if [Some(c::ERROR_SHARING_VIOLATION as _), Some(c::ERROR_ACCESS_DENIED as _)]
+ .contains(&e.raw_os_error()) =>
+ {
+ // `ERROR_ACCESS_DENIED` is returned when the user doesn't have permission for the resource.
+ // One such example is `System Volume Information` as default but can be created as well
// `ERROR_SHARING_VIOLATION` will almost never be returned.
// Usually if a file is locked you can still read some metadata.
// However, there are special system files, such as
@@ -1393,6 +1398,8 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> {
let mut data = Align8([MaybeUninit::<u8>::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
let data_ptr = data.0.as_mut_ptr();
let db = data_ptr.cast::<c::REPARSE_MOUNTPOINT_DATA_BUFFER>();
+ // Zero the header to ensure it's fully initialized, including reserved parameters.
+ *db = mem::zeroed();
let buf = ptr::addr_of_mut!((*db).ReparseTarget).cast::<c::WCHAR>();
let mut i = 0;
// FIXME: this conversion is very hacky
diff --git a/library/std/src/sys/windows/io.rs b/library/std/src/sys/windows/io.rs
index 2cc34c986..7fdd1f702 100644
--- a/library/std/src/sys/windows/io.rs
+++ b/library/std/src/sys/windows/io.rs
@@ -2,8 +2,7 @@ use crate::marker::PhantomData;
use crate::mem::size_of;
use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle};
use crate::slice;
-use crate::sys::{c, Align8};
-use core;
+use crate::sys::c;
use libc;
#[derive(Copy, Clone)]
@@ -125,22 +124,33 @@ unsafe fn msys_tty_on(handle: c::HANDLE) -> bool {
return false;
}
- const SIZE: usize = size_of::<c::FILE_NAME_INFO>() + c::MAX_PATH * size_of::<c::WCHAR>();
- let mut name_info_bytes = Align8([0u8; SIZE]);
+ /// Mirrors [`FILE_NAME_INFO`], giving it a fixed length that we can stack
+ /// allocate
+ ///
+ /// [`FILE_NAME_INFO`]: https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_name_info
+ #[repr(C)]
+ #[allow(non_snake_case)]
+ struct FILE_NAME_INFO {
+ FileNameLength: u32,
+ FileName: [u16; c::MAX_PATH as usize],
+ }
+ let mut name_info = FILE_NAME_INFO { FileNameLength: 0, FileName: [0; c::MAX_PATH as usize] };
+ // Safety: buffer length is fixed.
let res = c::GetFileInformationByHandleEx(
handle,
c::FileNameInfo,
- name_info_bytes.0.as_mut_ptr() as *mut libc::c_void,
- SIZE as u32,
+ &mut name_info as *mut _ as *mut libc::c_void,
+ size_of::<FILE_NAME_INFO>() as u32,
);
if res == 0 {
return false;
}
- let name_info: &c::FILE_NAME_INFO = &*(name_info_bytes.0.as_ptr() as *const c::FILE_NAME_INFO);
- let name_len = name_info.FileNameLength as usize / 2;
- // Offset to get the `FileName` field.
- let name_ptr = name_info_bytes.0.as_ptr().offset(size_of::<c::DWORD>() as isize).cast::<u16>();
- let s = core::slice::from_raw_parts(name_ptr, name_len);
+
+ // Use `get` because `FileNameLength` can be out of range.
+ let s = match name_info.FileName.get(..name_info.FileNameLength as usize / 2) {
+ None => return false,
+ Some(s) => s,
+ };
let name = String::from_utf16_lossy(s);
// Get the file name only.
let name = name.rsplit('\\').next().unwrap_or(&name);
diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs
index 70c9b14a0..32c6ccffb 100644
--- a/library/std/src/sys/windows/stdio.rs
+++ b/library/std/src/sys/windows/stdio.rs
@@ -1,6 +1,5 @@
#![unstable(issue = "none", feature = "windows_stdio")]
-use crate::char::decode_utf16;
use crate::cmp;
use crate::io;
use crate::mem::MaybeUninit;
@@ -170,14 +169,27 @@ fn write(
}
fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result<usize> {
+ debug_assert!(!utf8.is_empty());
+
let mut utf16 = [MaybeUninit::<u16>::uninit(); MAX_BUFFER_SIZE / 2];
- let mut len_utf16 = 0;
- for (chr, dest) in utf8.encode_utf16().zip(utf16.iter_mut()) {
- *dest = MaybeUninit::new(chr);
- len_utf16 += 1;
- }
- // Safety: We've initialized `len_utf16` values.
- let utf16: &[u16] = unsafe { MaybeUninit::slice_assume_init_ref(&utf16[..len_utf16]) };
+ let utf8 = &utf8[..utf8.floor_char_boundary(utf16.len())];
+
+ let utf16: &[u16] = unsafe {
+ // Note that this theoretically checks validity twice in the (most common) case
+ // where the underlying byte sequence is valid utf-8 (given the check in `write()`).
+ let result = c::MultiByteToWideChar(
+ c::CP_UTF8, // CodePage
+ c::MB_ERR_INVALID_CHARS, // dwFlags
+ utf8.as_ptr() as c::LPCCH, // lpMultiByteStr
+ utf8.len() as c::c_int, // cbMultiByte
+ utf16.as_mut_ptr() as c::LPWSTR, // lpWideCharStr
+ utf16.len() as c::c_int, // cchWideChar
+ );
+ assert!(result != 0, "Unexpected error in MultiByteToWideChar");
+
+ // Safety: MultiByteToWideChar initializes `result` values.
+ MaybeUninit::slice_assume_init_ref(&utf16[..result as usize])
+ };
let mut written = write_u16s(handle, &utf16)?;
@@ -190,8 +202,8 @@ fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result<usiz
// a missing surrogate can be produced (and also because of the UTF-8 validation above),
// write the missing surrogate out now.
// Buffering it would mean we have to lie about the number of bytes written.
- let first_char_remaining = utf16[written];
- if first_char_remaining >= 0xDCEE && first_char_remaining <= 0xDFFF {
+ let first_code_unit_remaining = utf16[written];
+ if first_code_unit_remaining >= 0xDCEE && first_code_unit_remaining <= 0xDFFF {
// low surrogate
// We just hope this works, and give up otherwise
let _ = write_u16s(handle, &utf16[written..written + 1]);
@@ -213,6 +225,7 @@ fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result<usiz
}
fn write_u16s(handle: c::HANDLE, data: &[u16]) -> io::Result<usize> {
+ debug_assert!(data.len() < u32::MAX as usize);
let mut written = 0;
cvt(unsafe {
c::WriteConsoleW(
@@ -366,26 +379,32 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit<u16>]) -> io::Result<usiz
Ok(amount as usize)
}
-#[allow(unused)]
fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result<usize> {
- let mut written = 0;
- for chr in decode_utf16(utf16.iter().cloned()) {
- match chr {
- Ok(chr) => {
- chr.encode_utf8(&mut utf8[written..]);
- written += chr.len_utf8();
- }
- Err(_) => {
- // We can't really do any better than forget all data and return an error.
- return Err(io::const_io_error!(
- io::ErrorKind::InvalidData,
- "Windows stdin in console mode does not support non-UTF-16 input; \
- encountered unpaired surrogate",
- ));
- }
- }
+ debug_assert!(utf16.len() <= c::c_int::MAX as usize);
+ debug_assert!(utf8.len() <= c::c_int::MAX as usize);
+
+ let result = unsafe {
+ c::WideCharToMultiByte(
+ c::CP_UTF8, // CodePage
+ c::WC_ERR_INVALID_CHARS, // dwFlags
+ utf16.as_ptr(), // lpWideCharStr
+ utf16.len() as c::c_int, // cchWideChar
+ utf8.as_mut_ptr() as c::LPSTR, // lpMultiByteStr
+ utf8.len() as c::c_int, // cbMultiByte
+ ptr::null(), // lpDefaultChar
+ ptr::null_mut(), // lpUsedDefaultChar
+ )
+ };
+ if result == 0 {
+ // We can't really do any better than forget all data and return an error.
+ Err(io::const_io_error!(
+ io::ErrorKind::InvalidData,
+ "Windows stdin in console mode does not support non-UTF-16 input; \
+ encountered unpaired surrogate",
+ ))
+ } else {
+ Ok(result as usize)
}
- Ok(written)
}
impl IncompleteUtf8 {
diff --git a/library/std/src/sys/windows/thread.rs b/library/std/src/sys/windows/thread.rs
index 1cb576c95..ed58c47e0 100644
--- a/library/std/src/sys/windows/thread.rs
+++ b/library/std/src/sys/windows/thread.rs
@@ -22,7 +22,7 @@ pub struct Thread {
impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
- let p = Box::into_raw(box p);
+ let p = Box::into_raw(Box::new(p));
// FIXME On UNIX, we guard against stack sizes that are too small but
// that's because pthreads enforces that stacks are at least
diff --git a/library/std/src/sys/windows/thread_parking.rs b/library/std/src/sys/windows/thread_parking.rs
index 5d43676ad..eb9167cd8 100644
--- a/library/std/src/sys/windows/thread_parking.rs
+++ b/library/std/src/sys/windows/thread_parking.rs
@@ -221,7 +221,7 @@ impl Parker {
fn keyed_event_handle() -> c::HANDLE {
const INVALID: c::HANDLE = ptr::invalid_mut(!0);
- static HANDLE: AtomicPtr<libc::c_void> = AtomicPtr::new(INVALID);
+ static HANDLE: AtomicPtr<crate::ffi::c_void> = AtomicPtr::new(INVALID);
match HANDLE.load(Relaxed) {
INVALID => {
let mut handle = c::INVALID_HANDLE_VALUE;
diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs
index f1d804ef4..8752f46ff 100644
--- a/library/std/src/sys_common/backtrace.rs
+++ b/library/std/src/sys_common/backtrace.rs
@@ -91,6 +91,19 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
if stop {
return false;
}
+ #[cfg(target_os = "nto")]
+ if libc::__my_thread_exit as *mut libc::c_void == frame.ip() {
+ if !hit && start {
+ use crate::backtrace_rs::SymbolName;
+ res = bt_fmt.frame().print_raw(
+ frame.ip(),
+ Some(SymbolName::new("__my_thread_exit".as_bytes())),
+ None,
+ None,
+ );
+ }
+ return false;
+ }
if !hit && start {
res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
}
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 6b24b0e9a..e9c727cbb 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -44,7 +44,6 @@ cfg_if::cfg_if! {
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")))] {
diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs
index fad4a6333..85ecc1def 100644
--- a/library/std/src/sys_common/net.rs
+++ b/library/std/src/sys_common/net.rs
@@ -14,14 +14,14 @@ use crate::sys::net::{cvt, cvt_gai, cvt_r, init, wrlen_t, Socket};
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::time::Duration;
-use libc::{c_int, c_void};
+use crate::ffi::{c_int, c_void};
cfg_if::cfg_if! {
if #[cfg(any(
target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos", target_os = "watchos",
target_os = "openbsd", target_os = "netbsd", target_os = "illumos",
- target_os = "solaris", target_os = "haiku", target_os = "l4re"))] {
+ target_os = "solaris", target_os = "haiku", target_os = "l4re", target_os = "nto"))] {
use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
use crate::sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
} else {
@@ -35,7 +35,7 @@ cfg_if::cfg_if! {
target_os = "linux", target_os = "android",
target_os = "dragonfly", target_os = "freebsd",
target_os = "openbsd", target_os = "netbsd",
- target_os = "haiku"))] {
+ target_os = "haiku", target_os = "nto"))] {
use libc::MSG_NOSIGNAL;
} else {
const MSG_NOSIGNAL: c_int = 0x0;
@@ -46,8 +46,9 @@ cfg_if::cfg_if! {
if #[cfg(any(
target_os = "dragonfly", target_os = "freebsd",
target_os = "openbsd", target_os = "netbsd",
- target_os = "solaris", target_os = "illumos"))] {
- use libc::c_uchar;
+ target_os = "solaris", target_os = "illumos",
+ target_os = "nto"))] {
+ use crate::ffi::c_uchar;
type IpV4MultiCastType = c_uchar;
} else {
type IpV4MultiCastType = c_int;
@@ -127,8 +128,8 @@ fn to_ipv6mr_interface(value: u32) -> c_int {
}
#[cfg(not(target_os = "android"))]
-fn to_ipv6mr_interface(value: u32) -> libc::c_uint {
- value as libc::c_uint
+fn to_ipv6mr_interface(value: u32) -> crate::ffi::c_uint {
+ value as crate::ffi::c_uint
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/library/std/src/sys_common/net/tests.rs b/library/std/src/sys_common/net/tests.rs
index ac75d9ebf..fc236b802 100644
--- a/library/std/src/sys_common/net/tests.rs
+++ b/library/std/src/sys_common/net/tests.rs
@@ -6,7 +6,7 @@ fn no_lookup_host_duplicates() {
let mut addrs = HashMap::new();
let lh = match LookupHost::try_from(("localhost", 0)) {
Ok(lh) => lh,
- Err(e) => panic!("couldn't resolve `localhost': {e}"),
+ Err(e) => panic!("couldn't resolve `localhost`: {e}"),
};
for sa in lh {
*addrs.entry(sa).or_insert(0) += 1;
diff --git a/library/std/src/sys_common/once/futex.rs b/library/std/src/sys_common/once/futex.rs
index 5c7e6c013..42db5fad4 100644
--- a/library/std/src/sys_common/once/futex.rs
+++ b/library/std/src/sys_common/once/futex.rs
@@ -4,6 +4,7 @@ use crate::sync::atomic::{
AtomicU32,
Ordering::{Acquire, Relaxed, Release},
};
+use crate::sync::once::ExclusiveState;
use crate::sys::futex::{futex_wait, futex_wake_all};
// On some platforms, the OS is very nice and handles the waiter queue for us.
@@ -78,6 +79,16 @@ impl Once {
self.state.load(Acquire) == COMPLETE
}
+ #[inline]
+ pub(crate) fn state(&mut self) -> ExclusiveState {
+ match *self.state.get_mut() {
+ INCOMPLETE => ExclusiveState::Incomplete,
+ POISONED => ExclusiveState::Poisoned,
+ COMPLETE => ExclusiveState::Complete,
+ _ => unreachable!("invalid Once state"),
+ }
+ }
+
// This uses FnMut to match the API of the generic implementation. As this
// implementation is quite light-weight, it is generic over the closure and
// so avoids the cost of dynamic dispatch.
diff --git a/library/std/src/sys_common/once/queue.rs b/library/std/src/sys_common/once/queue.rs
index d953a6745..def0bcd6f 100644
--- a/library/std/src/sys_common/once/queue.rs
+++ b/library/std/src/sys_common/once/queue.rs
@@ -60,6 +60,7 @@ use crate::fmt;
use crate::ptr;
use crate::sync as public;
use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
+use crate::sync::once::ExclusiveState;
use crate::thread::{self, Thread};
type Masked = ();
@@ -121,6 +122,16 @@ impl Once {
self.state_and_queue.load(Ordering::Acquire).addr() == COMPLETE
}
+ #[inline]
+ pub(crate) fn state(&mut self) -> ExclusiveState {
+ match self.state_and_queue.get_mut().addr() {
+ INCOMPLETE => ExclusiveState::Incomplete,
+ POISONED => ExclusiveState::Poisoned,
+ COMPLETE => ExclusiveState::Complete,
+ _ => unreachable!("invalid Once state"),
+ }
+ }
+
// This is a non-generic function to reduce the monomorphization cost of
// using `call_once` (this isn't exactly a trivial or small implementation).
//
diff --git a/library/std/src/sys_common/thread_local_dtor.rs b/library/std/src/sys_common/thread_local_dtor.rs
index 1d13a7171..844946eda 100644
--- a/library/std/src/sys_common/thread_local_dtor.rs
+++ b/library/std/src/sys_common/thread_local_dtor.rs
@@ -30,7 +30,7 @@ pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" fn(*mut
static DTORS: StaticKey = StaticKey::new(Some(run_dtors));
type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
if DTORS.get().is_null() {
- let v: Box<List> = box Vec::new();
+ let v: Box<List> = Box::new(Vec::new());
DTORS.set(Box::into_raw(v) as *mut u8);
}
let list: &mut List = &mut *(DTORS.get() as *mut List);
diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs
index 2672a2a75..89360e456 100644
--- a/library/std/src/sys_common/thread_local_key.rs
+++ b/library/std/src/sys_common/thread_local_key.rs
@@ -117,9 +117,15 @@ pub struct Key {
/// This value specifies no destructor by default.
pub const INIT: StaticKey = StaticKey::new(None);
-// Define a sentinel value that is unlikely to be returned
-// as a TLS key (but it may be returned).
+// Define a sentinel value that is likely not to be returned
+// as a TLS key.
+#[cfg(not(target_os = "nto"))]
const KEY_SENTVAL: usize = 0;
+// On QNX Neutrino, 0 is always returned when currently not in use.
+// Using 0 would mean to always create two keys and remote the first
+// one (with value of 0) immediately afterwards.
+#[cfg(target_os = "nto")]
+const KEY_SENTVAL: usize = libc::PTHREAD_KEYS_MAX + 1;
impl StaticKey {
#[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
diff --git a/library/std/src/sys_common/thread_parking/id.rs b/library/std/src/sys_common/thread_parking/id.rs
index e98169597..575988ec7 100644
--- a/library/std/src/sys_common/thread_parking/id.rs
+++ b/library/std/src/sys_common/thread_parking/id.rs
@@ -60,7 +60,7 @@ impl Parker {
if state == PARKED {
// Loop to guard against spurious wakeups.
while state == PARKED {
- park(self.state.as_mut_ptr().addr());
+ park(self.state.as_ptr().addr());
state = self.state.load(Acquire);
}
@@ -76,7 +76,7 @@ impl Parker {
let state = self.state.fetch_sub(1, Acquire).wrapping_sub(1);
if state == PARKED {
- park_timeout(dur, self.state.as_mut_ptr().addr());
+ park_timeout(dur, self.state.as_ptr().addr());
// Swap to ensure that we observe all state changes with acquire
// ordering, even if the state has been changed after the timeout
// occured.
@@ -99,7 +99,7 @@ impl Parker {
// and terminated before this call is made. This call then returns an
// error or wakes up an unrelated thread. The platform API and
// environment does allow this, however.
- unpark(tid, self.state.as_mut_ptr().addr());
+ unpark(tid, self.state.as_ptr().addr());
}
}
}
diff --git a/library/std/src/sys_common/thread_parking/mod.rs b/library/std/src/sys_common/thread_parking/mod.rs
index 0ead6633c..e8e028bb3 100644
--- a/library/std/src/sys_common/thread_parking/mod.rs
+++ b/library/std/src/sys_common/thread_parking/mod.rs
@@ -14,12 +14,10 @@ cfg_if::cfg_if! {
} else if #[cfg(any(
target_os = "netbsd",
all(target_vendor = "fortanix", target_env = "sgx"),
+ target_os = "solid_asp3",
))] {
mod id;
pub use id::Parker;
- } else if #[cfg(target_os = "solid_asp3")] {
- mod wait_flag;
- pub use wait_flag::Parker;
} else if #[cfg(any(windows, target_family = "unix"))] {
pub use crate::sys::thread_parking::Parker;
} else {
diff --git a/library/std/src/sys_common/thread_parking/wait_flag.rs b/library/std/src/sys_common/thread_parking/wait_flag.rs
deleted file mode 100644
index d0f8899a9..000000000
--- a/library/std/src/sys_common/thread_parking/wait_flag.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-//! A wait-flag-based thread parker.
-//!
-//! Some operating systems provide low-level parking primitives like wait counts,
-//! event flags or semaphores which are not susceptible to race conditions (meaning
-//! the wakeup can occur before the wait operation). To implement the `std` thread
-//! parker on top of these primitives, we only have to ensure that parking is fast
-//! when the thread token is available, the atomic ordering guarantees are maintained
-//! and spurious wakeups are minimized.
-//!
-//! To achieve this, this parker uses an atomic variable with three states: `EMPTY`,
-//! `PARKED` and `NOTIFIED`:
-//! * `EMPTY` means the token has not been made available, but the thread is not
-//! currently waiting on it.
-//! * `PARKED` means the token is not available and the thread is parked.
-//! * `NOTIFIED` means the token is available.
-//!
-//! `park` and `park_timeout` change the state from `EMPTY` to `PARKED` and from
-//! `NOTIFIED` to `EMPTY`. If the state was `NOTIFIED`, the thread was unparked and
-//! execution can continue without calling into the OS. If the state was `EMPTY`,
-//! the token is not available and the thread waits on the primitive (here called
-//! "wait flag").
-//!
-//! `unpark` changes the state to `NOTIFIED`. If the state was `PARKED`, the thread
-//! is or will be sleeping on the wait flag, so we raise it.
-
-use crate::pin::Pin;
-use crate::sync::atomic::AtomicI8;
-use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
-use crate::sys::wait_flag::WaitFlag;
-use crate::time::Duration;
-
-const EMPTY: i8 = 0;
-const PARKED: i8 = -1;
-const NOTIFIED: i8 = 1;
-
-pub struct Parker {
- state: AtomicI8,
- wait_flag: WaitFlag,
-}
-
-impl Parker {
- /// Construct a parker for the current thread. The UNIX parker
- /// implementation requires this to happen in-place.
- pub unsafe fn new_in_place(parker: *mut Parker) {
- parker.write(Parker { state: AtomicI8::new(EMPTY), wait_flag: WaitFlag::new() })
- }
-
- // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
- pub unsafe fn park(self: Pin<&Self>) {
- match self.state.fetch_sub(1, Acquire) {
- // NOTIFIED => EMPTY
- NOTIFIED => return,
- // EMPTY => PARKED
- EMPTY => (),
- _ => panic!("inconsistent park state"),
- }
-
- // Avoid waking up from spurious wakeups (these are quite likely, see below).
- loop {
- self.wait_flag.wait();
-
- match self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed) {
- Ok(_) => return,
- Err(PARKED) => (),
- Err(_) => panic!("inconsistent park state"),
- }
- }
- }
-
- // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
- pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
- match self.state.fetch_sub(1, Acquire) {
- NOTIFIED => return,
- EMPTY => (),
- _ => panic!("inconsistent park state"),
- }
-
- self.wait_flag.wait_timeout(dur);
-
- // Either a wakeup or a timeout occurred. Wakeups may be spurious, as there can be
- // a race condition when `unpark` is performed between receiving the timeout and
- // resetting the state, resulting in the eventflag being set unnecessarily. `park`
- // is protected against this by looping until the token is actually given, but
- // here we cannot easily tell.
-
- // Use `swap` to provide acquire ordering.
- match self.state.swap(EMPTY, Acquire) {
- NOTIFIED => (),
- PARKED => (),
- _ => panic!("inconsistent park state"),
- }
- }
-
- // This implementation doesn't require `Pin`, but other implementations do.
- pub fn unpark(self: Pin<&Self>) {
- let state = self.state.swap(NOTIFIED, Release);
-
- if state == PARKED {
- self.wait_flag.raise();
- }
- }
-}
diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs
index dd53767d4..bc588bdbb 100644
--- a/library/std/src/sys_common/wtf8.rs
+++ b/library/std/src/sys_common/wtf8.rs
@@ -18,10 +18,10 @@
#[cfg(test)]
mod tests;
+use core::char::{encode_utf16_raw, encode_utf8_raw};
use core::str::next_code_point;
use crate::borrow::Cow;
-use crate::char;
use crate::collections::TryReserveError;
use crate::fmt;
use crate::hash::{Hash, Hasher};
@@ -235,7 +235,7 @@ impl Wtf8Buf {
/// This does **not** include the WTF-8 concatenation check or `is_known_utf8` check.
fn push_code_point_unchecked(&mut self, code_point: CodePoint) {
let mut bytes = [0; 4];
- let bytes = char::encode_utf8_raw(code_point.value, &mut bytes);
+ let bytes = encode_utf8_raw(code_point.value, &mut bytes);
self.bytes.extend_from_slice(bytes)
}
@@ -594,7 +594,7 @@ impl Wtf8 {
}
/// Returns the code point at `position` if it is in the ASCII range,
- /// or `b'\xFF' otherwise.
+ /// or `b'\xFF'` otherwise.
///
/// # Panics
///
@@ -939,7 +939,7 @@ impl<'a> Iterator for EncodeWide<'a> {
let mut buf = [0; 2];
self.code_points.next().map(|code_point| {
- let n = char::encode_utf16_raw(code_point.value, &mut buf).len();
+ let n = encode_utf16_raw(code_point.value, &mut buf).len();
if n == 2 {
self.extra = buf[1];
}
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index b30bb7b77..cf7c2e05a 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -1110,8 +1110,7 @@ pub mod os {
let ptr = if ptr.is_null() {
// If the lookup returned null, we haven't initialized our own
// local copy, so do that now.
- let ptr: Box<Value<T>> = box Value { inner: LazyKeyInner::new(), key: self };
- let ptr = Box::into_raw(ptr);
+ let ptr = Box::into_raw(Box::new(Value { inner: LazyKeyInner::new(), key: self }));
// SAFETY: At this point we are sure there is no value inside
// ptr so setting it will not affect anyone else.
unsafe {
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 692ff0cbc..489af7767 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -124,8 +124,10 @@
//!
//! ## Stack size
//!
-//! The default stack size is platform-dependent and subject to change. Currently it is 2MB on all
-//! Tier-1 platforms. There are two ways to manually specify the stack size for spawned threads:
+//! The default stack size is platform-dependent and subject to change.
+//! Currently, it is 2 MiB on all Tier-1 platforms.
+//!
+//! There are two ways to manually specify the stack size for spawned threads:
//!
//! * Build the thread with [`Builder`] and pass the desired stack size to [`Builder::stack_size`].
//! * Set the `RUST_MIN_STACK` environment variable to an integer representing the desired stack
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index ecd06ebf7..5c2e9da70 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -1,6 +1,6 @@
//! Temporal quantification.
//!
-//! # Examples:
+//! # Examples
//!
//! There are multiple ways to create a new [`Duration`]:
//!
@@ -352,7 +352,7 @@ impl Instant {
self.checked_duration_since(earlier).unwrap_or_default()
}
- /// Returns the amount of time elapsed since this instant was created.
+ /// Returns the amount of time elapsed since this instant.
///
/// # Panics
///
@@ -525,8 +525,8 @@ impl SystemTime {
self.0.sub_time(&earlier.0).map_err(SystemTimeError)
}
- /// Returns the difference between the clock time when this
- /// system time was created, and the current clock time.
+ /// Returns the difference from this system time to the
+ /// current clock time.
///
/// This function may fail as the underlying system clock is susceptible to
/// drift and updates (e.g., the system clock could go backwards), so this
diff --git a/library/std/tests/common/mod.rs b/library/std/tests/common/mod.rs
new file mode 100644
index 000000000..fce220223
--- /dev/null
+++ b/library/std/tests/common/mod.rs
@@ -0,0 +1,58 @@
+#![allow(unused)]
+
+use std::env;
+use std::fs;
+use std::path::{Path, PathBuf};
+use std::thread;
+use rand::RngCore;
+
+/// Copied from `std::test_helpers::test_rng`, since these tests rely on the
+/// seed not being the same for every RNG invocation too.
+#[track_caller]
+pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
+ use core::hash::{BuildHasher, Hash, Hasher};
+ let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
+ core::panic::Location::caller().hash(&mut hasher);
+ let hc64 = hasher.finish();
+ let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();
+ let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
+ rand::SeedableRng::from_seed(seed)
+}
+
+// Copied from std::sys_common::io
+pub struct TempDir(PathBuf);
+
+impl TempDir {
+ pub fn join(&self, path: &str) -> PathBuf {
+ let TempDir(ref p) = *self;
+ p.join(path)
+ }
+
+ pub fn path(&self) -> &Path {
+ let TempDir(ref p) = *self;
+ p
+ }
+}
+
+impl Drop for TempDir {
+ fn drop(&mut self) {
+ // Gee, seeing how we're testing the fs module I sure hope that we
+ // at least implement this correctly!
+ let TempDir(ref p) = *self;
+ let result = fs::remove_dir_all(p);
+ // Avoid panicking while panicking as this causes the process to
+ // immediately abort, without displaying test results.
+ if !thread::panicking() {
+ result.unwrap();
+ }
+ }
+}
+
+#[track_caller] // for `test_rng`
+pub fn tmpdir() -> TempDir {
+ let p = env::temp_dir();
+ let mut r = test_rng();
+ let ret = p.join(&format!("rust-{}", r.next_u32()));
+ fs::create_dir(&ret).unwrap();
+ TempDir(ret)
+}
diff --git a/library/std/tests/create_dir_all_bare.rs b/library/std/tests/create_dir_all_bare.rs
new file mode 100644
index 000000000..fe789323f
--- /dev/null
+++ b/library/std/tests/create_dir_all_bare.rs
@@ -0,0 +1,39 @@
+#![cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx"))))]
+
+//! Note that this test changes the current directory so
+//! should not be in the same process as other tests.
+use std::env;
+use std::fs;
+use std::path::{Path, PathBuf};
+
+mod common;
+
+// On some platforms, setting the current directory will prevent deleting it.
+// So this helper ensures the current directory is reset.
+struct CurrentDir(PathBuf);
+impl CurrentDir {
+ fn new() -> Self {
+ Self(env::current_dir().unwrap())
+ }
+ fn set(&self, path: &Path) {
+ env::set_current_dir(path).unwrap();
+ }
+ fn with(path: &Path, f: impl FnOnce()) {
+ let current_dir = Self::new();
+ current_dir.set(path);
+ f();
+ }
+}
+impl Drop for CurrentDir {
+ fn drop(&mut self) {
+ env::set_current_dir(&self.0).unwrap();
+ }
+}
+
+#[test]
+fn create_dir_all_bare() {
+ let tmpdir = common::tmpdir();
+ CurrentDir::with(tmpdir.path(), || {
+ fs::create_dir_all("create-dir-all-bare").unwrap();
+ });
+}
diff --git a/library/std/tests/env.rs b/library/std/tests/env.rs
index aae2c49d8..96b4f372b 100644
--- a/library/std/tests/env.rs
+++ b/library/std/tests/env.rs
@@ -3,18 +3,8 @@ use std::ffi::{OsStr, OsString};
use rand::distributions::{Alphanumeric, DistString};
-/// Copied from `std::test_helpers::test_rng`, since these tests rely on the
-/// seed not being the same for every RNG invocation too.
-#[track_caller]
-pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
- use core::hash::{BuildHasher, Hash, Hasher};
- let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
- core::panic::Location::caller().hash(&mut hasher);
- let hc64 = hasher.finish();
- let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();
- let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
- rand::SeedableRng::from_seed(seed)
-}
+mod common;
+use common::test_rng;
#[track_caller]
fn make_rand_name() -> OsString {
diff --git a/library/std/tests/run-time-detect.rs b/library/std/tests/run-time-detect.rs
index 1a2c12556..bf3c81fcc 100644
--- a/library/std/tests/run-time-detect.rs
+++ b/library/std/tests/run-time-detect.rs
@@ -120,16 +120,13 @@ fn x86_all() {
println!("avx512dq: {:?}", is_x86_feature_detected!("avx512dq"));
println!("avx512er: {:?}", is_x86_feature_detected!("avx512er"));
println!("avx512f: {:?}", is_x86_feature_detected!("avx512f"));
- println!("avx512gfni: {:?}", is_x86_feature_detected!("avx512gfni"));
println!("avx512ifma: {:?}", is_x86_feature_detected!("avx512ifma"));
println!("avx512pf: {:?}", is_x86_feature_detected!("avx512pf"));
- println!("avx512vaes: {:?}", is_x86_feature_detected!("avx512vaes"));
println!("avx512vbmi2: {:?}", is_x86_feature_detected!("avx512vbmi2"));
println!("avx512vbmi: {:?}", is_x86_feature_detected!("avx512vbmi"));
println!("avx512vl: {:?}", is_x86_feature_detected!("avx512vl"));
println!("avx512vnni: {:?}", is_x86_feature_detected!("avx512vnni"));
println!("avx512vp2intersect: {:?}", is_x86_feature_detected!("avx512vp2intersect"));
- println!("avx512vpclmulqdq: {:?}", is_x86_feature_detected!("avx512vpclmulqdq"));
println!("avx512vpopcntdq: {:?}", is_x86_feature_detected!("avx512vpopcntdq"));
println!("avx: {:?}", is_x86_feature_detected!("avx"));
println!("bmi1: {:?}", is_x86_feature_detected!("bmi1"));
@@ -138,6 +135,7 @@ fn x86_all() {
println!("f16c: {:?}", is_x86_feature_detected!("f16c"));
println!("fma: {:?}", is_x86_feature_detected!("fma"));
println!("fxsr: {:?}", is_x86_feature_detected!("fxsr"));
+ println!("gfni: {:?}", is_x86_feature_detected!("gfni"));
println!("lzcnt: {:?}", is_x86_feature_detected!("lzcnt"));
//println!("movbe: {:?}", is_x86_feature_detected!("movbe")); // movbe is unsupported as a target feature
println!("pclmulqdq: {:?}", is_x86_feature_detected!("pclmulqdq"));
@@ -154,6 +152,8 @@ fn x86_all() {
println!("sse: {:?}", is_x86_feature_detected!("sse"));
println!("ssse3: {:?}", is_x86_feature_detected!("ssse3"));
println!("tbm: {:?}", is_x86_feature_detected!("tbm"));
+ println!("vaes: {:?}", is_x86_feature_detected!("vaes"));
+ println!("vpclmulqdq: {:?}", is_x86_feature_detected!("vpclmulqdq"));
println!("xsave: {:?}", is_x86_feature_detected!("xsave"));
println!("xsavec: {:?}", is_x86_feature_detected!("xsavec"));
println!("xsaveopt: {:?}", is_x86_feature_detected!("xsaveopt"));