summaryrefslogtreecommitdiffstats
path: root/library/std
diff options
context:
space:
mode:
Diffstat (limited to 'library/std')
-rw-r--r--library/std/Cargo.toml23
-rw-r--r--library/std/build.rs4
-rw-r--r--library/std/src/collections/hash/map.rs60
-rw-r--r--library/std/src/collections/hash/map/tests.rs26
-rw-r--r--library/std/src/collections/hash/set.rs53
-rw-r--r--library/std/src/collections/hash/set/tests.rs42
-rw-r--r--library/std/src/f32.rs2
-rw-r--r--library/std/src/f64.rs2
-rw-r--r--library/std/src/ffi/mod.rs8
-rw-r--r--library/std/src/ffi/os_str.rs102
-rw-r--r--library/std/src/fs.rs10
-rw-r--r--library/std/src/fs/tests.rs28
-rw-r--r--library/std/src/io/buffered/bufreader.rs31
-rw-r--r--library/std/src/io/buffered/bufwriter.rs140
-rw-r--r--library/std/src/io/buffered/linewriter.rs50
-rw-r--r--library/std/src/io/buffered/linewritershim.rs6
-rw-r--r--library/std/src/io/copy.rs110
-rw-r--r--library/std/src/io/copy/tests.rs108
-rw-r--r--library/std/src/io/mod.rs13
-rw-r--r--library/std/src/io/util/tests.rs61
-rw-r--r--library/std/src/lib.rs13
-rw-r--r--library/std/src/macros.rs4
-rw-r--r--library/std/src/net/socket_addr/tests.rs2
-rw-r--r--library/std/src/net/tcp/tests.rs11
-rw-r--r--library/std/src/os/ios/fs.rs2
-rw-r--r--library/std/src/os/mod.rs3
-rw-r--r--library/std/src/os/unix/mod.rs3
-rw-r--r--library/std/src/os/unix/net/ancillary.rs9
-rw-r--r--library/std/src/os/unix/net/stream.rs3
-rw-r--r--library/std/src/os/unix/process.rs2
-rw-r--r--library/std/src/os/unix/ucred.rs4
-rw-r--r--library/std/src/os/unix/ucred/tests.rs9
-rw-r--r--library/std/src/path.rs52
-rw-r--r--library/std/src/personality.rs2
-rw-r--r--library/std/src/personality/gcc.rs2
-rw-r--r--library/std/src/primitive_docs.rs2
-rw-r--r--library/std/src/process.rs6
-rw-r--r--library/std/src/process/tests.rs15
-rw-r--r--library/std/src/sync/barrier.rs14
-rw-r--r--library/std/src/sync/mpmc/waker.rs46
-rw-r--r--library/std/src/sync/mpsc/mod.rs4
-rw-r--r--library/std/src/sync/once.rs2
-rw-r--r--library/std/src/sys/common/small_c_string.rs2
-rw-r--r--library/std/src/sys/common/tests.rs4
-rw-r--r--library/std/src/sys/common/thread_local/fast_local.rs22
-rw-r--r--library/std/src/sys/common/thread_local/mod.rs21
-rw-r--r--library/std/src/sys/unix/args.rs4
-rw-r--r--library/std/src/sys/unix/env.rs11
-rw-r--r--library/std/src/sys/unix/fd.rs17
-rw-r--r--library/std/src/sys/unix/fs.rs75
-rw-r--r--library/std/src/sys/unix/kernel_copy.rs4
-rw-r--r--library/std/src/sys/unix/l4re.rs6
-rw-r--r--library/std/src/sys/unix/locks/pthread_condvar.rs3
-rw-r--r--library/std/src/sys/unix/mod.rs15
-rw-r--r--library/std/src/sys/unix/net.rs8
-rw-r--r--library/std/src/sys/unix/os.rs12
-rw-r--r--library/std/src/sys/unix/os_str.rs13
-rw-r--r--library/std/src/sys/unix/os_str/tests.rs9
-rw-r--r--library/std/src/sys/unix/path.rs2
-rw-r--r--library/std/src/sys/unix/process/process_common.rs4
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs152
-rw-r--r--library/std/src/sys/unix/process/process_vxworks.rs7
-rw-r--r--library/std/src/sys/unix/rand.rs3
-rw-r--r--library/std/src/sys/unix/thread.rs34
-rw-r--r--library/std/src/sys/unix/thread_parking/pthread.rs6
-rw-r--r--library/std/src/sys/unix/time.rs6
-rw-r--r--library/std/src/sys/unix/weak.rs4
-rw-r--r--library/std/src/sys/wasi/fd.rs6
-rw-r--r--library/std/src/sys/wasi/fs.rs4
-rw-r--r--library/std/src/sys/windows/args.rs6
-rw-r--r--library/std/src/sys/windows/c.rs100
-rw-r--r--library/std/src/sys/windows/c/windows_sys.lst5
-rw-r--r--library/std/src/sys/windows/c/windows_sys.rs26
-rw-r--r--library/std/src/sys/windows/net.rs2
-rw-r--r--library/std/src/sys/windows/os_str.rs12
-rw-r--r--library/std/src/sys/windows/path.rs42
-rw-r--r--library/std/src/sys/windows/process.rs15
-rw-r--r--library/std/src/sys/windows/rand.rs5
-rw-r--r--library/std/src/sys/windows/stdio.rs7
-rw-r--r--library/std/src/sys/windows/stdio/tests.rs6
-rw-r--r--library/std/src/sys_common/net.rs2
-rw-r--r--library/std/src/sys_common/wtf8.rs17
-rw-r--r--library/std/src/sys_common/wtf8/tests.rs6
-rw-r--r--library/std/src/thread/mod.rs36
-rw-r--r--library/std/src/thread/tests.rs1
-rw-r--r--library/std/tests/common/mod.rs8
86 files changed, 1271 insertions, 568 deletions
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 09afc696c..e022c2d14 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -1,3 +1,5 @@
+cargo-features = ["public-dependency"]
+
[package]
name = "std"
version = "0.0.0"
@@ -10,24 +12,24 @@ edition = "2021"
crate-type = ["dylib", "rlib"]
[dependencies]
-alloc = { path = "../alloc" }
+alloc = { path = "../alloc", public = true }
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.143", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.92" }
+core = { path = "../core", public = true }
+libc = { version = "0.2.146", default-features = false, features = ['rustc-dep-of-std'], public = true }
+compiler_builtins = { version = "0.1.95" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
-hashbrown = { version = "0.13", default-features = false, features = ['rustc-dep-of-std'] }
+hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep-of-std'] }
std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] }
# Dependencies of the `backtrace` crate
-addr2line = { version = "0.18.0", optional = true, default-features = false }
+addr2line = { version = "0.21.0", optional = true, default-features = false }
rustc-demangle = { version = "0.1.21", features = ['rustc-dep-of-std'] }
-miniz_oxide = { version = "0.6.0", optional = true, default-features = false }
+miniz_oxide = { version = "0.7.0", optional = true, default-features = false, public = false }
[dependencies.object]
-version = "0.30.0"
+version = "0.32.0"
optional = true
default-features = false
features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive']
@@ -36,11 +38,11 @@ features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive']
rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
rand_xorshift = "0.3.0"
-[target.'cfg(any(all(target_family = "wasm", not(target_os = "emscripten")), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
+[target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] }
[target.x86_64-fortanix-unknown-sgx.dependencies]
-fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'] }
+fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'], public = true }
[target.'cfg(target_os = "hermit")'.dependencies]
hermit-abi = { version = "0.3.0", features = ['rustc-dep-of-std'] }
@@ -63,6 +65,7 @@ compiler-builtins-c = ["alloc/compiler-builtins-c"]
compiler-builtins-mem = ["alloc/compiler-builtins-mem"]
compiler-builtins-no-asm = ["alloc/compiler-builtins-no-asm"]
compiler-builtins-mangled-names = ["alloc/compiler-builtins-mangled-names"]
+compiler-builtins-weak-intrinsics = ["alloc/compiler-builtins-weak-intrinsics"]
llvm-libunwind = ["unwind/llvm-libunwind"]
system-llvm-libunwind = ["unwind/system-llvm-libunwind"]
diff --git a/library/std/build.rs b/library/std/build.rs
index 0fb03c8e8..ddf6e84d8 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -18,6 +18,7 @@ fn main() {
|| target.contains("illumos")
|| target.contains("apple-darwin")
|| target.contains("apple-ios")
+ || target.contains("apple-tvos")
|| target.contains("apple-watchos")
|| target.contains("uwp")
|| target.contains("windows")
@@ -36,6 +37,8 @@ fn main() {
|| target.contains("nintendo-3ds")
|| target.contains("vita")
|| target.contains("nto")
+ // See src/bootstrap/synthetic_targets.rs
+ || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
{
// These platforms don't have any special requirements.
} else {
@@ -46,7 +49,6 @@ fn main() {
// - mipsel-sony-psp
// - nvptx64-nvidia-cuda
// - arch=avr
- // - tvos (aarch64-apple-tvos, x86_64-apple-tvos)
// - uefi (x86_64-unknown-uefi, i686-unknown-uefi)
// - JSON targets
// - Any new targets that have not been explicitly added above.
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index c722bad2e..a083b6560 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -623,28 +623,27 @@ impl<K, V, S> HashMap<K, V, S> {
/// If the closure returns false, or panics, the element remains in the map and will not be
/// yielded.
///
- /// Note that `drain_filter` lets you mutate every value in the filter closure, regardless of
+ /// Note that `extract_if` lets you mutate every value in the filter closure, regardless of
/// whether you choose to keep or remove it.
///
- /// If the iterator is only partially consumed or not consumed at all, each of the remaining
- /// elements will still be subjected to the closure and removed and dropped if it returns true.
+ /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
+ /// or the iteration short-circuits, then the remaining elements will be retained.
+ /// Use [`retain`] with a negated predicate if you do not need the returned iterator.
///
- /// It is unspecified how many more elements will be subjected to the closure
- /// if a panic occurs in the closure, or a panic occurs while dropping an element,
- /// or if the `DrainFilter` value is leaked.
+ /// [`retain`]: HashMap::retain
///
/// # Examples
///
/// Splitting a map into even and odd keys, reusing the original map:
///
/// ```
- /// #![feature(hash_drain_filter)]
+ /// #![feature(hash_extract_if)]
/// use std::collections::HashMap;
///
/// let mut map: HashMap<i32, i32> = (0..8).map(|x| (x, x)).collect();
- /// let drained: HashMap<i32, i32> = map.drain_filter(|k, _v| k % 2 == 0).collect();
+ /// let extracted: HashMap<i32, i32> = map.extract_if(|k, _v| k % 2 == 0).collect();
///
- /// let mut evens = drained.keys().copied().collect::<Vec<_>>();
+ /// let mut evens = extracted.keys().copied().collect::<Vec<_>>();
/// let mut odds = map.keys().copied().collect::<Vec<_>>();
/// evens.sort();
/// odds.sort();
@@ -654,12 +653,12 @@ impl<K, V, S> HashMap<K, V, S> {
/// ```
#[inline]
#[rustc_lint_query_instability]
- #[unstable(feature = "hash_drain_filter", issue = "59618")]
- pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F>
+ #[unstable(feature = "hash_extract_if", issue = "59618")]
+ pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, K, V, F>
where
F: FnMut(&K, &mut V) -> bool,
{
- DrainFilter { base: self.base.drain_filter(pred) }
+ ExtractIf { base: self.base.extract_if(pred) }
}
/// Retains only the elements specified by the predicate.
@@ -1578,28 +1577,29 @@ impl<'a, K, V> Drain<'a, K, V> {
/// A draining, filtering iterator over the entries of a `HashMap`.
///
-/// This `struct` is created by the [`drain_filter`] method on [`HashMap`].
+/// This `struct` is created by the [`extract_if`] method on [`HashMap`].
///
-/// [`drain_filter`]: HashMap::drain_filter
+/// [`extract_if`]: HashMap::extract_if
///
/// # Example
///
/// ```
-/// #![feature(hash_drain_filter)]
+/// #![feature(hash_extract_if)]
///
/// use std::collections::HashMap;
///
/// let mut map = HashMap::from([
/// ("a", 1),
/// ]);
-/// let iter = map.drain_filter(|_k, v| *v % 2 == 0);
+/// let iter = map.extract_if(|_k, v| *v % 2 == 0);
/// ```
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-pub struct DrainFilter<'a, K, V, F>
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+pub struct ExtractIf<'a, K, V, F>
where
F: FnMut(&K, &mut V) -> bool,
{
- base: base::DrainFilter<'a, K, V, F>,
+ base: base::ExtractIf<'a, K, V, F>,
}
/// A mutable iterator over the values of a `HashMap`.
@@ -2479,8 +2479,8 @@ where
}
}
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-impl<K, V, F> Iterator for DrainFilter<'_, K, V, F>
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+impl<K, V, F> Iterator for ExtractIf<'_, K, V, F>
where
F: FnMut(&K, &mut V) -> bool,
{
@@ -2496,16 +2496,16 @@ where
}
}
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-impl<K, V, F> FusedIterator for DrainFilter<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {}
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+impl<K, V, F> FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {}
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-impl<'a, K, V, F> fmt::Debug for DrainFilter<'a, K, V, F>
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+impl<'a, K, V, F> fmt::Debug for ExtractIf<'a, K, V, F>
where
F: FnMut(&K, &mut V) -> bool,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("DrainFilter").finish_non_exhaustive()
+ f.debug_struct("ExtractIf").finish_non_exhaustive()
}
}
@@ -2543,12 +2543,12 @@ impl<'a, K, V> Entry<'a, K, V> {
/// ```
/// use std::collections::HashMap;
///
- /// let mut map: HashMap<&str, String> = HashMap::new();
- /// let s = "hoho".to_string();
+ /// let mut map = HashMap::new();
+ /// let value = "hoho";
///
- /// map.entry("poneyland").or_insert_with(|| s);
+ /// map.entry("poneyland").or_insert_with(|| value);
///
- /// assert_eq!(map["poneyland"], "hoho".to_string());
+ /// assert_eq!(map["poneyland"], "hoho");
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs
index 6b89518e2..91a3776e7 100644
--- a/library/std/src/collections/hash/map/tests.rs
+++ b/library/std/src/collections/hash/map/tests.rs
@@ -944,7 +944,7 @@ fn test_raw_entry() {
}
}
-mod test_drain_filter {
+mod test_extract_if {
use super::*;
use crate::panic::{catch_unwind, AssertUnwindSafe};
@@ -968,7 +968,7 @@ mod test_drain_filter {
#[test]
fn empty() {
let mut map: HashMap<i32, i32> = HashMap::new();
- map.drain_filter(|_, _| unreachable!("there's nothing to decide on"));
+ map.extract_if(|_, _| unreachable!("there's nothing to decide on")).for_each(drop);
assert!(map.is_empty());
}
@@ -976,7 +976,7 @@ mod test_drain_filter {
fn consuming_nothing() {
let pairs = (0..3).map(|i| (i, i));
let mut map: HashMap<_, _> = pairs.collect();
- assert!(map.drain_filter(|_, _| false).eq_sorted(crate::iter::empty()));
+ assert!(map.extract_if(|_, _| false).eq_sorted(crate::iter::empty()));
assert_eq!(map.len(), 3);
}
@@ -984,7 +984,7 @@ mod test_drain_filter {
fn consuming_all() {
let pairs = (0..3).map(|i| (i, i));
let mut map: HashMap<_, _> = pairs.clone().collect();
- assert!(map.drain_filter(|_, _| true).eq_sorted(pairs));
+ assert!(map.extract_if(|_, _| true).eq_sorted(pairs));
assert!(map.is_empty());
}
@@ -993,7 +993,7 @@ mod test_drain_filter {
let pairs = (0..3).map(|i| (i, i));
let mut map: HashMap<_, _> = pairs.collect();
assert!(
- map.drain_filter(|_, v| {
+ map.extract_if(|_, v| {
*v += 6;
false
})
@@ -1008,7 +1008,7 @@ mod test_drain_filter {
let pairs = (0..3).map(|i| (i, i));
let mut map: HashMap<_, _> = pairs.collect();
assert!(
- map.drain_filter(|_, v| {
+ map.extract_if(|_, v| {
*v += 6;
true
})
@@ -1034,14 +1034,15 @@ mod test_drain_filter {
let mut map = (0..3).map(|i| (i, D)).collect::<HashMap<_, _>>();
catch_unwind(move || {
- drop(map.drain_filter(|_, _| {
+ map.extract_if(|_, _| {
PREDS.fetch_add(1, Ordering::SeqCst);
true
- }))
+ })
+ .for_each(drop)
})
.unwrap_err();
- assert_eq!(PREDS.load(Ordering::SeqCst), 3);
+ assert_eq!(PREDS.load(Ordering::SeqCst), 2);
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
}
@@ -1060,10 +1061,11 @@ mod test_drain_filter {
let mut map = (0..3).map(|i| (i, D)).collect::<HashMap<_, _>>();
catch_unwind(AssertUnwindSafe(|| {
- drop(map.drain_filter(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) {
+ map.extract_if(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) {
0 => true,
_ => panic!(),
- }))
+ })
+ .for_each(drop)
}))
.unwrap_err();
@@ -1088,7 +1090,7 @@ mod test_drain_filter {
let mut map = (0..3).map(|i| (i, D)).collect::<HashMap<_, _>>();
{
- let mut it = map.drain_filter(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) {
+ let mut it = map.extract_if(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) {
0 => true,
_ => panic!(),
});
diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs
index ac906e682..ec59634df 100644
--- a/library/std/src/collections/hash/set.rs
+++ b/library/std/src/collections/hash/set.rs
@@ -262,25 +262,24 @@ impl<T, S> HashSet<T, S> {
/// If the closure returns false, the value will remain in the list and will not be yielded
/// by the iterator.
///
- /// If the iterator is only partially consumed or not consumed at all, each of the remaining
- /// values will still be subjected to the closure and removed and dropped if it returns true.
+ /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
+ /// or the iteration short-circuits, then the remaining elements will be retained.
+ /// Use [`retain`] with a negated predicate if you do not need the returned iterator.
///
- /// It is unspecified how many more values will be subjected to the closure
- /// if a panic occurs in the closure, or if a panic occurs while dropping a value, or if the
- /// `DrainFilter` itself is leaked.
+ /// [`retain`]: HashSet::retain
///
/// # Examples
///
/// Splitting a set into even and odd values, reusing the original set:
///
/// ```
- /// #![feature(hash_drain_filter)]
+ /// #![feature(hash_extract_if)]
/// use std::collections::HashSet;
///
/// let mut set: HashSet<i32> = (0..8).collect();
- /// let drained: HashSet<i32> = set.drain_filter(|v| v % 2 == 0).collect();
+ /// let extracted: HashSet<i32> = set.extract_if(|v| v % 2 == 0).collect();
///
- /// let mut evens = drained.into_iter().collect::<Vec<_>>();
+ /// let mut evens = extracted.into_iter().collect::<Vec<_>>();
/// let mut odds = set.into_iter().collect::<Vec<_>>();
/// evens.sort();
/// odds.sort();
@@ -290,12 +289,12 @@ impl<T, S> HashSet<T, S> {
/// ```
#[inline]
#[rustc_lint_query_instability]
- #[unstable(feature = "hash_drain_filter", issue = "59618")]
- pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, T, F>
+ #[unstable(feature = "hash_extract_if", issue = "59618")]
+ pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, T, F>
where
F: FnMut(&T) -> bool,
{
- DrainFilter { base: self.base.drain_filter(pred) }
+ ExtractIf { base: self.base.extract_if(pred) }
}
/// Retains only the elements specified by the predicate.
@@ -868,7 +867,9 @@ where
/// Returns whether the value was newly inserted. That is:
///
/// - If the set did not previously contain this value, `true` is returned.
- /// - If the set already contained this value, `false` is returned.
+ /// - If the set already contained this value, `false` is returned,
+ /// and the set is not modified: original value is not replaced,
+ /// and the value passed as argument is dropped.
///
/// # Examples
///
@@ -1310,27 +1311,27 @@ pub struct Drain<'a, K: 'a> {
/// A draining, filtering iterator over the items of a `HashSet`.
///
-/// This `struct` is created by the [`drain_filter`] method on [`HashSet`].
+/// This `struct` is created by the [`extract_if`] method on [`HashSet`].
///
-/// [`drain_filter`]: HashSet::drain_filter
+/// [`extract_if`]: HashSet::extract_if
///
/// # Examples
///
/// ```
-/// #![feature(hash_drain_filter)]
+/// #![feature(hash_extract_if)]
///
/// use std::collections::HashSet;
///
/// let mut a = HashSet::from([1, 2, 3]);
///
-/// let mut drain_filtered = a.drain_filter(|v| v % 2 == 0);
+/// let mut extract_ifed = a.extract_if(|v| v % 2 == 0);
/// ```
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-pub struct DrainFilter<'a, K, F>
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+pub struct ExtractIf<'a, K, F>
where
F: FnMut(&K) -> bool,
{
- base: base::DrainFilter<'a, K, F>,
+ base: base::ExtractIf<'a, K, F>,
}
/// A lazy iterator producing elements in the intersection of `HashSet`s.
@@ -1576,8 +1577,8 @@ impl<K: fmt::Debug> fmt::Debug for Drain<'_, K> {
}
}
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-impl<K, F> Iterator for DrainFilter<'_, K, F>
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+impl<K, F> Iterator for ExtractIf<'_, K, F>
where
F: FnMut(&K) -> bool,
{
@@ -1593,16 +1594,16 @@ where
}
}
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-impl<K, F> FusedIterator for DrainFilter<'_, K, F> where F: FnMut(&K) -> bool {}
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+impl<K, F> FusedIterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool {}
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-impl<'a, K, F> fmt::Debug for DrainFilter<'a, K, F>
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+impl<'a, K, F> fmt::Debug for ExtractIf<'a, K, F>
where
F: FnMut(&K) -> bool,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("DrainFilter").finish_non_exhaustive()
+ f.debug_struct("ExtractIf").finish_non_exhaustive()
}
}
diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs
index 941a0450c..e0cd80b44 100644
--- a/library/std/src/collections/hash/set/tests.rs
+++ b/library/std/src/collections/hash/set/tests.rs
@@ -3,6 +3,7 @@ use super::HashSet;
use crate::panic::{catch_unwind, AssertUnwindSafe};
use crate::sync::atomic::{AtomicU32, Ordering};
+use crate::sync::Arc;
#[test]
fn test_zero_capacities() {
@@ -418,18 +419,18 @@ fn test_retain() {
}
#[test]
-fn test_drain_filter() {
+fn test_extract_if() {
let mut x: HashSet<_> = [1].iter().copied().collect();
let mut y: HashSet<_> = [1].iter().copied().collect();
- x.drain_filter(|_| true);
- y.drain_filter(|_| false);
+ x.extract_if(|_| true).for_each(drop);
+ y.extract_if(|_| false).for_each(drop);
assert_eq!(x.len(), 0);
assert_eq!(y.len(), 1);
}
#[test]
-fn test_drain_filter_drop_panic_leak() {
+fn test_extract_if_drop_panic_leak() {
static PREDS: AtomicU32 = AtomicU32::new(0);
static DROPS: AtomicU32 = AtomicU32::new(0);
@@ -446,19 +447,20 @@ fn test_drain_filter_drop_panic_leak() {
let mut set = (0..3).map(|i| D(i)).collect::<HashSet<_>>();
catch_unwind(move || {
- drop(set.drain_filter(|_| {
+ set.extract_if(|_| {
PREDS.fetch_add(1, Ordering::SeqCst);
true
- }))
+ })
+ .for_each(drop)
})
.ok();
- assert_eq!(PREDS.load(Ordering::SeqCst), 3);
+ assert_eq!(PREDS.load(Ordering::SeqCst), 2);
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
}
#[test]
-fn test_drain_filter_pred_panic_leak() {
+fn test_extract_if_pred_panic_leak() {
static PREDS: AtomicU32 = AtomicU32::new(0);
static DROPS: AtomicU32 = AtomicU32::new(0);
@@ -473,10 +475,11 @@ fn test_drain_filter_pred_panic_leak() {
let mut set: HashSet<_> = (0..3).map(|_| D).collect();
catch_unwind(AssertUnwindSafe(|| {
- drop(set.drain_filter(|_| match PREDS.fetch_add(1, Ordering::SeqCst) {
+ set.extract_if(|_| match PREDS.fetch_add(1, Ordering::SeqCst) {
0 => true,
_ => panic!(),
- }))
+ })
+ .for_each(drop)
}))
.ok();
@@ -502,3 +505,22 @@ fn const_with_hasher() {
const X: HashSet<(), ()> = HashSet::with_hasher(());
assert_eq!(X.len(), 0);
}
+
+#[test]
+fn test_insert_does_not_overwrite_the_value() {
+ let first_value = Arc::new(17);
+ let second_value = Arc::new(17);
+
+ let mut set = HashSet::new();
+ let inserted = set.insert(first_value.clone());
+ assert!(inserted);
+
+ let inserted = set.insert(second_value);
+ assert!(!inserted);
+
+ assert!(
+ Arc::ptr_eq(set.iter().next().unwrap(), &first_value),
+ "Insert must not overwrite the value, so the contained value pointer \
+ must be the same as first value pointer we inserted"
+ );
+}
diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index 408244b2c..bed90418b 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -528,7 +528,7 @@ impl f32 {
/// The positive difference of two numbers.
///
- /// * If `self <= other`: `0:0`
+ /// * If `self <= other`: `0.0`
/// * Else: `self - other`
///
/// # Examples
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index 6782b861f..e72de05ca 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -530,7 +530,7 @@ impl f64 {
/// The positive difference of two numbers.
///
- /// * If `self <= other`: `0:0`
+ /// * If `self <= other`: `0.0`
/// * Else: `self - other`
///
/// # Examples
diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs
index d987bf69b..3ddb87487 100644
--- a/library/std/src/ffi/mod.rs
+++ b/library/std/src/ffi/mod.rs
@@ -127,6 +127,14 @@
//! trait, which provides a [`from_wide`] method to convert a native Windows
//! string (without the terminating nul character) to an [`OsString`].
//!
+//! ## On all platforms
+//!
+//! On all platforms, [`OsStr`] consists of a sequence of bytes that is encoded as a superset of
+//! UTF-8; see [`OsString`] for more details on its encoding on different platforms.
+//!
+//! For limited, inexpensive conversions from and to bytes, see [`OsStr::as_os_str_bytes`] and
+//! [`OsStr::from_os_str_bytes_unchecked`].
+//!
//! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value
//! [Unicode code point]: https://www.unicode.org/glossary/#code_point
//! [`env::set_var()`]: crate::env::set_var "env::set_var"
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 5c0541d3c..e7bad9d54 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -667,6 +667,51 @@ impl OsStr {
s.as_ref()
}
+ /// Converts a slice of bytes to an OS string slice without checking that the string contains
+ /// valid `OsStr`-encoded data.
+ ///
+ /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8.
+ /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit
+ /// ASCII.
+ ///
+ /// See the [module's toplevel documentation about conversions][conversions] for safe,
+ /// cross-platform [conversions] from/to native representations.
+ ///
+ /// # Safety
+ ///
+ /// As the encoding is unspecified, callers must pass in bytes that originated as a mixture of
+ /// validated UTF-8 and bytes from [`OsStr::as_os_str_bytes`] from within the same rust version
+ /// built for the same target platform. For example, reconstructing an `OsStr` from bytes sent
+ /// over the network or stored in a file will likely violate these safety rules.
+ ///
+ /// Due to the encoding being self-synchronizing, the bytes from [`OsStr::as_os_str_bytes`] can be
+ /// split either immediately before or immediately after any valid non-empty UTF-8 substring.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(os_str_bytes)]
+ ///
+ /// use std::ffi::OsStr;
+ ///
+ /// let os_str = OsStr::new("Mary had a little lamb");
+ /// let bytes = os_str.as_os_str_bytes();
+ /// let words = bytes.split(|b| *b == b' ');
+ /// let words: Vec<&OsStr> = words.map(|word| {
+ /// // SAFETY:
+ /// // - Each `word` only contains content that originated from `OsStr::as_os_str_bytes`
+ /// // - Only split with ASCII whitespace which is a non-empty UTF-8 substring
+ /// unsafe { OsStr::from_os_str_bytes_unchecked(word) }
+ /// }).collect();
+ /// ```
+ ///
+ /// [conversions]: super#conversions
+ #[inline]
+ #[unstable(feature = "os_str_bytes", issue = "111544")]
+ pub unsafe fn from_os_str_bytes_unchecked(bytes: &[u8]) -> &Self {
+ Self::from_inner(Slice::from_os_str_bytes_unchecked(bytes))
+ }
+
#[inline]
fn from_inner(inner: &Slice) -> &OsStr {
// SAFETY: OsStr is just a wrapper of Slice,
@@ -700,7 +745,7 @@ impl OsStr {
without modifying the original"]
#[inline]
pub fn to_str(&self) -> Option<&str> {
- self.inner.to_str()
+ self.inner.to_str().ok()
}
/// Converts an `OsStr` to a <code>[Cow]<[str]></code>.
@@ -837,13 +882,24 @@ impl OsStr {
OsString { inner: Buf::from_box(boxed) }
}
- /// Gets the underlying byte representation.
+ /// Converts an OS string slice to a byte slice. To convert the byte slice back into an OS
+ /// string slice, use the [`OsStr::from_os_str_bytes_unchecked`] function.
+ ///
+ /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8.
+ /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit
+ /// ASCII.
+ ///
+ /// Note: As the encoding is unspecified, any sub-slice of bytes that is not valid UTF-8 should
+ /// be treated as opaque and only comparable within the same rust version built for the same
+ /// target platform. For example, sending the slice over the network or storing it in a file
+ /// will likely result in incompatible byte slices. See [`OsString`] for more encoding details
+ /// and [`std::ffi`] for platform-specific, specified conversions.
///
- /// Note: it is *crucial* that this API is not externally public, to avoid
- /// revealing the internal, platform-specific encodings.
+ /// [`std::ffi`]: crate::ffi
#[inline]
- pub(crate) fn bytes(&self) -> &[u8] {
- unsafe { &*(&self.inner as *const _ as *const [u8]) }
+ #[unstable(feature = "os_str_bytes", issue = "111544")]
+ pub fn as_os_str_bytes(&self) -> &[u8] {
+ self.inner.as_os_str_bytes()
}
/// Converts this string to its ASCII lower case equivalent in-place.
@@ -1109,6 +1165,24 @@ impl<'a> From<Cow<'a, OsStr>> for OsString {
}
}
+#[stable(feature = "str_tryfrom_osstr_impl", since = "1.72.0")]
+impl<'a> TryFrom<&'a OsStr> for &'a str {
+ type Error = crate::str::Utf8Error;
+
+ /// Tries to convert an `&OsStr` to a `&str`.
+ ///
+ /// ```
+ /// use std::ffi::OsStr;
+ ///
+ /// let os_str = OsStr::new("foo");
+ /// let as_str = <&str>::try_from(os_str).unwrap();
+ /// assert_eq!(as_str, "foo");
+ /// ```
+ fn try_from(value: &'a OsStr) -> Result<Self, Self::Error> {
+ value.inner.to_str()
+ }
+}
+
#[stable(feature = "box_default_extra", since = "1.17.0")]
impl Default for Box<OsStr> {
#[inline]
@@ -1131,7 +1205,7 @@ impl Default for &OsStr {
impl PartialEq for OsStr {
#[inline]
fn eq(&self, other: &OsStr) -> bool {
- self.bytes().eq(other.bytes())
+ self.as_os_str_bytes().eq(other.as_os_str_bytes())
}
}
@@ -1158,23 +1232,23 @@ impl Eq for OsStr {}
impl PartialOrd for OsStr {
#[inline]
fn partial_cmp(&self, other: &OsStr) -> Option<cmp::Ordering> {
- self.bytes().partial_cmp(other.bytes())
+ self.as_os_str_bytes().partial_cmp(other.as_os_str_bytes())
}
#[inline]
fn lt(&self, other: &OsStr) -> bool {
- self.bytes().lt(other.bytes())
+ self.as_os_str_bytes().lt(other.as_os_str_bytes())
}
#[inline]
fn le(&self, other: &OsStr) -> bool {
- self.bytes().le(other.bytes())
+ self.as_os_str_bytes().le(other.as_os_str_bytes())
}
#[inline]
fn gt(&self, other: &OsStr) -> bool {
- self.bytes().gt(other.bytes())
+ self.as_os_str_bytes().gt(other.as_os_str_bytes())
}
#[inline]
fn ge(&self, other: &OsStr) -> bool {
- self.bytes().ge(other.bytes())
+ self.as_os_str_bytes().ge(other.as_os_str_bytes())
}
}
@@ -1193,7 +1267,7 @@ impl PartialOrd<str> for OsStr {
impl Ord for OsStr {
#[inline]
fn cmp(&self, other: &OsStr) -> cmp::Ordering {
- self.bytes().cmp(other.bytes())
+ self.as_os_str_bytes().cmp(other.as_os_str_bytes())
}
}
@@ -1243,7 +1317,7 @@ impl_cmp!(Cow<'a, OsStr>, OsString);
impl Hash for OsStr {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
- self.bytes().hash(state)
+ self.as_os_str_bytes().hash(state)
}
}
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 89dfdfafd..c2d82169d 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -1755,8 +1755,14 @@ impl DirEntry {
self.0.file_type().map(FileType)
}
- /// Returns the bare file name of this directory entry without any other
- /// leading path component.
+ /// Returns the file name of this directory entry without any
+ /// leading path component(s).
+ ///
+ /// As an example,
+ /// the output of the function will result in "foo" for all the following paths:
+ /// - "./foo"
+ /// - "/the/foo"
+ /// - "../../foo"
///
/// # Examples
///
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index e2480bcbb..9ff01b9c3 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -1640,6 +1640,10 @@ fn test_file_times() {
use crate::os::ios::fs::FileTimesExt;
#[cfg(target_os = "macos")]
use crate::os::macos::fs::FileTimesExt;
+ #[cfg(target_os = "tvos")]
+ use crate::os::tvos::fs::FileTimesExt;
+ #[cfg(target_os = "tvos")]
+ use crate::os::tvos::fs::FileTimesExt;
#[cfg(target_os = "watchos")]
use crate::os::watchos::fs::FileTimesExt;
#[cfg(windows)]
@@ -1651,9 +1655,21 @@ fn test_file_times() {
let accessed = SystemTime::UNIX_EPOCH + Duration::from_secs(12345);
let modified = SystemTime::UNIX_EPOCH + Duration::from_secs(54321);
times = times.set_accessed(accessed).set_modified(modified);
- #[cfg(any(windows, target_os = "macos", target_os = "ios", target_os = "watchos"))]
+ #[cfg(any(
+ windows,
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "watchos",
+ target_os = "tvos",
+ ))]
let created = SystemTime::UNIX_EPOCH + Duration::from_secs(32123);
- #[cfg(any(windows, target_os = "macos", target_os = "ios", target_os = "watchos"))]
+ #[cfg(any(
+ windows,
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "watchos",
+ target_os = "tvos",
+ ))]
{
times = times.set_created(created);
}
@@ -1678,7 +1694,13 @@ fn test_file_times() {
let metadata = file.metadata().unwrap();
assert_eq!(metadata.accessed().unwrap(), accessed);
assert_eq!(metadata.modified().unwrap(), modified);
- #[cfg(any(windows, target_os = "macos", target_os = "ios", target_os = "watchos"))]
+ #[cfg(any(
+ windows,
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "watchos",
+ target_os = "tvos",
+ ))]
{
assert_eq!(metadata.created().unwrap(), created);
}
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index 4f339a18a..7097dfef8 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -47,13 +47,13 @@ use buffer::Buffer;
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct BufReader<R> {
- inner: R,
+pub struct BufReader<R: ?Sized> {
buf: Buffer,
+ inner: R,
}
impl<R: Read> BufReader<R> {
- /// Creates a new `BufReader<R>` with a default buffer capacity. The default is currently 8 KB,
+ /// Creates a new `BufReader<R>` with a default buffer capacity. The default is currently 8 KiB,
/// but may change in the future.
///
/// # Examples
@@ -95,7 +95,7 @@ impl<R: Read> BufReader<R> {
}
}
-impl<R> BufReader<R> {
+impl<R: ?Sized> BufReader<R> {
/// Gets a reference to the underlying reader.
///
/// It is inadvisable to directly read from the underlying reader.
@@ -213,26 +213,29 @@ impl<R> BufReader<R> {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn into_inner(self) -> R {
+ pub fn into_inner(self) -> R
+ where
+ R: Sized,
+ {
self.inner
}
/// Invalidates all data in the internal buffer.
#[inline]
- fn discard_buffer(&mut self) {
+ pub(in crate::io) fn discard_buffer(&mut self) {
self.buf.discard_buffer()
}
}
// This is only used by a test which asserts that the initialization-tracking is correct.
#[cfg(test)]
-impl<R> BufReader<R> {
+impl<R: ?Sized> BufReader<R> {
pub fn initialized(&self) -> usize {
self.buf.initialized()
}
}
-impl<R: Seek> BufReader<R> {
+impl<R: ?Sized + Seek> BufReader<R> {
/// Seeks relative to the current position. If the new position lies within the buffer,
/// the buffer will not be flushed, allowing for more efficient seeks.
/// This method does not return the location of the underlying reader, so the caller
@@ -257,7 +260,7 @@ impl<R: Seek> BufReader<R> {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<R: Read> Read for BufReader<R> {
+impl<R: ?Sized + Read> Read for BufReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
// If we don't have any buffered data and we're doing a massive read
// (larger than our internal buffer), bypass our internal buffer
@@ -371,7 +374,7 @@ impl<R: Read> Read for BufReader<R> {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<R: Read> BufRead for BufReader<R> {
+impl<R: ?Sized + Read> BufRead for BufReader<R> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
self.buf.fill_buf(&mut self.inner)
}
@@ -384,11 +387,11 @@ impl<R: Read> BufRead for BufReader<R> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<R> fmt::Debug for BufReader<R>
where
- R: fmt::Debug,
+ R: ?Sized + fmt::Debug,
{
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("BufReader")
- .field("reader", &self.inner)
+ .field("reader", &&self.inner)
.field(
"buffer",
&format_args!("{}/{}", self.buf.filled() - self.buf.pos(), self.capacity()),
@@ -398,7 +401,7 @@ where
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<R: Seek> Seek for BufReader<R> {
+impl<R: ?Sized + Seek> Seek for BufReader<R> {
/// Seek to an offset, in bytes, in the underlying reader.
///
/// The position used for seeking with <code>[SeekFrom::Current]\(_)</code> is the
@@ -491,7 +494,7 @@ impl<R: Seek> Seek for BufReader<R> {
}
}
-impl<T> SizeHint for BufReader<T> {
+impl<T: ?Sized> SizeHint for BufReader<T> {
#[inline]
fn lower_bound(&self) -> usize {
SizeHint::lower_bound(self.get_ref()) + self.buffer().len()
diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs
index 14c455d4f..0f04f2911 100644
--- a/library/std/src/io/buffered/bufwriter.rs
+++ b/library/std/src/io/buffered/bufwriter.rs
@@ -67,8 +67,7 @@ use crate::ptr;
/// [`TcpStream`]: crate::net::TcpStream
/// [`flush`]: BufWriter::flush
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct BufWriter<W: Write> {
- inner: W,
+pub struct BufWriter<W: ?Sized + Write> {
// The buffer. Avoid using this like a normal `Vec` in common code paths.
// That is, don't use `buf.push`, `buf.extend_from_slice`, or any other
// methods that require bounds checking or the like. This makes an enormous
@@ -78,10 +77,11 @@ pub struct BufWriter<W: Write> {
// write the buffered data a second time in BufWriter's destructor. This
// flag tells the Drop impl if it should skip the flush.
panicked: bool,
+ inner: W,
}
impl<W: Write> BufWriter<W> {
- /// Creates a new `BufWriter<W>` with a default buffer capacity. The default is currently 8 KB,
+ /// Creates a new `BufWriter<W>` with a default buffer capacity. The default is currently 8 KiB,
/// but may change in the future.
///
/// # Examples
@@ -115,6 +115,69 @@ impl<W: Write> BufWriter<W> {
BufWriter { inner, buf: Vec::with_capacity(capacity), panicked: false }
}
+ /// Unwraps this `BufWriter<W>`, returning the underlying writer.
+ ///
+ /// The buffer is written out before returning the writer.
+ ///
+ /// # Errors
+ ///
+ /// An [`Err`] will be returned if an error occurs while flushing the buffer.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::BufWriter;
+ /// use std::net::TcpStream;
+ ///
+ /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+ ///
+ /// // unwrap the TcpStream and flush the buffer
+ /// let stream = buffer.into_inner().unwrap();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
+ match self.flush_buf() {
+ Err(e) => Err(IntoInnerError::new(self, e)),
+ Ok(()) => Ok(self.into_parts().0),
+ }
+ }
+
+ /// Disassembles this `BufWriter<W>`, returning the underlying writer, and any buffered but
+ /// unwritten data.
+ ///
+ /// If the underlying writer panicked, it is not known what portion of the data was written.
+ /// In this case, we return `WriterPanicked` for the buffered data (from which the buffer
+ /// contents can still be recovered).
+ ///
+ /// `into_parts` makes no attempt to flush data and cannot fail.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::{BufWriter, Write};
+ ///
+ /// let mut buffer = [0u8; 10];
+ /// let mut stream = BufWriter::new(buffer.as_mut());
+ /// write!(stream, "too much data").unwrap();
+ /// stream.flush().expect_err("it doesn't fit");
+ /// let (recovered_writer, buffered_data) = stream.into_parts();
+ /// assert_eq!(recovered_writer.len(), 0);
+ /// assert_eq!(&buffered_data.unwrap(), b"ata");
+ /// ```
+ #[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
+ pub fn into_parts(mut self) -> (W, Result<Vec<u8>, WriterPanicked>) {
+ let buf = mem::take(&mut self.buf);
+ let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) };
+
+ // SAFETY: forget(self) prevents double dropping inner
+ let inner = unsafe { ptr::read(&self.inner) };
+ mem::forget(self);
+
+ (inner, buf)
+ }
+}
+
+impl<W: ?Sized + Write> BufWriter<W> {
/// Send data in our local buffer into the inner writer, looping as
/// necessary until either it's all been sent or an error occurs.
///
@@ -284,67 +347,6 @@ impl<W: Write> BufWriter<W> {
self.buf.capacity()
}
- /// Unwraps this `BufWriter<W>`, returning the underlying writer.
- ///
- /// The buffer is written out before returning the writer.
- ///
- /// # Errors
- ///
- /// An [`Err`] will be returned if an error occurs while flushing the buffer.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::io::BufWriter;
- /// use std::net::TcpStream;
- ///
- /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
- ///
- /// // unwrap the TcpStream and flush the buffer
- /// let stream = buffer.into_inner().unwrap();
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
- match self.flush_buf() {
- Err(e) => Err(IntoInnerError::new(self, e)),
- Ok(()) => Ok(self.into_parts().0),
- }
- }
-
- /// Disassembles this `BufWriter<W>`, returning the underlying writer, and any buffered but
- /// unwritten data.
- ///
- /// If the underlying writer panicked, it is not known what portion of the data was written.
- /// In this case, we return `WriterPanicked` for the buffered data (from which the buffer
- /// contents can still be recovered).
- ///
- /// `into_parts` makes no attempt to flush data and cannot fail.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::io::{BufWriter, Write};
- ///
- /// let mut buffer = [0u8; 10];
- /// let mut stream = BufWriter::new(buffer.as_mut());
- /// write!(stream, "too much data").unwrap();
- /// stream.flush().expect_err("it doesn't fit");
- /// let (recovered_writer, buffered_data) = stream.into_parts();
- /// assert_eq!(recovered_writer.len(), 0);
- /// assert_eq!(&buffered_data.unwrap(), b"ata");
- /// ```
- #[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
- pub fn into_parts(mut self) -> (W, Result<Vec<u8>, WriterPanicked>) {
- let buf = mem::take(&mut self.buf);
- let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) };
-
- // SAFETY: forget(self) prevents double dropping inner
- let inner = unsafe { ptr::read(&self.inner) };
- mem::forget(self);
-
- (inner, buf)
- }
-
// Ensure this function does not get inlined into `write`, so that it
// remains inlineable and its common path remains as short as possible.
// If this function ends up being called frequently relative to `write`,
@@ -511,7 +513,7 @@ impl fmt::Debug for WriterPanicked {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> Write for BufWriter<W> {
+impl<W: ?Sized + Write> Write for BufWriter<W> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
// Use < instead of <= to avoid a needless trip through the buffer in some cases.
@@ -640,20 +642,20 @@ impl<W: Write> Write for BufWriter<W> {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> fmt::Debug for BufWriter<W>
+impl<W: ?Sized + Write> fmt::Debug for BufWriter<W>
where
W: fmt::Debug,
{
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("BufWriter")
- .field("writer", &self.inner)
+ .field("writer", &&self.inner)
.field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity()))
.finish()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write + Seek> Seek for BufWriter<W> {
+impl<W: ?Sized + Write + Seek> Seek for BufWriter<W> {
/// Seek to the offset, in bytes, in the underlying writer.
///
/// Seeking always writes out the internal buffer before seeking.
@@ -664,7 +666,7 @@ impl<W: Write + Seek> Seek for BufWriter<W> {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> Drop for BufWriter<W> {
+impl<W: ?Sized + Write> Drop for BufWriter<W> {
fn drop(&mut self) {
if !self.panicked {
// dtors should not panic, so we ignore a failed flush
diff --git a/library/std/src/io/buffered/linewriter.rs b/library/std/src/io/buffered/linewriter.rs
index a26a4ab33..3d4ae7041 100644
--- a/library/std/src/io/buffered/linewriter.rs
+++ b/library/std/src/io/buffered/linewriter.rs
@@ -64,7 +64,7 @@ use crate::io::{self, buffered::LineWriterShim, BufWriter, IntoInnerError, IoSli
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct LineWriter<W: Write> {
+pub struct LineWriter<W: ?Sized + Write> {
inner: BufWriter<W>,
}
@@ -109,27 +109,6 @@ impl<W: Write> LineWriter<W> {
LineWriter { inner: BufWriter::with_capacity(capacity, inner) }
}
- /// Gets a reference to the underlying writer.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::fs::File;
- /// use std::io::LineWriter;
- ///
- /// fn main() -> std::io::Result<()> {
- /// let file = File::create("poem.txt")?;
- /// let file = LineWriter::new(file);
- ///
- /// let reference = file.get_ref();
- /// Ok(())
- /// }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn get_ref(&self) -> &W {
- self.inner.get_ref()
- }
-
/// Gets a mutable reference to the underlying writer.
///
/// Caution must be taken when calling methods on the mutable reference
@@ -184,8 +163,31 @@ impl<W: Write> LineWriter<W> {
}
}
+impl<W: ?Sized + Write> LineWriter<W> {
+ /// Gets a reference to the underlying writer.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::io::LineWriter;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let file = File::create("poem.txt")?;
+ /// let file = LineWriter::new(file);
+ ///
+ /// let reference = file.get_ref();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn get_ref(&self) -> &W {
+ self.inner.get_ref()
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> Write for LineWriter<W> {
+impl<W: ?Sized + Write> Write for LineWriter<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
LineWriterShim::new(&mut self.inner).write(buf)
}
@@ -216,7 +218,7 @@ impl<W: Write> Write for LineWriter<W> {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> fmt::Debug for LineWriter<W>
+impl<W: ?Sized + Write> fmt::Debug for LineWriter<W>
where
W: fmt::Debug,
{
diff --git a/library/std/src/io/buffered/linewritershim.rs b/library/std/src/io/buffered/linewritershim.rs
index 0175d2693..f2a55da05 100644
--- a/library/std/src/io/buffered/linewritershim.rs
+++ b/library/std/src/io/buffered/linewritershim.rs
@@ -11,11 +11,11 @@ use crate::sys_common::memchr;
/// `BufWriters` to be temporarily given line-buffering logic; this is what
/// enables Stdout to be alternately in line-buffered or block-buffered mode.
#[derive(Debug)]
-pub struct LineWriterShim<'a, W: Write> {
+pub struct LineWriterShim<'a, W: ?Sized + Write> {
buffer: &'a mut BufWriter<W>,
}
-impl<'a, W: Write> LineWriterShim<'a, W> {
+impl<'a, W: ?Sized + Write> LineWriterShim<'a, W> {
pub fn new(buffer: &'a mut BufWriter<W>) -> Self {
Self { buffer }
}
@@ -49,7 +49,7 @@ impl<'a, W: Write> LineWriterShim<'a, W> {
}
}
-impl<'a, W: Write> Write for LineWriterShim<'a, W> {
+impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> {
/// Write some data into this BufReader with line buffering. This means
/// that, if any newlines are present in the data, the data up to the last
/// newline is sent directly to the underlying writer, and data after it
diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs
index 1d9d93f5b..ef1f4031e 100644
--- a/library/std/src/io/copy.rs
+++ b/library/std/src/io/copy.rs
@@ -1,6 +1,9 @@
-use super::{BorrowedBuf, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE};
+use super::{BorrowedBuf, BufReader, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE};
use crate::mem::MaybeUninit;
+#[cfg(test)]
+mod tests;
+
/// Copies the entire contents of a reader into a writer.
///
/// This function will continuously read data from `reader` and then
@@ -71,32 +74,113 @@ where
R: Read,
W: Write,
{
- BufferedCopySpec::copy_to(reader, writer)
+ let read_buf = BufferedReaderSpec::buffer_size(reader);
+ let write_buf = BufferedWriterSpec::buffer_size(writer);
+
+ if read_buf >= DEFAULT_BUF_SIZE && read_buf >= write_buf {
+ return BufferedReaderSpec::copy_to(reader, writer);
+ }
+
+ BufferedWriterSpec::copy_from(writer, reader)
+}
+
+/// Specialization of the read-write loop that reuses the internal
+/// buffer of a BufReader. If there's no buffer then the writer side
+/// should be used intead.
+trait BufferedReaderSpec {
+ fn buffer_size(&self) -> usize;
+
+ fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result<u64>;
+}
+
+impl<T> BufferedReaderSpec for T
+where
+ Self: Read,
+ T: ?Sized,
+{
+ #[inline]
+ default fn buffer_size(&self) -> usize {
+ 0
+ }
+
+ default fn copy_to(&mut self, _to: &mut (impl Write + ?Sized)) -> Result<u64> {
+ unimplemented!("only called from specializations");
+ }
+}
+
+impl<I> BufferedReaderSpec for BufReader<I>
+where
+ Self: Read,
+ I: ?Sized,
+{
+ fn buffer_size(&self) -> usize {
+ self.capacity()
+ }
+
+ fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result<u64> {
+ let mut len = 0;
+
+ loop {
+ // Hack: this relies on `impl Read for BufReader` always calling fill_buf
+ // if the buffer is empty, even for empty slices.
+ // It can't be called directly here since specialization prevents us
+ // from adding I: Read
+ match self.read(&mut []) {
+ Ok(_) => {}
+ Err(e) if e.kind() == ErrorKind::Interrupted => continue,
+ Err(e) => return Err(e),
+ }
+ let buf = self.buffer();
+ if self.buffer().len() == 0 {
+ return Ok(len);
+ }
+
+ // In case the writer side is a BufWriter then its write_all
+ // implements an optimization that passes through large
+ // buffers to the underlying writer. That code path is #[cold]
+ // but we're still avoiding redundant memcopies when doing
+ // a copy between buffered inputs and outputs.
+ to.write_all(buf)?;
+ len += buf.len() as u64;
+ self.discard_buffer();
+ }
+ }
}
/// Specialization of the read-write loop that either uses a stack buffer
/// or reuses the internal buffer of a BufWriter
-trait BufferedCopySpec: Write {
- fn copy_to<R: Read + ?Sized>(reader: &mut R, writer: &mut Self) -> Result<u64>;
+trait BufferedWriterSpec: Write {
+ fn buffer_size(&self) -> usize;
+
+ fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64>;
}
-impl<W: Write + ?Sized> BufferedCopySpec for W {
- default fn copy_to<R: Read + ?Sized>(reader: &mut R, writer: &mut Self) -> Result<u64> {
- stack_buffer_copy(reader, writer)
+impl<W: Write + ?Sized> BufferedWriterSpec for W {
+ #[inline]
+ default fn buffer_size(&self) -> usize {
+ 0
+ }
+
+ default fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64> {
+ stack_buffer_copy(reader, self)
}
}
-impl<I: Write> BufferedCopySpec for BufWriter<I> {
- fn copy_to<R: Read + ?Sized>(reader: &mut R, writer: &mut Self) -> Result<u64> {
- if writer.capacity() < DEFAULT_BUF_SIZE {
- return stack_buffer_copy(reader, writer);
+impl<I: Write + ?Sized> BufferedWriterSpec for BufWriter<I> {
+ fn buffer_size(&self) -> usize {
+ self.capacity()
+ }
+
+ fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64> {
+ if self.capacity() < DEFAULT_BUF_SIZE {
+ return stack_buffer_copy(reader, self);
}
let mut len = 0;
let mut init = 0;
loop {
- let buf = writer.buffer_mut();
+ let buf = self.buffer_mut();
let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into();
unsafe {
@@ -127,7 +211,7 @@ impl<I: Write> BufferedCopySpec for BufWriter<I> {
Err(e) => return Err(e),
}
} else {
- writer.flush_buf()?;
+ self.flush_buf()?;
init = 0;
}
}
diff --git a/library/std/src/io/copy/tests.rs b/library/std/src/io/copy/tests.rs
new file mode 100644
index 000000000..8c816af15
--- /dev/null
+++ b/library/std/src/io/copy/tests.rs
@@ -0,0 +1,108 @@
+use crate::cmp::{max, min};
+use crate::io::*;
+
+#[test]
+fn copy_copies() {
+ let mut r = repeat(0).take(4);
+ let mut w = sink();
+ assert_eq!(copy(&mut r, &mut w).unwrap(), 4);
+
+ let mut r = repeat(0).take(1 << 17);
+ assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17);
+}
+
+struct ShortReader {
+ cap: usize,
+ read_size: usize,
+ observed_buffer: usize,
+}
+
+impl Read for ShortReader {
+ fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
+ let bytes = min(self.cap, self.read_size);
+ self.cap -= bytes;
+ self.observed_buffer = max(self.observed_buffer, buf.len());
+ Ok(bytes)
+ }
+}
+
+struct WriteObserver {
+ observed_buffer: usize,
+}
+
+impl Write for WriteObserver {
+ fn write(&mut self, buf: &[u8]) -> Result<usize> {
+ self.observed_buffer = max(self.observed_buffer, buf.len());
+ Ok(buf.len())
+ }
+
+ fn flush(&mut self) -> Result<()> {
+ Ok(())
+ }
+}
+
+#[test]
+fn copy_specializes_bufwriter() {
+ let cap = 117 * 1024;
+ let buf_sz = 16 * 1024;
+ let mut r = ShortReader { cap, observed_buffer: 0, read_size: 1337 };
+ let mut w = BufWriter::with_capacity(buf_sz, WriteObserver { observed_buffer: 0 });
+ assert_eq!(
+ copy(&mut r, &mut w).unwrap(),
+ cap as u64,
+ "expected the whole capacity to be copied"
+ );
+ assert_eq!(r.observed_buffer, buf_sz, "expected a large buffer to be provided to the reader");
+ assert!(w.get_mut().observed_buffer > DEFAULT_BUF_SIZE, "expected coalesced writes");
+}
+
+#[test]
+fn copy_specializes_bufreader() {
+ let mut source = vec![0; 768 * 1024];
+ source[1] = 42;
+ let mut buffered = BufReader::with_capacity(256 * 1024, Cursor::new(&mut source));
+
+ let mut sink = Vec::new();
+ assert_eq!(crate::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64);
+ assert_eq!(source.as_slice(), sink.as_slice());
+
+ let buf_sz = 71 * 1024;
+ assert!(buf_sz > DEFAULT_BUF_SIZE, "test precondition");
+
+ let mut buffered = BufReader::with_capacity(buf_sz, Cursor::new(&mut source));
+ let mut sink = WriteObserver { observed_buffer: 0 };
+ assert_eq!(crate::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64);
+ assert_eq!(
+ sink.observed_buffer, buf_sz,
+ "expected a large buffer to be provided to the writer"
+ );
+}
+
+#[cfg(unix)]
+mod io_benches {
+ use crate::fs::File;
+ use crate::fs::OpenOptions;
+ use crate::io::prelude::*;
+ use crate::io::BufReader;
+
+ use test::Bencher;
+
+ #[bench]
+ fn bench_copy_buf_reader(b: &mut Bencher) {
+ let mut file_in = File::open("/dev/zero").expect("opening /dev/zero failed");
+ // use dyn to avoid specializations unrelated to readbuf
+ let dyn_in = &mut file_in as &mut dyn Read;
+ let mut reader = BufReader::with_capacity(256 * 1024, dyn_in.take(0));
+ let mut writer =
+ OpenOptions::new().write(true).open("/dev/null").expect("opening /dev/null failed");
+
+ const BYTES: u64 = 1024 * 1024;
+
+ b.bytes = BYTES;
+
+ b.iter(|| {
+ reader.get_mut().set_limit(BYTES);
+ crate::io::copy(&mut reader, &mut writer).unwrap()
+ });
+ }
+}
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 8a007d095..71d91f213 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -1416,17 +1416,18 @@ pub trait Write {
///
/// This function will attempt to write the entire contents of `buf`, but
/// the entire write might not succeed, or the write may also generate an
- /// error. A call to `write` represents *at most one* attempt to write to
+ /// error. Typically, a call to `write` represents one attempt to write to
/// any wrapped object.
///
/// Calls to `write` are not guaranteed to block waiting for data to be
/// written, and a write which would otherwise block can be indicated through
/// an [`Err`] variant.
///
- /// If the return value is [`Ok(n)`] then it must be guaranteed that
- /// `n <= buf.len()`. A return value of `0` typically means that the
- /// underlying object is no longer able to accept bytes and will likely not
- /// be able to in the future as well, or that the buffer provided is empty.
+ /// If this method consumed `n > 0` bytes of `buf` it must return [`Ok(n)`].
+ /// If the return value is `Ok(n)` then `n` must satisfy `n <= buf.len()`.
+ /// A return value of `Ok(0)` typically means that the underlying object is
+ /// no longer able to accept bytes and will likely not be able to in the
+ /// future as well, or that the buffer provided is empty.
///
/// # Errors
///
@@ -2754,7 +2755,7 @@ trait SizeHint {
}
}
-impl<T> SizeHint for T {
+impl<T: ?Sized> SizeHint for T {
#[inline]
default fn lower_bound(&self) -> usize {
0
diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs
index ce5e2c9da..1baa94e64 100644
--- a/library/std/src/io/util/tests.rs
+++ b/library/std/src/io/util/tests.rs
@@ -1,68 +1,9 @@
-use crate::cmp::{max, min};
use crate::io::prelude::*;
-use crate::io::{
- copy, empty, repeat, sink, BorrowedBuf, BufWriter, Empty, Repeat, Result, SeekFrom, Sink,
- DEFAULT_BUF_SIZE,
-};
+use crate::io::{empty, repeat, sink, BorrowedBuf, Empty, Repeat, SeekFrom, Sink};
use crate::mem::MaybeUninit;
#[test]
-fn copy_copies() {
- let mut r = repeat(0).take(4);
- let mut w = sink();
- assert_eq!(copy(&mut r, &mut w).unwrap(), 4);
-
- let mut r = repeat(0).take(1 << 17);
- assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17);
-}
-
-struct ShortReader {
- cap: usize,
- read_size: usize,
- observed_buffer: usize,
-}
-
-impl Read for ShortReader {
- fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
- let bytes = min(self.cap, self.read_size);
- self.cap -= bytes;
- self.observed_buffer = max(self.observed_buffer, buf.len());
- Ok(bytes)
- }
-}
-
-struct WriteObserver {
- observed_buffer: usize,
-}
-
-impl Write for WriteObserver {
- fn write(&mut self, buf: &[u8]) -> Result<usize> {
- self.observed_buffer = max(self.observed_buffer, buf.len());
- Ok(buf.len())
- }
-
- fn flush(&mut self) -> Result<()> {
- Ok(())
- }
-}
-
-#[test]
-fn copy_specializes_bufwriter() {
- let cap = 117 * 1024;
- let buf_sz = 16 * 1024;
- let mut r = ShortReader { cap, observed_buffer: 0, read_size: 1337 };
- let mut w = BufWriter::with_capacity(buf_sz, WriteObserver { observed_buffer: 0 });
- assert_eq!(
- copy(&mut r, &mut w).unwrap(),
- cap as u64,
- "expected the whole capacity to be copied"
- );
- assert_eq!(r.observed_buffer, buf_sz, "expected a large buffer to be provided to the reader");
- assert!(w.get_mut().observed_buffer > DEFAULT_BUF_SIZE, "expected coalesced writes");
-}
-
-#[test]
fn sink_sinks() {
let mut s = sink();
assert_eq!(s.write(&[]).unwrap(), 0);
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 318a46d1b..72b9ad348 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -188,6 +188,13 @@
//! [array]: prim@array
//! [slice]: prim@slice
+// To run std tests without x.py without ending up with two copies of std, Miri needs to be
+// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
+// rustc itself never sets the feature, so this line has no affect there.
+#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
+// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies.
+#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))]
+//
#![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
#![doc(
@@ -202,12 +209,6 @@
no_global_oom_handling,
not(no_global_oom_handling)
))]
-// To run std tests without x.py without ending up with two copies of std, Miri needs to be
-// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
-// rustc itself never sets the feature, so this line has no affect there.
-#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
-// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies.
-#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))]
// Don't link to std. We are std.
#![no_std]
// Tell the compiler to link to either panic_abort or panic_unwind
diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs
index fcc5cfafd..ba1b8cbfa 100644
--- a/library/std/src/macros.rs
+++ b/library/std/src/macros.rs
@@ -154,7 +154,7 @@ macro_rules! println {
///
/// Panics if writing to `io::stderr` fails.
///
-/// Writing to non-blocking stdout can cause an error, which will lead
+/// Writing to non-blocking stderr can cause an error, which will lead
/// this macro to panic.
///
/// # Examples
@@ -189,7 +189,7 @@ macro_rules! eprint {
///
/// Panics if writing to `io::stderr` fails.
///
-/// Writing to non-blocking stdout can cause an error, which will lead
+/// Writing to non-blocking stderr can cause an error, which will lead
/// this macro to panic.
///
/// # Examples
diff --git a/library/std/src/net/socket_addr/tests.rs b/library/std/src/net/socket_addr/tests.rs
index dfc6dabbe..6a065cfba 100644
--- a/library/std/src/net/socket_addr/tests.rs
+++ b/library/std/src/net/socket_addr/tests.rs
@@ -85,7 +85,7 @@ fn ipv6_socket_addr_to_string() {
// IPv4-compatible address.
assert_eq!(
SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280), 8080, 0, 0).to_string(),
- "[::192.0.2.128]:8080"
+ "[::c000:280]:8080"
);
// IPv6 address with no zero segments.
diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs
index 7a3c66e45..db367cfa0 100644
--- a/library/std/src/net/tcp/tests.rs
+++ b/library/std/src/net/tcp/tests.rs
@@ -47,6 +47,17 @@ fn connect_error() {
}
#[test]
+#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+fn connect_timeout_error() {
+ let socket_addr = next_test_ip4();
+ let result = TcpStream::connect_timeout(&socket_addr, Duration::MAX);
+ assert!(!matches!(result, Err(e) if e.kind() == ErrorKind::TimedOut));
+
+ let _listener = TcpListener::bind(&socket_addr).unwrap();
+ assert!(TcpStream::connect_timeout(&socket_addr, Duration::MAX).is_ok());
+}
+
+#[test]
fn listen_localhost() {
let socket_addr = next_test_ip4();
let listener = t!(TcpListener::bind(&socket_addr));
diff --git a/library/std/src/os/ios/fs.rs b/library/std/src/os/ios/fs.rs
index 6d4d54b7c..b319527a5 100644
--- a/library/std/src/os/ios/fs.rs
+++ b/library/std/src/os/ios/fs.rs
@@ -6,7 +6,7 @@ use crate::sys_common::{AsInner, AsInnerMut, IntoInner};
use crate::time::SystemTime;
#[allow(deprecated)]
-use crate::os::ios::raw;
+use super::raw;
/// OS-specific extensions to [`fs::Metadata`].
///
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index 5b54cc5f2..634c3cc4a 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -137,6 +137,9 @@ pub mod redox;
pub mod solaris;
#[cfg(target_os = "solid_asp3")]
pub mod solid;
+#[cfg(target_os = "tvos")]
+#[path = "ios/mod.rs"]
+pub(crate) mod tvos;
#[cfg(target_os = "vita")]
pub mod vita;
#[cfg(target_os = "vxworks")]
diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs
index 6fe111118..401ec1e7a 100644
--- a/library/std/src/os/unix/mod.rs
+++ b/library/std/src/os/unix/mod.rs
@@ -73,6 +73,8 @@ mod platform {
pub use crate::os::redox::*;
#[cfg(target_os = "solaris")]
pub use crate::os::solaris::*;
+ #[cfg(target_os = "tvos")]
+ pub use crate::os::tvos::*;
#[cfg(target_os = "vita")]
pub use crate::os::vita::*;
#[cfg(target_os = "vxworks")]
@@ -96,6 +98,7 @@ pub mod thread;
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos",
target_os = "macos",
target_os = "netbsd",
diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs
index 7565fbc0d..218536689 100644
--- a/library/std/src/os/unix/net/ancillary.rs
+++ b/library/std/src/os/unix/net/ancillary.rs
@@ -11,12 +11,19 @@ use crate::slice::from_raw_parts;
use crate::sys::net::Socket;
// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
-#[cfg(all(doc, not(target_os = "linux"), not(target_os = "android"), not(target_os = "netbsd")))]
+#[cfg(all(
+ doc,
+ not(target_os = "linux"),
+ not(target_os = "android"),
+ not(target_os = "netbsd"),
+ not(target_os = "freebsd")
+))]
#[allow(non_camel_case_types)]
mod libc {
pub use libc::c_int;
pub struct ucred;
pub struct cmsghdr;
+ pub struct sockcred2;
pub type pid_t = i32;
pub type gid_t = u32;
pub type uid_t = u32;
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
index bf2a51b5e..e20170873 100644
--- a/library/std/src/os/unix/net/stream.rs
+++ b/library/std/src/os/unix/net/stream.rs
@@ -11,6 +11,7 @@ use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, Owned
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
+ target_os = "tvos",
target_os = "macos",
target_os = "watchos",
target_os = "netbsd",
@@ -30,6 +31,7 @@ use crate::time::Duration;
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
+ target_os = "tvos",
target_os = "macos",
target_os = "watchos",
target_os = "netbsd",
@@ -238,6 +240,7 @@ impl UnixStream {
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
+ target_os = "tvos",
target_os = "macos",
target_os = "watchos",
target_os = "netbsd",
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
index 729c63d18..2b40b672d 100644
--- a/library/std/src/os/unix/process.rs
+++ b/library/std/src/os/unix/process.rs
@@ -15,7 +15,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
use cfg_if::cfg_if;
cfg_if! {
- if #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))] {
+ if #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon", target_os = "vita"))] {
type UserId = u16;
type GroupId = u16;
} else if #[cfg(target_os = "nto")] {
diff --git a/library/std/src/os/unix/ucred.rs b/library/std/src/os/unix/ucred.rs
index 95967eac2..6a0cc2d2c 100644
--- a/library/std/src/os/unix/ucred.rs
+++ b/library/std/src/os/unix/ucred.rs
@@ -36,7 +36,7 @@ pub use self::impl_linux::peer_cred;
))]
pub use self::impl_bsd::peer_cred;
-#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))]
pub use self::impl_mac::peer_cred;
#[cfg(any(target_os = "linux", target_os = "android"))]
@@ -98,7 +98,7 @@ pub mod impl_bsd {
}
}
-#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))]
pub mod impl_mac {
use super::UCred;
use crate::os::unix::io::AsRawFd;
diff --git a/library/std/src/os/unix/ucred/tests.rs b/library/std/src/os/unix/ucred/tests.rs
index e63a2fc24..dd99ecdd8 100644
--- a/library/std/src/os/unix/ucred/tests.rs
+++ b/library/std/src/os/unix/ucred/tests.rs
@@ -8,6 +8,7 @@ use libc::{getegid, geteuid, getpid};
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
+ target_os = "tvos",
target_os = "macos",
target_os = "watchos",
target_os = "openbsd"
@@ -26,7 +27,13 @@ fn test_socket_pair() {
}
#[test]
-#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos", target_os = "watchos"))]
+#[cfg(any(
+ target_os = "linux",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "watchos",
+ target_os = "tvos",
+))]
fn test_socket_pair_pids(arg: Type) -> RetType {
// Create two connected sockets and get their peer credentials.
let (sock_a, sock_b) = UnixStream::pair().unwrap();
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index febdeb514..28cd3c4e4 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -193,7 +193,7 @@ impl<'a> Prefix<'a> {
fn len(&self) -> usize {
use self::Prefix::*;
fn os_str_len(s: &OsStr) -> usize {
- s.bytes().len()
+ s.as_os_str_bytes().len()
}
match *self {
Verbatim(x) => 4 + os_str_len(x),
@@ -299,20 +299,6 @@ where
}
}
-unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
- // SAFETY: See note at the top of this module to understand why this and
- // `OsStr::bytes` are used:
- //
- // This casts are safe as OsStr is internally a wrapper around [u8] on all
- // platforms.
- //
- // Note that currently this relies on the special knowledge that std has;
- // these types are single-element structs but are not marked
- // repr(transparent) or repr(C) which would make these casts not allowable
- // outside std.
- unsafe { &*(s as *const [u8] as *const OsStr) }
-}
-
// Detect scheme on Redox
fn has_redox_scheme(s: &[u8]) -> bool {
cfg!(target_os = "redox") && s.contains(&b':')
@@ -330,7 +316,7 @@ fn has_physical_root(s: &[u8], prefix: Option<Prefix<'_>>) -> bool {
// basic workhorse for splitting stem and extension
fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
- if file.bytes() == b".." {
+ if file.as_os_str_bytes() == b".." {
return (Some(file), None);
}
@@ -338,18 +324,23 @@ fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
// and back. This is safe to do because (1) we only look at ASCII
// contents of the encoding and (2) new &OsStr values are produced
// only from ASCII-bounded slices of existing &OsStr values.
- let mut iter = file.bytes().rsplitn(2, |b| *b == b'.');
+ let mut iter = file.as_os_str_bytes().rsplitn(2, |b| *b == b'.');
let after = iter.next();
let before = iter.next();
if before == Some(b"") {
(Some(file), None)
} else {
- unsafe { (before.map(|s| u8_slice_as_os_str(s)), after.map(|s| u8_slice_as_os_str(s))) }
+ unsafe {
+ (
+ before.map(|s| OsStr::from_os_str_bytes_unchecked(s)),
+ after.map(|s| OsStr::from_os_str_bytes_unchecked(s)),
+ )
+ }
}
}
fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) {
- let slice = file.bytes();
+ let slice = file.as_os_str_bytes();
if slice == b".." {
return (file, None);
}
@@ -364,7 +355,12 @@ fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) {
};
let before = &slice[..i];
let after = &slice[i + 1..];
- unsafe { (u8_slice_as_os_str(before), Some(u8_slice_as_os_str(after))) }
+ unsafe {
+ (
+ OsStr::from_os_str_bytes_unchecked(before),
+ Some(OsStr::from_os_str_bytes_unchecked(after)),
+ )
+ }
}
////////////////////////////////////////////////////////////////////////////////
@@ -743,7 +739,7 @@ impl<'a> Components<'a> {
// separately via `include_cur_dir`
b".." => Some(Component::ParentDir),
b"" => None,
- _ => Some(Component::Normal(unsafe { u8_slice_as_os_str(comp) })),
+ _ => Some(Component::Normal(unsafe { OsStr::from_os_str_bytes_unchecked(comp) })),
}
}
@@ -900,7 +896,7 @@ impl<'a> Iterator for Components<'a> {
let raw = &self.path[..self.prefix_len()];
self.path = &self.path[self.prefix_len()..];
return Some(Component::Prefix(PrefixComponent {
- raw: unsafe { u8_slice_as_os_str(raw) },
+ raw: unsafe { OsStr::from_os_str_bytes_unchecked(raw) },
parsed: self.prefix.unwrap(),
}));
}
@@ -972,7 +968,7 @@ impl<'a> DoubleEndedIterator for Components<'a> {
State::Prefix if self.prefix_len() > 0 => {
self.back = State::Done;
return Some(Component::Prefix(PrefixComponent {
- raw: unsafe { u8_slice_as_os_str(self.path) },
+ raw: unsafe { OsStr::from_os_str_bytes_unchecked(self.path) },
parsed: self.prefix.unwrap(),
}));
}
@@ -1481,17 +1477,17 @@ impl PathBuf {
fn _set_extension(&mut self, extension: &OsStr) -> bool {
let file_stem = match self.file_stem() {
None => return false,
- Some(f) => f.bytes(),
+ Some(f) => f.as_os_str_bytes(),
};
// truncate until right after the file stem
let end_file_stem = file_stem[file_stem.len()..].as_ptr().addr();
- let start = self.inner.bytes().as_ptr().addr();
+ let start = self.inner.as_os_str_bytes().as_ptr().addr();
let v = self.as_mut_vec();
v.truncate(end_file_stem.wrapping_sub(start));
// add the new extension, if any
- let new = extension.bytes();
+ let new = extension.as_os_str_bytes();
if !new.is_empty() {
v.reserve_exact(new.len() + 1);
v.push(b'.');
@@ -2011,11 +2007,11 @@ impl Path {
// The following (private!) function allows construction of a path from a u8
// slice, which is only safe when it is known to follow the OsStr encoding.
unsafe fn from_u8_slice(s: &[u8]) -> &Path {
- unsafe { Path::new(u8_slice_as_os_str(s)) }
+ unsafe { Path::new(OsStr::from_os_str_bytes_unchecked(s)) }
}
// The following (private!) function reveals the byte encoding used for OsStr.
fn as_u8_slice(&self) -> &[u8] {
- self.inner.bytes()
+ self.inner.as_os_str_bytes()
}
/// Directly wraps a string slice as a `Path` slice.
diff --git a/library/std/src/personality.rs b/library/std/src/personality.rs
index 63f0ad4f1..386a399f5 100644
--- a/library/std/src/personality.rs
+++ b/library/std/src/personality.rs
@@ -29,7 +29,7 @@ cfg_if::cfg_if! {
all(target_family = "windows", target_env = "gnu"),
target_os = "psp",
target_os = "solid_asp3",
- all(target_family = "unix", not(target_os = "espidf")),
+ all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re")),
all(target_vendor = "fortanix", target_env = "sgx"),
))] {
mod gcc;
diff --git a/library/std/src/personality/gcc.rs b/library/std/src/personality/gcc.rs
index 82edb11cb..6552d96ca 100644
--- a/library/std/src/personality/gcc.rs
+++ b/library/std/src/personality/gcc.rs
@@ -85,7 +85,7 @@ const UNWIND_DATA_REG: (i32, i32) = (4, 5); // a0, a1
// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
cfg_if::cfg_if! {
- if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "watchos"), not(target_os = "netbsd")))] {
+ if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "tvos"), not(target_os = "watchos"), not(target_os = "netbsd")))] {
// ARM EHABI personality routine.
// https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
//
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index 8266e8990..80289ca08 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -308,7 +308,7 @@ mod prim_never {}
///
/// ```no_run
/// // Undefined behaviour
-/// unsafe { char::from_u32_unchecked(0x110000) };
+/// let _ = unsafe { char::from_u32_unchecked(0x110000) };
/// ```
///
/// USVs are also the exact set of values that may be encoded in UTF-8. Because
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 9da74a5dd..8f3201b00 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1904,8 +1904,8 @@ impl FromInner<imp::ExitCode> for ExitCode {
}
impl Child {
- /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`]
- /// error is returned.
+ /// Forces the child process to exit. If the child has already exited, `Ok(())`
+ /// is returned.
///
/// The mapping to [`ErrorKind`]s is not part of the compatibility contract of the function.
///
@@ -1920,7 +1920,7 @@ impl Child {
///
/// let mut command = Command::new("yes");
/// if let Ok(mut child) = command.spawn() {
- /// child.kill().expect("command wasn't running");
+ /// child.kill().expect("command couldn't be killed");
/// } else {
/// println!("yes command didn't start");
/// }
diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs
index d7f4d335d..366b59146 100644
--- a/library/std/src/process/tests.rs
+++ b/library/std/src/process/tests.rs
@@ -582,3 +582,18 @@ fn run_canonical_bat_script() {
assert!(output.status.success());
assert_eq!(String::from_utf8_lossy(&output.stdout).trim(), "Hello, fellow Rustaceans!");
}
+
+#[test]
+fn terminate_exited_process() {
+ let mut cmd = if cfg!(target_os = "android") {
+ let mut p = shell_cmd();
+ p.args(&["-c", "true"]);
+ p
+ } else {
+ known_command()
+ };
+ let mut p = cmd.stdout(Stdio::null()).spawn().unwrap();
+ p.wait().unwrap();
+ assert!(p.kill().is_ok());
+ assert!(p.kill().is_ok());
+}
diff --git a/library/std/src/sync/barrier.rs b/library/std/src/sync/barrier.rs
index 11836b7b6..e39254aa4 100644
--- a/library/std/src/sync/barrier.rs
+++ b/library/std/src/sync/barrier.rs
@@ -13,9 +13,10 @@ use crate::sync::{Condvar, Mutex};
/// use std::sync::{Arc, Barrier};
/// use std::thread;
///
-/// let mut handles = Vec::with_capacity(10);
-/// let barrier = Arc::new(Barrier::new(10));
-/// for _ in 0..10 {
+/// let n = 10;
+/// let mut handles = Vec::with_capacity(n);
+/// let barrier = Arc::new(Barrier::new(n));
+/// for _ in 0..n {
/// let c = Arc::clone(&barrier);
/// // The same messages will be printed together.
/// // You will NOT see any interleaving.
@@ -105,9 +106,10 @@ impl Barrier {
/// use std::sync::{Arc, Barrier};
/// use std::thread;
///
- /// let mut handles = Vec::with_capacity(10);
- /// let barrier = Arc::new(Barrier::new(10));
- /// for _ in 0..10 {
+ /// let n = 10;
+ /// let mut handles = Vec::with_capacity(n);
+ /// let barrier = Arc::new(Barrier::new(n));
+ /// for _ in 0..n {
/// let c = Arc::clone(&barrier);
/// // The same messages will be printed together.
/// // You will NOT see any interleaving.
diff --git a/library/std/src/sync/mpmc/waker.rs b/library/std/src/sync/mpmc/waker.rs
index 4912ca4f8..9aab1b941 100644
--- a/library/std/src/sync/mpmc/waker.rs
+++ b/library/std/src/sync/mpmc/waker.rs
@@ -66,26 +66,32 @@ impl Waker {
/// Attempts to find another thread's entry, select the operation, and wake it up.
#[inline]
pub(crate) fn try_select(&mut self) -> Option<Entry> {
- self.selectors
- .iter()
- .position(|selector| {
- // Does the entry belong to a different thread?
- selector.cx.thread_id() != current_thread_id()
- && selector // Try selecting this operation.
- .cx
- .try_select(Selected::Operation(selector.oper))
- .is_ok()
- && {
- // Provide the packet.
- selector.cx.store_packet(selector.packet);
- // Wake the thread up.
- selector.cx.unpark();
- true
- }
- })
- // Remove the entry from the queue to keep it clean and improve
- // performance.
- .map(|pos| self.selectors.remove(pos))
+ if self.selectors.is_empty() {
+ None
+ } else {
+ let thread_id = current_thread_id();
+
+ self.selectors
+ .iter()
+ .position(|selector| {
+ // Does the entry belong to a different thread?
+ selector.cx.thread_id() != thread_id
+ && selector // Try selecting this operation.
+ .cx
+ .try_select(Selected::Operation(selector.oper))
+ .is_ok()
+ && {
+ // Provide the packet.
+ selector.cx.store_packet(selector.packet);
+ // Wake the thread up.
+ selector.cx.unpark();
+ true
+ }
+ })
+ // Remove the entry from the queue to keep it clean and improve
+ // performance.
+ .map(|pos| self.selectors.remove(pos))
+ }
}
/// Notifies all operations waiting to be ready.
diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs
index 0e0c87d1c..c00134c8b 100644
--- a/library/std/src/sync/mpsc/mod.rs
+++ b/library/std/src/sync/mpsc/mod.rs
@@ -347,8 +347,8 @@ pub struct Sender<T> {
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: Send> Send for Sender<T> {}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> !Sync for Sender<T> {}
+#[stable(feature = "mpsc_sender_sync", since = "1.72.0")]
+unsafe impl<T: Send> Sync for Sender<T> {}
/// The sending-half of Rust's synchronous [`sync_channel`] type.
///
diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs
index 1b17c3108..8c46080e4 100644
--- a/library/std/src/sync/once.rs
+++ b/library/std/src/sync/once.rs
@@ -91,7 +91,7 @@ impl Once {
/// return).
///
/// If the given closure recursively invokes `call_once` on the same [`Once`]
- /// instance the exact behavior is not specified, allowed outcomes are
+ /// instance, the exact behavior is not specified: allowed outcomes are
/// a panic or a deadlock.
///
/// # Examples
diff --git a/library/std/src/sys/common/small_c_string.rs b/library/std/src/sys/common/small_c_string.rs
index 01acd5191..963d17a47 100644
--- a/library/std/src/sys/common/small_c_string.rs
+++ b/library/std/src/sys/common/small_c_string.rs
@@ -19,7 +19,7 @@ pub fn run_path_with_cstr<T, F>(path: &Path, f: F) -> io::Result<T>
where
F: FnOnce(&CStr) -> io::Result<T>,
{
- run_with_cstr(path.as_os_str().bytes(), f)
+ run_with_cstr(path.as_os_str().as_os_str_bytes(), f)
}
#[inline]
diff --git a/library/std/src/sys/common/tests.rs b/library/std/src/sys/common/tests.rs
index fb6f5d6af..0a1cbcbe8 100644
--- a/library/std/src/sys/common/tests.rs
+++ b/library/std/src/sys/common/tests.rs
@@ -8,7 +8,7 @@ use core::iter::repeat;
fn stack_allocation_works() {
let path = Path::new("abc");
let result = run_path_with_cstr(path, |p| {
- assert_eq!(p, &*CString::new(path.as_os_str().bytes()).unwrap());
+ assert_eq!(p, &*CString::new(path.as_os_str().as_os_str_bytes()).unwrap());
Ok(42)
});
assert_eq!(result.unwrap(), 42);
@@ -25,7 +25,7 @@ fn heap_allocation_works() {
let path = repeat("a").take(384).collect::<String>();
let path = Path::new(&path);
let result = run_path_with_cstr(path, |p| {
- assert_eq!(p, &*CString::new(path.as_os_str().bytes()).unwrap());
+ assert_eq!(p, &*CString::new(path.as_os_str().as_os_str_bytes()).unwrap());
Ok(42)
});
assert_eq!(result.unwrap(), 42);
diff --git a/library/std/src/sys/common/thread_local/fast_local.rs b/library/std/src/sys/common/thread_local/fast_local.rs
index 447044a79..bc5da1a18 100644
--- a/library/std/src/sys/common/thread_local/fast_local.rs
+++ b/library/std/src/sys/common/thread_local/fast_local.rs
@@ -33,20 +33,21 @@ pub macro thread_local_inner {
// 1 == dtor registered, dtor not run
// 2 == dtor registered and is running or has run
#[thread_local]
- static mut STATE: $crate::primitive::u8 = 0;
+ static STATE: $crate::cell::Cell<$crate::primitive::u8> = $crate::cell::Cell::new(0);
+ // Safety: Performs `drop_in_place(ptr as *mut $t)`, and requires
+ // all that comes with it.
unsafe extern "C" fn destroy(ptr: *mut $crate::primitive::u8) {
- let ptr = ptr as *mut $t;
-
- unsafe {
- $crate::debug_assert_eq!(STATE, 1);
- STATE = 2;
- $crate::ptr::drop_in_place(ptr);
- }
+ $crate::thread::local_impl::abort_on_dtor_unwind(|| {
+ let old_state = STATE.replace(2);
+ $crate::debug_assert_eq!(old_state, 1);
+ // Safety: safety requirement is passed on to caller.
+ unsafe { $crate::ptr::drop_in_place(ptr.cast::<$t>()); }
+ });
}
unsafe {
- match STATE {
+ match STATE.get() {
// 0 == we haven't registered a destructor, so do
// so now.
0 => {
@@ -54,7 +55,7 @@ pub macro thread_local_inner {
$crate::ptr::addr_of_mut!(VAL) as *mut $crate::primitive::u8,
destroy,
);
- STATE = 1;
+ STATE.set(1);
$crate::option::Option::Some(&VAL)
}
// 1 == the destructor is registered and the value
@@ -148,7 +149,6 @@ impl<T> fmt::Debug for Key<T> {
f.debug_struct("Key").finish_non_exhaustive()
}
}
-
impl<T> Key<T> {
pub const fn new() -> Key<T> {
Key { inner: LazyKeyInner::new(), dtor_state: Cell::new(DtorState::Unregistered) }
diff --git a/library/std/src/sys/common/thread_local/mod.rs b/library/std/src/sys/common/thread_local/mod.rs
index 77f645883..975509bd4 100644
--- a/library/std/src/sys/common/thread_local/mod.rs
+++ b/library/std/src/sys/common/thread_local/mod.rs
@@ -101,3 +101,24 @@ mod lazy {
}
}
}
+
+/// Run a callback in a scenario which must not unwind (such as a `extern "C"
+/// fn` declared in a user crate). If the callback unwinds anyway, then
+/// `rtabort` with a message about thread local panicking on drop.
+#[inline]
+pub fn abort_on_dtor_unwind(f: impl FnOnce()) {
+ // Using a guard like this is lower cost.
+ let guard = DtorUnwindGuard;
+ f();
+ core::mem::forget(guard);
+
+ struct DtorUnwindGuard;
+ impl Drop for DtorUnwindGuard {
+ #[inline]
+ fn drop(&mut self) {
+ // This is not terribly descriptive, but it doesn't need to be as we'll
+ // already have printed a panic message at this point.
+ rtabort!("thread local panicked on drop");
+ }
+ }
+}
diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs
index 9ed4d9c1e..eafd6821f 100644
--- a/library/std/src/sys/unix/args.rs
+++ b/library/std/src/sys/unix/args.rs
@@ -168,7 +168,7 @@ mod imp {
}
}
-#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))]
mod imp {
use super::Args;
use crate::ffi::CStr;
@@ -209,7 +209,7 @@ mod imp {
// for i in (0..[args count])
// res.push([args objectAtIndex:i])
// res
- #[cfg(any(target_os = "ios", target_os = "watchos"))]
+ #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))]
pub fn args() -> Args {
use crate::ffi::OsString;
use crate::mem;
diff --git a/library/std/src/sys/unix/env.rs b/library/std/src/sys/unix/env.rs
index 8c3ef88d8..929e9dae7 100644
--- a/library/std/src/sys/unix/env.rs
+++ b/library/std/src/sys/unix/env.rs
@@ -31,6 +31,17 @@ pub mod os {
pub const EXE_EXTENSION: &str = "";
}
+#[cfg(target_os = "tvos")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "tvos";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".dylib";
+ pub const DLL_EXTENSION: &str = "dylib";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
#[cfg(target_os = "watchos")]
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 cb630eede..85e020ae4 100644
--- a/library/std/src/sys/unix/fd.rs
+++ b/library/std/src/sys/unix/fd.rs
@@ -44,6 +44,7 @@ const READ_LIMIT: usize = libc::ssize_t::MAX as usize;
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
+ target_os = "tvos",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
@@ -69,6 +70,7 @@ const fn max_iov() -> usize {
target_os = "emscripten",
target_os = "freebsd",
target_os = "ios",
+ target_os = "tvos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
@@ -181,6 +183,7 @@ impl FileDesc {
target_os = "fuchsia",
target_os = "illumos",
target_os = "ios",
+ target_os = "tvos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
@@ -222,6 +225,7 @@ impl FileDesc {
#[cfg(any(
all(target_os = "android", target_pointer_width = "32"),
target_os = "ios",
+ target_os = "tvos",
target_os = "macos",
))]
pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
@@ -320,6 +324,7 @@ impl FileDesc {
target_os = "fuchsia",
target_os = "illumos",
target_os = "ios",
+ target_os = "tvos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
@@ -361,6 +366,7 @@ impl FileDesc {
#[cfg(any(
all(target_os = "android", target_pointer_width = "32"),
target_os = "ios",
+ target_os = "tvos",
target_os = "macos",
))]
pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
@@ -402,7 +408,10 @@ impl FileDesc {
}
}
#[cfg(any(
- all(target_env = "newlib", not(any(target_os = "espidf", target_os = "horizon"))),
+ all(
+ target_env = "newlib",
+ not(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))
+ ),
target_os = "solaris",
target_os = "illumos",
target_os = "emscripten",
@@ -424,10 +433,10 @@ impl FileDesc {
Ok(())
}
}
- #[cfg(any(target_os = "espidf", target_os = "horizon"))]
+ #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))]
pub fn set_cloexec(&self) -> io::Result<()> {
- // FD_CLOEXEC is not supported in ESP-IDF and Horizon OS but there's no need to,
- // because neither supports spawning processes.
+ // FD_CLOEXEC is not supported in ESP-IDF, Horizon OS and Vita but there's no need to,
+ // because none of them supports spawning processes.
Ok(())
}
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 09e9ae272..fbc7f04ce 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -15,6 +15,7 @@ use crate::mem;
target_os = "redox",
target_os = "illumos",
target_os = "nto",
+ target_os = "vita",
))]
use crate::mem::MaybeUninit;
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
@@ -31,6 +32,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
all(target_os = "linux", target_env = "gnu"),
target_os = "macos",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos",
))]
use crate::sys::weak::syscall;
@@ -42,6 +44,7 @@ use libc::{c_int, mode_t};
#[cfg(any(
target_os = "macos",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos",
target_os = "solaris",
all(target_os = "linux", target_env = "gnu")
@@ -58,6 +61,7 @@ use libc::fstatat64;
target_os = "redox",
target_os = "illumos",
target_os = "nto",
+ target_os = "vita",
))]
use libc::readdir as readdir64;
#[cfg(target_os = "linux")]
@@ -74,6 +78,7 @@ use libc::readdir64_r;
target_os = "fuchsia",
target_os = "redox",
target_os = "nto",
+ target_os = "vita",
)))]
use libc::readdir_r as readdir64_r;
#[cfg(target_os = "android")]
@@ -283,6 +288,7 @@ unsafe impl Sync for Dir {}
target_os = "fuchsia",
target_os = "redox",
target_os = "nto",
+ target_os = "vita"
))]
pub struct DirEntry {
dir: Arc<InnerReadDir>,
@@ -304,10 +310,16 @@ pub struct DirEntry {
target_os = "fuchsia",
target_os = "redox",
target_os = "nto",
+ target_os = "vita",
))]
struct dirent64_min {
d_ino: u64,
- #[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "nto")))]
+ #[cfg(not(any(
+ target_os = "solaris",
+ target_os = "illumos",
+ target_os = "nto",
+ target_os = "vita"
+ )))]
d_type: u8,
}
@@ -319,6 +331,7 @@ struct dirent64_min {
target_os = "fuchsia",
target_os = "redox",
target_os = "nto",
+ target_os = "vita",
)))]
pub struct DirEntry {
dir: Arc<InnerReadDir>,
@@ -349,7 +362,7 @@ pub struct FilePermissions {
pub struct FileTimes {
accessed: Option<SystemTime>,
modified: Option<SystemTime>,
- #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
+ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos"))]
created: Option<SystemTime>,
}
@@ -508,6 +521,7 @@ impl FileAttr {
target_os = "openbsd",
target_os = "macos",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos",
))]
pub fn created(&self) -> io::Result<SystemTime> {
@@ -519,7 +533,9 @@ impl FileAttr {
target_os = "openbsd",
target_os = "macos",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos",
+ target_os = "vita",
)))]
pub fn created(&self) -> io::Result<SystemTime> {
cfg_has_statx! {
@@ -541,6 +557,11 @@ impl FileAttr {
currently",
))
}
+
+ #[cfg(target_os = "vita")]
+ pub fn created(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::new(self.stat.st_ctime as i64, 0))
+ }
}
#[cfg(target_os = "nto")]
@@ -594,7 +615,7 @@ impl FileTimes {
self.modified = Some(t);
}
- #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
+ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos"))]
pub fn set_created(&mut self, t: SystemTime) {
self.created = Some(t);
}
@@ -645,6 +666,7 @@ impl Iterator for ReadDir {
target_os = "redox",
target_os = "illumos",
target_os = "nto",
+ target_os = "vita",
))]
fn next(&mut self) -> Option<io::Result<DirEntry>> {
if self.end_of_stream {
@@ -725,6 +747,7 @@ impl Iterator for ReadDir {
continue;
}
+ #[cfg(not(target_os = "vita"))]
let entry = dirent64_min {
d_ino: *offset_ptr!(entry_ptr, d_ino) as u64,
#[cfg(not(any(
@@ -735,6 +758,9 @@ impl Iterator for ReadDir {
d_type: *offset_ptr!(entry_ptr, d_type) as u8,
};
+ #[cfg(target_os = "vita")]
+ let entry = dirent64_min { d_ino: 0u64 };
+
return Some(Ok(DirEntry {
entry,
name: name.to_owned(),
@@ -752,6 +778,7 @@ impl Iterator for ReadDir {
target_os = "redox",
target_os = "illumos",
target_os = "nto",
+ target_os = "vita",
)))]
fn next(&mut self) -> Option<io::Result<DirEntry>> {
if self.end_of_stream {
@@ -842,6 +869,7 @@ impl DirEntry {
target_os = "haiku",
target_os = "vxworks",
target_os = "nto",
+ target_os = "vita",
))]
pub fn file_type(&self) -> io::Result<FileType> {
self.metadata().map(|m| m.file_type())
@@ -853,6 +881,7 @@ impl DirEntry {
target_os = "haiku",
target_os = "vxworks",
target_os = "nto",
+ target_os = "vita",
)))]
pub fn file_type(&self) -> io::Result<FileType> {
match self.entry.d_type {
@@ -870,6 +899,7 @@ impl DirEntry {
#[cfg(any(
target_os = "macos",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos",
target_os = "linux",
target_os = "emscripten",
@@ -903,6 +933,7 @@ impl DirEntry {
#[cfg(any(
target_os = "macos",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos",
target_os = "netbsd",
target_os = "openbsd",
@@ -921,6 +952,7 @@ impl DirEntry {
#[cfg(not(any(
target_os = "macos",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos",
target_os = "netbsd",
target_os = "openbsd",
@@ -939,6 +971,7 @@ impl DirEntry {
target_os = "fuchsia",
target_os = "redox",
target_os = "nto",
+ target_os = "vita",
)))]
fn name_cstr(&self) -> &CStr {
unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
@@ -951,6 +984,7 @@ impl DirEntry {
target_os = "fuchsia",
target_os = "redox",
target_os = "nto",
+ target_os = "vita",
))]
fn name_cstr(&self) -> &CStr {
&self.name
@@ -1080,11 +1114,21 @@ impl File {
cvt_r(|| unsafe { os_fsync(self.as_raw_fd()) })?;
return Ok(());
- #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
+ #[cfg(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "tvos",
+ target_os = "watchos",
+ ))]
unsafe fn os_fsync(fd: c_int) -> c_int {
libc::fcntl(fd, libc::F_FULLFSYNC)
}
- #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "watchos")))]
+ #[cfg(not(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "tvos",
+ target_os = "watchos",
+ )))]
unsafe fn os_fsync(fd: c_int) -> c_int {
libc::fsync(fd)
}
@@ -1094,7 +1138,12 @@ impl File {
cvt_r(|| unsafe { os_datasync(self.as_raw_fd()) })?;
return Ok(());
- #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
+ #[cfg(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "tvos",
+ target_os = "watchos",
+ ))]
unsafe fn os_datasync(fd: c_int) -> c_int {
libc::fcntl(fd, libc::F_FULLFSYNC)
}
@@ -1113,6 +1162,7 @@ impl File {
target_os = "android",
target_os = "freebsd",
target_os = "ios",
+ target_os = "tvos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
@@ -1222,7 +1272,7 @@ impl File {
io::ErrorKind::Unsupported,
"setting file times not supported",
))
- } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] {
+ } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] {
let mut buf = [mem::MaybeUninit::<libc::timespec>::uninit(); 3];
let mut num_times = 0;
let mut attrlist: libc::attrlist = unsafe { mem::zeroed() };
@@ -1543,7 +1593,7 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> {
run_path_with_cstr(original, |original| {
run_path_with_cstr(link, |link| {
cfg_if::cfg_if! {
- if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon"))] {
+ if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita"))] {
// VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves
// it implementation-defined whether `link` follows symlinks, so rely on the
// `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior.
@@ -1666,6 +1716,8 @@ fn open_to_and_set_permissions(
.truncate(true)
.open(to)?;
let writer_metadata = writer.metadata()?;
+ // fchmod is broken on vita
+ #[cfg(not(target_os = "vita"))]
if writer_metadata.is_file() {
// Set the correct file permissions, in case the file already existed.
// Don't set the permissions on already existing non-files like
@@ -1680,6 +1732,7 @@ fn open_to_and_set_permissions(
target_os = "android",
target_os = "macos",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos",
)))]
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
@@ -1707,7 +1760,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
}
}
-#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))]
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
use crate::sync::atomic::{AtomicBool, Ordering};
@@ -1844,11 +1897,12 @@ pub fn chroot(dir: &Path) -> io::Result<()> {
pub use remove_dir_impl::remove_dir_all;
-// Fallback for REDOX, ESP-ID, Horizon, and Miri
+// Fallback for REDOX, ESP-ID, Horizon, Vita and Miri
#[cfg(any(
target_os = "redox",
target_os = "espidf",
target_os = "horizon",
+ target_os = "vita",
target_os = "nto",
miri
))]
@@ -1861,6 +1915,7 @@ mod remove_dir_impl {
target_os = "redox",
target_os = "espidf",
target_os = "horizon",
+ target_os = "vita",
target_os = "nto",
miri
)))]
diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs
index 16c8e0c0e..7d49bbdcb 100644
--- a/library/std/src/sys/unix/kernel_copy.rs
+++ b/library/std/src/sys/unix/kernel_copy.rs
@@ -466,7 +466,7 @@ impl<T: CopyRead> CopyRead for Take<T> {
}
}
-impl<T: CopyRead> CopyRead for BufReader<T> {
+impl<T: ?Sized + CopyRead> CopyRead for BufReader<T> {
fn drain_to<W: Write>(&mut self, writer: &mut W, outer_limit: u64) -> Result<u64> {
let buf = self.buffer();
let buf = &buf[0..min(buf.len(), outer_limit.try_into().unwrap_or(usize::MAX))];
@@ -495,7 +495,7 @@ impl<T: CopyRead> CopyRead for BufReader<T> {
}
}
-impl<T: CopyWrite> CopyWrite for BufWriter<T> {
+impl<T: ?Sized + CopyWrite> CopyWrite for BufWriter<T> {
fn properties(&self) -> CopyParams {
self.get_ref().properties()
}
diff --git a/library/std/src/sys/unix/l4re.rs b/library/std/src/sys/unix/l4re.rs
index ee016887e..fe9559f2a 100644
--- a/library/std/src/sys/unix/l4re.rs
+++ b/library/std/src/sys/unix/l4re.rs
@@ -10,7 +10,7 @@ macro_rules! unimpl {
pub mod net {
#![allow(warnings)]
use crate::fmt;
- use crate::io::{self, IoSlice, IoSliceMut};
+ use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
use crate::sys::fd::FileDesc;
@@ -218,6 +218,10 @@ pub mod net {
unimpl!();
}
+ pub fn read_buf(&self, _: BorrowedCursor<'_>) -> io::Result<()> {
+ unimpl!();
+ }
+
pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
unimpl!();
}
diff --git a/library/std/src/sys/unix/locks/pthread_condvar.rs b/library/std/src/sys/unix/locks/pthread_condvar.rs
index 192fa216d..2dc1b0c60 100644
--- a/library/std/src/sys/unix/locks/pthread_condvar.rs
+++ b/library/std/src/sys/unix/locks/pthread_condvar.rs
@@ -32,6 +32,7 @@ impl LazyInit for AllocatedCondvar {
if #[cfg(any(
target_os = "macos",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos",
target_os = "l4re",
target_os = "android",
@@ -124,6 +125,7 @@ impl Condvar {
#[cfg(not(any(
target_os = "macos",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos",
target_os = "android",
target_os = "espidf",
@@ -158,6 +160,7 @@ impl Condvar {
#[cfg(any(
target_os = "macos",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos",
target_os = "android",
target_os = "espidf",
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index bb9e65e68..326f1481e 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -88,6 +88,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
// The poll on Darwin doesn't set POLLNVAL for closed fds.
target_os = "macos",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos",
target_os = "redox",
target_os = "l4re",
@@ -164,12 +165,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
}
unsafe fn reset_sigpipe(#[allow(unused_variables)] sigpipe: u8) {
- #[cfg(not(any(
- target_os = "emscripten",
- target_os = "fuchsia",
- target_os = "horizon",
- target_os = "vita"
- )))]
+ #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "horizon")))]
{
// We don't want to add this as a public type to std, nor do we
// want to `include!` a file from the compiler (which would break
@@ -207,7 +203,6 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
target_os = "emscripten",
target_os = "fuchsia",
target_os = "horizon",
- target_os = "vita"
)))]
static UNIX_SIGPIPE_ATTR_SPECIFIED: crate::sync::atomic::AtomicBool =
crate::sync::atomic::AtomicBool::new(false);
@@ -217,7 +212,6 @@ static UNIX_SIGPIPE_ATTR_SPECIFIED: crate::sync::atomic::AtomicBool =
target_os = "emscripten",
target_os = "fuchsia",
target_os = "horizon",
- target_os = "vita",
)))]
pub(crate) fn unix_sigpipe_attr_specified() -> bool {
UNIX_SIGPIPE_ATTR_SPECIFIED.load(crate::sync::atomic::Ordering::Relaxed)
@@ -395,7 +389,7 @@ cfg_if::cfg_if! {
} else if #[cfg(target_os = "macos")] {
#[link(name = "System")]
extern "C" {}
- } else if #[cfg(any(target_os = "ios", target_os = "watchos"))] {
+ } else if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))] {
#[link(name = "System")]
#[link(name = "objc")]
#[link(name = "Security", kind = "framework")]
@@ -408,6 +402,9 @@ cfg_if::cfg_if! {
} else if #[cfg(all(target_os = "linux", target_env = "uclibc"))] {
#[link(name = "dl")]
extern "C" {}
+ } else if #[cfg(target_os = "vita")] {
+ #[link(name = "pthread", kind = "static", modifiers = "-bundle")]
+ extern "C" {}
}
}
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index 39edb136c..7258c222a 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -454,12 +454,18 @@ impl Socket {
Ok(passcred != 0)
}
- #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
+ #[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "vita")))]
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
let mut nonblocking = nonblocking as libc::c_int;
cvt(unsafe { libc::ioctl(self.as_raw_fd(), libc::FIONBIO, &mut nonblocking) }).map(drop)
}
+ #[cfg(target_os = "vita")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ let option = nonblocking as libc::c_int;
+ setsockopt(self, libc::SOL_SOCKET, libc::SO_NONBLOCK, option)
+ }
+
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
// FIONBIO is inadequate for sockets on illumos/Solaris, so use the
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 8edfd3313..a68c14758 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -63,7 +63,13 @@ extern "C" {
#[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"),
+ any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "tvos",
+ target_os = "freebsd",
+ target_os = "watchos"
+ ),
link_name = "__error"
)]
#[cfg_attr(target_os = "haiku", link_name = "_errnop")]
@@ -375,7 +381,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
Ok(PathBuf::from(OsString::from_vec(e)))
}
-#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))]
pub fn current_exe() -> io::Result<PathBuf> {
unsafe {
let mut sz: u32 = 0;
@@ -609,6 +615,7 @@ pub fn home_dir() -> Option<PathBuf> {
#[cfg(any(
target_os = "android",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos",
target_os = "emscripten",
target_os = "redox",
@@ -623,6 +630,7 @@ pub fn home_dir() -> Option<PathBuf> {
#[cfg(not(any(
target_os = "android",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos",
target_os = "emscripten",
target_os = "redox",
diff --git a/library/std/src/sys/unix/os_str.rs b/library/std/src/sys/unix/os_str.rs
index 488217f39..f7333fd5a 100644
--- a/library/std/src/sys/unix/os_str.rs
+++ b/library/std/src/sys/unix/os_str.rs
@@ -193,17 +193,22 @@ impl Buf {
impl Slice {
#[inline]
- fn from_u8_slice(s: &[u8]) -> &Slice {
+ pub fn as_os_str_bytes(&self) -> &[u8] {
+ &self.inner
+ }
+
+ #[inline]
+ pub unsafe fn from_os_str_bytes_unchecked(s: &[u8]) -> &Slice {
unsafe { mem::transmute(s) }
}
#[inline]
pub fn from_str(s: &str) -> &Slice {
- Slice::from_u8_slice(s.as_bytes())
+ unsafe { Slice::from_os_str_bytes_unchecked(s.as_bytes()) }
}
- pub fn to_str(&self) -> Option<&str> {
- str::from_utf8(&self.inner).ok()
+ pub fn to_str(&self) -> Result<&str, crate::str::Utf8Error> {
+ str::from_utf8(&self.inner)
}
pub fn to_string_lossy(&self) -> Cow<'_, str> {
diff --git a/library/std/src/sys/unix/os_str/tests.rs b/library/std/src/sys/unix/os_str/tests.rs
index 22ba0c923..91bc0e61a 100644
--- a/library/std/src/sys/unix/os_str/tests.rs
+++ b/library/std/src/sys/unix/os_str/tests.rs
@@ -2,7 +2,7 @@ use super::*;
#[test]
fn slice_debug_output() {
- let input = Slice::from_u8_slice(b"\xF0hello,\tworld");
+ let input = unsafe { Slice::from_os_str_bytes_unchecked(b"\xF0hello,\tworld") };
let expected = r#""\xF0hello,\tworld""#;
let output = format!("{input:?}");
@@ -11,8 +11,7 @@ fn slice_debug_output() {
#[test]
fn display() {
- assert_eq!(
- "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye",
- Slice::from_u8_slice(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string(),
- );
+ assert_eq!("Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", unsafe {
+ Slice::from_os_str_bytes_unchecked(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string()
+ },);
}
diff --git a/library/std/src/sys/unix/path.rs b/library/std/src/sys/unix/path.rs
index a98a69e2d..935245f63 100644
--- a/library/std/src/sys/unix/path.rs
+++ b/library/std/src/sys/unix/path.rs
@@ -30,7 +30,7 @@ pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
// Get the components, skipping the redundant leading "." component if it exists.
let mut components = path.strip_prefix(".").unwrap_or(path).components();
- let path_os = path.as_os_str().bytes();
+ let path_os = path.as_os_str().as_os_str_bytes();
let mut normalized = if path.is_absolute() {
// "If a pathname begins with two successive <slash> characters, the
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index afd03d79c..640648e87 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -164,9 +164,9 @@ pub enum ProgramKind {
impl ProgramKind {
fn new(program: &OsStr) -> Self {
- if program.bytes().starts_with(b"/") {
+ if program.as_os_str_bytes().starts_with(b"/") {
Self::Absolute
- } else if program.bytes().contains(&b'/') {
+ } else if program.as_os_str_bytes().contains(&b'/') {
// If the program has more than one component in it, it is a relative path.
Self::Relative
} else {
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 612d43fe2..0ce93af66 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -15,6 +15,8 @@ use crate::sys::weak::raw_syscall;
#[cfg(any(
target_os = "macos",
+ target_os = "watchos",
+ target_os = "tvos",
target_os = "freebsd",
all(target_os = "linux", target_env = "gnu"),
all(target_os = "linux", target_env = "musl"),
@@ -28,15 +30,38 @@ use libc::RTP_ID as pid_t;
#[cfg(not(target_os = "vxworks"))]
use libc::{c_int, pid_t};
-#[cfg(not(any(target_os = "vxworks", target_os = "l4re")))]
+#[cfg(not(any(
+ target_os = "vxworks",
+ target_os = "l4re",
+ target_os = "tvos",
+ target_os = "watchos",
+)))]
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;
+ use crate::time::Duration;
+ use crate::sync::LazyLock;
+ // Get smallest amount of time we can sleep.
+ // Return a common value if it cannot be determined.
+ fn get_clock_resolution() -> Duration {
+ static MIN_DELAY: LazyLock<Duration, fn() -> Duration> = LazyLock::new(|| {
+ let mut mindelay = libc::timespec { tv_sec: 0, tv_nsec: 0 };
+ if unsafe { libc::clock_getres(libc::CLOCK_MONOTONIC, &mut mindelay) } == 0
+ {
+ Duration::from_nanos(mindelay.tv_nsec as u64)
+ } else {
+ Duration::from_millis(1)
+ }
+ });
+ *MIN_DELAY
+ }
+ // Arbitrary minimum sleep duration for retrying fork/spawn
+ const MIN_FORKSPAWN_SLEEP: Duration = Duration::from_nanos(1);
+ // Maximum duration of sleeping before giving up and returning an error
+ const MAX_FORKSPAWN_SLEEP: Duration = Duration::from_millis(1000);
}
}
@@ -66,7 +91,6 @@ impl Command {
if let Some(ret) = self.posix_spawn(&theirs, envp.as_ref())? {
return Ok((ret, ours));
}
-
let (input, output) = sys::pipe::anon_pipe()?;
// Whatever happens after the fork is almost for sure going to touch or
@@ -148,9 +172,31 @@ impl Command {
crate::sys_common::process::wait_with_output(proc, pipes)
}
+ // WatchOS and TVOS headers mark the `fork`/`exec*` functions with
+ // `__WATCHOS_PROHIBITED __TVOS_PROHIBITED`, and indicate that the
+ // `posix_spawn*` functions should be used instead. It isn't entirely clear
+ // what `PROHIBITED` means here (e.g. if calls to these functions are
+ // allowed to exist in dead code), but it sounds bad, so we go out of our
+ // way to avoid that all-together.
+ #[cfg(any(target_os = "tvos", target_os = "watchos"))]
+ const ERR_APPLE_TV_WATCH_NO_FORK_EXEC: Error = io::const_io_error!(
+ ErrorKind::Unsupported,
+ "`fork`+`exec`-based process spawning is not supported on this target",
+ );
+
+ #[cfg(any(target_os = "tvos", target_os = "watchos"))]
+ unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
+ return Err(Self::ERR_APPLE_TV_WATCH_NO_FORK_EXEC);
+ }
+
// Attempts to fork the process. If successful, returns Ok((0, -1))
// in the child, and Ok((child_pid, -1)) in the parent.
- #[cfg(not(any(target_os = "linux", all(target_os = "nto", target_env = "nto71"))))]
+ #[cfg(not(any(
+ target_os = "linux",
+ target_os = "watchos",
+ target_os = "tvos",
+ 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))
}
@@ -163,12 +209,25 @@ impl Command {
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;
+ let mut delay = MIN_FORKSPAWN_SLEEP;
+
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;
+ if r == -1 as libc::pid_t && errno() as libc::c_int == libc::EBADF {
+ if delay < get_clock_resolution() {
+ // We cannot sleep this short (it would be longer).
+ // Yield instead.
+ thread::yield_now();
+ } else if delay < MAX_FORKSPAWN_SLEEP {
+ thread::sleep(delay);
+ } else {
+ return Err(io::const_io_error!(
+ ErrorKind::WouldBlock,
+ "forking returned EBADF too often",
+ ));
+ }
+ delay *= 2;
+ continue;
} else {
return cvt(r).map(|res| (res, -1));
}
@@ -308,6 +367,7 @@ impl Command {
// allocation). Instead we just close it manually. This will never
// have the drop glue anyway because this code never returns (the
// child will either exec() or invoke libc::exit)
+ #[cfg(not(any(target_os = "tvos", target_os = "watchos")))]
unsafe fn do_exec(
&mut self,
stdio: ChildPipes,
@@ -414,8 +474,19 @@ impl Command {
Err(io::Error::last_os_error())
}
+ #[cfg(any(target_os = "tvos", target_os = "watchos"))]
+ unsafe fn do_exec(
+ &mut self,
+ _stdio: ChildPipes,
+ _maybe_envp: Option<&CStringArray>,
+ ) -> Result<!, io::Error> {
+ return Err(Self::ERR_APPLE_TV_WATCH_NO_FORK_EXEC);
+ }
+
#[cfg(not(any(
target_os = "macos",
+ target_os = "tvos",
+ target_os = "watchos",
target_os = "freebsd",
all(target_os = "linux", target_env = "gnu"),
all(target_os = "linux", target_env = "musl"),
@@ -433,6 +504,9 @@ impl Command {
// directly.
#[cfg(any(
target_os = "macos",
+ // FIXME: `target_os = "ios"`?
+ target_os = "tvos",
+ target_os = "watchos",
target_os = "freebsd",
all(target_os = "linux", target_env = "gnu"),
all(target_os = "linux", target_env = "musl"),
@@ -480,17 +554,28 @@ impl Command {
attrp: *const posix_spawnattr_t,
argv: *const *mut c_char,
envp: *const *mut c_char,
- ) -> i32 {
- let mut tries_left = MAX_FORKSPAWN_TRIES;
+ ) -> io::Result<i32> {
+ let mut delay = MIN_FORKSPAWN_SLEEP;
loop {
match libc::posix_spawnp(pid, file, file_actions, attrp, argv, envp) {
- libc::EBADF if tries_left > 0 => {
- thread::yield_now();
- tries_left -= 1;
+ libc::EBADF => {
+ if delay < get_clock_resolution() {
+ // We cannot sleep this short (it would be longer).
+ // Yield instead.
+ thread::yield_now();
+ } else if delay < MAX_FORKSPAWN_SLEEP {
+ thread::sleep(delay);
+ } else {
+ return Err(io::const_io_error!(
+ ErrorKind::WouldBlock,
+ "posix_spawnp returned EBADF too often",
+ ));
+ }
+ delay *= 2;
continue;
}
r => {
- return r;
+ return Ok(r);
}
}
}
@@ -508,7 +593,7 @@ impl Command {
}
let addchdir = match self.get_cwd() {
Some(cwd) => {
- if cfg!(target_os = "macos") {
+ if cfg!(any(target_os = "macos", target_os = "tvos", target_os = "watchos")) {
// There is a bug in macOS where a relative executable
// path like "../myprogram" will cause `posix_spawn` to
// successfully launch the program, but erroneously return
@@ -620,14 +705,20 @@ impl Command {
let spawn_fn = libc::posix_spawnp;
#[cfg(target_os = "nto")]
let spawn_fn = retrying_libc_posix_spawnp;
- cvt_nz(spawn_fn(
+
+ let spawn_res = spawn_fn(
&mut p.pid,
self.get_program_cstr().as_ptr(),
file_actions.0.as_ptr(),
attrs.0.as_ptr(),
self.get_argv().as_ptr() as *const _,
envp as *const _,
- ))?;
+ );
+
+ #[cfg(target_os = "nto")]
+ let spawn_res = spawn_res?;
+
+ cvt_nz(spawn_res)?;
Ok(Some(p))
}
}
@@ -671,12 +762,9 @@ impl Process {
pub fn kill(&mut self) -> io::Result<()> {
// If we've already waited on this process then the pid can be recycled
// and used for another process, and we probably shouldn't be killing
- // random processes, so just return an error.
+ // random processes, so return Ok because the process has exited already.
if self.status.is_some() {
- Err(io::const_io_error!(
- ErrorKind::InvalidInput,
- "invalid argument: can't kill an exited process",
- ))
+ Ok(())
} else {
cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
}
@@ -788,31 +876,47 @@ fn signal_string(signal: i32) -> &'static str {
libc::SIGILL => " (SIGILL)",
libc::SIGTRAP => " (SIGTRAP)",
libc::SIGABRT => " (SIGABRT)",
+ #[cfg(not(target_os = "l4re"))]
libc::SIGBUS => " (SIGBUS)",
libc::SIGFPE => " (SIGFPE)",
libc::SIGKILL => " (SIGKILL)",
+ #[cfg(not(target_os = "l4re"))]
libc::SIGUSR1 => " (SIGUSR1)",
libc::SIGSEGV => " (SIGSEGV)",
+ #[cfg(not(target_os = "l4re"))]
libc::SIGUSR2 => " (SIGUSR2)",
libc::SIGPIPE => " (SIGPIPE)",
libc::SIGALRM => " (SIGALRM)",
libc::SIGTERM => " (SIGTERM)",
+ #[cfg(not(target_os = "l4re"))]
libc::SIGCHLD => " (SIGCHLD)",
+ #[cfg(not(target_os = "l4re"))]
libc::SIGCONT => " (SIGCONT)",
+ #[cfg(not(target_os = "l4re"))]
libc::SIGSTOP => " (SIGSTOP)",
+ #[cfg(not(target_os = "l4re"))]
libc::SIGTSTP => " (SIGTSTP)",
+ #[cfg(not(target_os = "l4re"))]
libc::SIGTTIN => " (SIGTTIN)",
+ #[cfg(not(target_os = "l4re"))]
libc::SIGTTOU => " (SIGTTOU)",
+ #[cfg(not(target_os = "l4re"))]
libc::SIGURG => " (SIGURG)",
+ #[cfg(not(target_os = "l4re"))]
libc::SIGXCPU => " (SIGXCPU)",
+ #[cfg(not(target_os = "l4re"))]
libc::SIGXFSZ => " (SIGXFSZ)",
+ #[cfg(not(target_os = "l4re"))]
libc::SIGVTALRM => " (SIGVTALRM)",
+ #[cfg(not(target_os = "l4re"))]
libc::SIGPROF => " (SIGPROF)",
+ #[cfg(not(target_os = "l4re"))]
libc::SIGWINCH => " (SIGWINCH)",
- #[cfg(not(target_os = "haiku"))]
+ #[cfg(not(any(target_os = "haiku", target_os = "l4re")))]
libc::SIGIO => " (SIGIO)",
#[cfg(target_os = "haiku")]
libc::SIGPOLL => " (SIGPOLL)",
+ #[cfg(not(target_os = "l4re"))]
libc::SIGSYS => " (SIGSYS)",
// For information on Linux signals, run `man 7 signal`
#[cfg(all(
diff --git a/library/std/src/sys/unix/process/process_vxworks.rs b/library/std/src/sys/unix/process/process_vxworks.rs
index c40e7ada0..f70d3cb39 100644
--- a/library/std/src/sys/unix/process/process_vxworks.rs
+++ b/library/std/src/sys/unix/process/process_vxworks.rs
@@ -144,12 +144,9 @@ impl Process {
pub fn kill(&mut self) -> io::Result<()> {
// If we've already waited on this process then the pid can be recycled
// and used for another process, and we probably shouldn't be killing
- // random processes, so just return an error.
+ // random processes, so return Ok because the process has exited already.
if self.status.is_some() {
- Err(io::const_io_error!(
- ErrorKind::InvalidInput,
- "invalid argument: can't kill an exited process",
- ))
+ Ok(())
} else {
cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
}
diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs
index d8b63546b..d471be33e 100644
--- a/library/std/src/sys/unix/rand.rs
+++ b/library/std/src/sys/unix/rand.rs
@@ -14,6 +14,7 @@ pub fn hashmap_random_keys() -> (u64, u64) {
unix,
not(target_os = "macos"),
not(target_os = "ios"),
+ not(target_os = "tvos"),
not(target_os = "watchos"),
not(target_os = "openbsd"),
not(target_os = "freebsd"),
@@ -198,7 +199,7 @@ mod imp {
// once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
// only used on iOS where direct access to `/dev/urandom` is blocked by the
// sandbox.
-#[cfg(any(target_os = "ios", target_os = "watchos"))]
+#[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))]
mod imp {
use crate::io;
use crate::ptr;
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 7307d9b2c..4f2d9cf36 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -150,7 +150,7 @@ impl Thread {
}
}
- #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
+ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))]
pub fn set_name(name: &CStr) {
unsafe {
let name = truncate_cstr::<{ libc::MAXTHREADNAMESIZE }>(name);
@@ -284,7 +284,13 @@ impl Drop for Thread {
}
}
-#[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "watchos"))]
+#[cfg(any(
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "tvos",
+ target_os = "watchos",
+))]
fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] {
let mut result = [0; MAX_WITH_NUL];
for (src, dst) in cstr.to_bytes().iter().zip(&mut result[..MAX_WITH_NUL - 1]) {
@@ -300,6 +306,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
target_os = "emscripten",
target_os = "fuchsia",
target_os = "ios",
+ target_os = "tvos",
target_os = "linux",
target_os = "macos",
target_os = "solaris",
@@ -345,6 +352,29 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
}
}
+ #[cfg(target_os = "netbsd")]
+ {
+ unsafe {
+ let set = libc::_cpuset_create();
+ if !set.is_null() {
+ let mut count: usize = 0;
+ if libc::pthread_getaffinity_np(libc::pthread_self(), libc::_cpuset_size(set), set) == 0 {
+ for i in 0..u64::MAX {
+ match libc::_cpuset_isset(i, set) {
+ -1 => break,
+ 0 => continue,
+ _ => count = count + 1,
+ }
+ }
+ }
+ libc::_cpuset_destroy(set);
+ if let Some(count) = NonZeroUsize::new(count) {
+ return Ok(count);
+ }
+ }
+ }
+ }
+
let mut cpus: libc::c_uint = 0;
let mut cpus_size = crate::mem::size_of_val(&cpus);
diff --git a/library/std/src/sys/unix/thread_parking/pthread.rs b/library/std/src/sys/unix/thread_parking/pthread.rs
index 43046ed07..ae805d843 100644
--- a/library/std/src/sys/unix/thread_parking/pthread.rs
+++ b/library/std/src/sys/unix/thread_parking/pthread.rs
@@ -46,6 +46,7 @@ unsafe fn wait_timeout(
#[cfg(any(
target_os = "macos",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos",
target_os = "espidf",
target_os = "horizon",
@@ -73,6 +74,7 @@ unsafe fn wait_timeout(
#[cfg(not(any(
target_os = "macos",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos",
target_os = "espidf",
target_os = "horizon",
@@ -120,10 +122,12 @@ impl Parker {
if #[cfg(any(
target_os = "macos",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos",
target_os = "l4re",
target_os = "android",
- target_os = "redox"
+ target_os = "redox",
+ target_os = "vita",
))] {
addr_of_mut!((*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER));
} else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] {
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index a9fbc7ab1..17b4130c2 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -219,7 +219,8 @@ impl From<__timespec64> for Timespec {
#[cfg(any(
all(target_os = "macos", any(not(target_arch = "aarch64"))),
target_os = "ios",
- target_os = "watchos"
+ target_os = "watchos",
+ target_os = "tvos"
))]
mod inner {
use crate::sync::atomic::{AtomicU64, Ordering};
@@ -339,7 +340,8 @@ mod inner {
#[cfg(not(any(
all(target_os = "macos", any(not(target_arch = "aarch64"))),
target_os = "ios",
- target_os = "watchos"
+ target_os = "watchos",
+ target_os = "tvos"
)))]
mod inner {
use crate::fmt;
diff --git a/library/std/src/sys/unix/weak.rs b/library/std/src/sys/unix/weak.rs
index 62ffee70b..61088ff16 100644
--- a/library/std/src/sys/unix/weak.rs
+++ b/library/std/src/sys/unix/weak.rs
@@ -28,7 +28,7 @@ use crate::ptr;
use crate::sync::atomic::{self, AtomicPtr, Ordering};
// We can use true weak linkage on ELF targets.
-#[cfg(not(any(target_os = "macos", target_os = "ios")))]
+#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "tvos")))]
pub(crate) macro weak {
(fn $name:ident($($t:ty),*) -> $ret:ty) => (
let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
@@ -43,7 +43,7 @@ pub(crate) macro weak {
}
// On non-ELF targets, use the dlsym approximation of weak linkage.
-#[cfg(any(target_os = "macos", target_os = "ios"))]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos"))]
pub(crate) use self::dlsym as weak;
pub(crate) struct ExternWeak<F: Copy> {
diff --git a/library/std/src/sys/wasi/fd.rs b/library/std/src/sys/wasi/fd.rs
index 9a8b2a0be..1b50c2ea6 100644
--- a/library/std/src/sys/wasi/fd.rs
+++ b/library/std/src/sys/wasi/fd.rs
@@ -96,7 +96,7 @@ impl WasiFd {
unsafe { wasi::fd_sync(self.as_raw_fd() as wasi::Fd).map_err(err2io) }
}
- pub fn advise(&self, offset: u64, len: u64, advice: wasi::Advice) -> io::Result<()> {
+ pub(crate) fn advise(&self, offset: u64, len: u64, advice: wasi::Advice) -> io::Result<()> {
unsafe {
wasi::fd_advise(self.as_raw_fd() as wasi::Fd, offset, len, advice).map_err(err2io)
}
@@ -179,7 +179,7 @@ impl WasiFd {
}
}
- pub fn filestat_get(&self) -> io::Result<wasi::Filestat> {
+ pub(crate) fn filestat_get(&self) -> io::Result<wasi::Filestat> {
unsafe { wasi::fd_filestat_get(self.as_raw_fd() as wasi::Fd).map_err(err2io) }
}
@@ -199,7 +199,7 @@ impl WasiFd {
unsafe { wasi::fd_filestat_set_size(self.as_raw_fd() as wasi::Fd, size).map_err(err2io) }
}
- pub fn path_filestat_get(
+ pub(crate) fn path_filestat_get(
&self,
flags: wasi::Lookupflags,
path: &str,
diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs
index 8d1dbf591..437aae3ae 100644
--- a/library/std/src/sys/wasi/fs.rs
+++ b/library/std/src/sys/wasi/fs.rs
@@ -104,7 +104,7 @@ impl FileAttr {
Ok(SystemTime::from_wasi_timestamp(self.meta.ctim))
}
- pub fn as_wasi(&self) -> &wasi::Filestat {
+ pub(crate) fn as_wasi(&self) -> &wasi::Filestat {
&self.meta
}
}
@@ -142,7 +142,7 @@ impl FileType {
self.bits == wasi::FILETYPE_SYMBOLIC_LINK
}
- pub fn bits(&self) -> wasi::Filetype {
+ pub(crate) fn bits(&self) -> wasi::Filetype {
self.bits
}
}
diff --git a/library/std/src/sys/windows/args.rs b/library/std/src/sys/windows/args.rs
index 5bfd8b52e..6b597f499 100644
--- a/library/std/src/sys/windows/args.rs
+++ b/library/std/src/sys/windows/args.rs
@@ -226,7 +226,7 @@ pub(crate) fn append_arg(cmd: &mut Vec<u16>, arg: &Arg, force_quotes: bool) -> i
// that it actually gets passed through on the command line or otherwise
// it will be dropped entirely when parsed on the other end.
ensure_no_nuls(arg)?;
- let arg_bytes = arg.bytes();
+ let arg_bytes = arg.as_os_str_bytes();
let (quote, escape) = match quote {
Quote::Always => (true, true),
Quote::Auto => {
@@ -297,7 +297,9 @@ pub(crate) fn make_bat_command_line(
// * `|<>` 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)),
+ Arg::Regular(arg) if !force_quotes => {
+ arg.as_os_str_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 2bc40c474..d9ccba0e9 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -12,13 +12,13 @@ use crate::os::windows::io::{AsRawHandle, BorrowedHandle};
use crate::ptr;
use core::ffi::NonZero_c_ulong;
-#[path = "c/windows_sys.rs"] // c.rs is included from two places so we need to specify this
mod windows_sys;
pub use windows_sys::*;
pub type DWORD = c_ulong;
pub type NonZeroDWORD = NonZero_c_ulong;
pub type LARGE_INTEGER = c_longlong;
+#[cfg_attr(target_vendor = "uwp", allow(unused))]
pub type LONG = c_long;
pub type UINT = c_uint;
pub type WCHAR = u16;
@@ -267,6 +267,8 @@ pub unsafe fn getaddrinfo(
windows_sys::getaddrinfo(node.cast::<u8>(), service.cast::<u8>(), hints, res)
}
+cfg_if::cfg_if! {
+if #[cfg(not(target_vendor = "uwp"))] {
pub unsafe fn NtReadFile(
filehandle: BorrowedHandle<'_>,
event: HANDLE,
@@ -313,6 +315,8 @@ pub unsafe fn NtWriteFile(
key.map(|k| k as *const u32).unwrap_or(ptr::null()),
)
}
+}
+}
// Functions that aren't available on every version of Windows that we support,
// but we still use them and just provide some form of a fallback implementation.
@@ -376,4 +380,98 @@ compat_fn_with_fallback! {
) -> NTSTATUS {
panic!("keyed events not available")
}
+
+ // These functions are available on UWP when lazily loaded. They will fail WACK if loaded statically.
+ #[cfg(target_vendor = "uwp")]
+ pub fn NtCreateFile(
+ filehandle: *mut HANDLE,
+ desiredaccess: FILE_ACCESS_RIGHTS,
+ objectattributes: *const OBJECT_ATTRIBUTES,
+ iostatusblock: *mut IO_STATUS_BLOCK,
+ allocationsize: *const i64,
+ fileattributes: FILE_FLAGS_AND_ATTRIBUTES,
+ shareaccess: FILE_SHARE_MODE,
+ createdisposition: NTCREATEFILE_CREATE_DISPOSITION,
+ createoptions: NTCREATEFILE_CREATE_OPTIONS,
+ eabuffer: *const ::core::ffi::c_void,
+ ealength: u32
+ ) -> NTSTATUS {
+ STATUS_NOT_IMPLEMENTED
+ }
+ #[cfg(target_vendor = "uwp")]
+ pub fn NtReadFile(
+ filehandle: BorrowedHandle<'_>,
+ event: HANDLE,
+ apcroutine: PIO_APC_ROUTINE,
+ apccontext: *mut c_void,
+ iostatusblock: &mut IO_STATUS_BLOCK,
+ buffer: *mut crate::mem::MaybeUninit<u8>,
+ length: ULONG,
+ byteoffset: Option<&LARGE_INTEGER>,
+ key: Option<&ULONG>
+ ) -> NTSTATUS {
+ STATUS_NOT_IMPLEMENTED
+ }
+ #[cfg(target_vendor = "uwp")]
+ pub fn NtWriteFile(
+ filehandle: BorrowedHandle<'_>,
+ event: HANDLE,
+ apcroutine: PIO_APC_ROUTINE,
+ apccontext: *mut c_void,
+ iostatusblock: &mut IO_STATUS_BLOCK,
+ buffer: *const u8,
+ length: ULONG,
+ byteoffset: Option<&LARGE_INTEGER>,
+ key: Option<&ULONG>
+ ) -> NTSTATUS {
+ STATUS_NOT_IMPLEMENTED
+ }
+ #[cfg(target_vendor = "uwp")]
+ pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> u32 {
+ Status as u32
+ }
+}
+
+// # Arm32 shim
+//
+// AddVectoredExceptionHandler and WSAStartup use platform-specific types.
+// However, Microsoft no longer supports thumbv7a so definitions for those targets
+// are not included in the win32 metadata. We work around that by defining them here.
+//
+// Where possible, these definitions should be kept in sync with https://docs.rs/windows-sys
+cfg_if::cfg_if! {
+if #[cfg(not(target_vendor = "uwp"))] {
+ #[link(name = "kernel32")]
+ extern "system" {
+ pub fn AddVectoredExceptionHandler(
+ first: u32,
+ handler: PVECTORED_EXCEPTION_HANDLER,
+ ) -> *mut c_void;
+ }
+ pub type PVECTORED_EXCEPTION_HANDLER = Option<
+ unsafe extern "system" fn(exceptioninfo: *mut EXCEPTION_POINTERS) -> i32,
+ >;
+ #[repr(C)]
+ pub struct EXCEPTION_POINTERS {
+ pub ExceptionRecord: *mut EXCEPTION_RECORD,
+ pub ContextRecord: *mut CONTEXT,
+ }
+ #[cfg(target_arch = "arm")]
+ pub enum CONTEXT {}
+}}
+
+#[link(name = "ws2_32")]
+extern "system" {
+ pub fn WSAStartup(wversionrequested: u16, lpwsadata: *mut WSADATA) -> i32;
+}
+#[cfg(target_arch = "arm")]
+#[repr(C)]
+pub struct WSADATA {
+ pub wVersion: u16,
+ pub wHighVersion: u16,
+ pub szDescription: [u8; 257],
+ pub szSystemStatus: [u8; 129],
+ pub iMaxSockets: u16,
+ pub iMaxUdpDg: u16,
+ pub lpVendorInfo: PSTR,
}
diff --git a/library/std/src/sys/windows/c/windows_sys.lst b/library/std/src/sys/windows/c/windows_sys.lst
index 3e454199f..631aedd26 100644
--- a/library/std/src/sys/windows/c/windows_sys.lst
+++ b/library/std/src/sys/windows/c/windows_sys.lst
@@ -1930,6 +1930,7 @@ Windows.Win32.Foundation.SetLastError
Windows.Win32.Foundation.STATUS_DELETE_PENDING
Windows.Win32.Foundation.STATUS_END_OF_FILE
Windows.Win32.Foundation.STATUS_INVALID_PARAMETER
+Windows.Win32.Foundation.STATUS_NOT_IMPLEMENTED
Windows.Win32.Foundation.STATUS_PENDING
Windows.Win32.Foundation.STATUS_SUCCESS
Windows.Win32.Foundation.TRUE
@@ -2170,7 +2171,6 @@ Windows.Win32.Networking.WinSock.WSARecv
Windows.Win32.Networking.WinSock.WSASend
Windows.Win32.Networking.WinSock.WSASERVICE_NOT_FOUND
Windows.Win32.Networking.WinSock.WSASocketW
-Windows.Win32.Networking.WinSock.WSAStartup
Windows.Win32.Networking.WinSock.WSASYSCALLFAILURE
Windows.Win32.Networking.WinSock.WSASYSNOTREADY
Windows.Win32.Networking.WinSock.WSATRY_AGAIN
@@ -2418,12 +2418,10 @@ Windows.Win32.System.Console.STD_HANDLE
Windows.Win32.System.Console.STD_INPUT_HANDLE
Windows.Win32.System.Console.STD_OUTPUT_HANDLE
Windows.Win32.System.Console.WriteConsoleW
-Windows.Win32.System.Diagnostics.Debug.AddVectoredExceptionHandler
Windows.Win32.System.Diagnostics.Debug.ARM64_NT_NEON128
Windows.Win32.System.Diagnostics.Debug.CONTEXT
Windows.Win32.System.Diagnostics.Debug.CONTEXT
Windows.Win32.System.Diagnostics.Debug.CONTEXT
-Windows.Win32.System.Diagnostics.Debug.EXCEPTION_POINTERS
Windows.Win32.System.Diagnostics.Debug.EXCEPTION_RECORD
Windows.Win32.System.Diagnostics.Debug.FACILITY_CODE
Windows.Win32.System.Diagnostics.Debug.FACILITY_NT_BIT
@@ -2436,7 +2434,6 @@ Windows.Win32.System.Diagnostics.Debug.FORMAT_MESSAGE_IGNORE_INSERTS
Windows.Win32.System.Diagnostics.Debug.FORMAT_MESSAGE_OPTIONS
Windows.Win32.System.Diagnostics.Debug.FormatMessageW
Windows.Win32.System.Diagnostics.Debug.M128A
-Windows.Win32.System.Diagnostics.Debug.PVECTORED_EXCEPTION_HANDLER
Windows.Win32.System.Diagnostics.Debug.XSAVE_FORMAT
Windows.Win32.System.Diagnostics.Debug.XSAVE_FORMAT
Windows.Win32.System.Environment.FreeEnvironmentStringsW
diff --git a/library/std/src/sys/windows/c/windows_sys.rs b/library/std/src/sys/windows/c/windows_sys.rs
index 36a30f6ba..023770871 100644
--- a/library/std/src/sys/windows/c/windows_sys.rs
+++ b/library/std/src/sys/windows/c/windows_sys.rs
@@ -40,13 +40,6 @@ extern "system" {
}
#[link(name = "kernel32")]
extern "system" {
- pub fn AddVectoredExceptionHandler(
- first: u32,
- handler: PVECTORED_EXCEPTION_HANDLER,
- ) -> *mut ::core::ffi::c_void;
-}
-#[link(name = "kernel32")]
-extern "system" {
pub fn CancelIo(hfile: HANDLE) -> BOOL;
}
#[link(name = "kernel32")]
@@ -712,10 +705,6 @@ extern "system" {
}
#[link(name = "ws2_32")]
extern "system" {
- pub fn WSAStartup(wversionrequested: u16, lpwsadata: *mut WSADATA) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
pub fn accept(s: SOCKET, addr: *mut SOCKADDR, addrlen: *mut i32) -> SOCKET;
}
#[link(name = "ws2_32")]
@@ -3029,17 +3018,6 @@ pub const ERROR_XML_PARSE_ERROR: WIN32_ERROR = 1465u32;
pub type EXCEPTION_DISPOSITION = i32;
pub const EXCEPTION_MAXIMUM_PARAMETERS: u32 = 15u32;
#[repr(C)]
-pub struct EXCEPTION_POINTERS {
- pub ExceptionRecord: *mut EXCEPTION_RECORD,
- pub ContextRecord: *mut CONTEXT,
-}
-impl ::core::marker::Copy for EXCEPTION_POINTERS {}
-impl ::core::clone::Clone for EXCEPTION_POINTERS {
- fn clone(&self) -> Self {
- *self
- }
-}
-#[repr(C)]
pub struct EXCEPTION_RECORD {
pub ExceptionCode: NTSTATUS,
pub ExceptionFlags: u32,
@@ -3748,9 +3726,6 @@ pub const PROFILE_SERVER: PROCESS_CREATION_FLAGS = 1073741824u32;
pub const PROFILE_USER: PROCESS_CREATION_FLAGS = 268435456u32;
pub const PROGRESS_CONTINUE: u32 = 0u32;
pub type PSTR = *mut u8;
-pub type PVECTORED_EXCEPTION_HANDLER = ::core::option::Option<
- unsafe extern "system" fn(exceptioninfo: *mut EXCEPTION_POINTERS) -> i32,
->;
pub type PWSTR = *mut u16;
pub const READ_CONTROL: FILE_ACCESS_RIGHTS = 131072u32;
pub const REALTIME_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 256u32;
@@ -3888,6 +3863,7 @@ pub type STARTUPINFOW_FLAGS = u32;
pub const STATUS_DELETE_PENDING: NTSTATUS = -1073741738i32;
pub const STATUS_END_OF_FILE: NTSTATUS = -1073741807i32;
pub const STATUS_INVALID_PARAMETER: NTSTATUS = -1073741811i32;
+pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = -1073741822i32;
pub const STATUS_PENDING: NTSTATUS = 259i32;
pub const STATUS_SUCCESS: NTSTATUS = 0i32;
pub const STD_ERROR_HANDLE: STD_HANDLE = 4294967284u32;
diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs
index 2404bbe2b..1ae42cb7e 100644
--- a/library/std/src/sys/windows/net.rs
+++ b/library/std/src/sys/windows/net.rs
@@ -159,7 +159,7 @@ impl Socket {
}
let mut timeout = c::timeval {
- tv_sec: timeout.as_secs() as c_long,
+ tv_sec: cmp::min(timeout.as_secs(), c_long::MAX as u64) as c_long,
tv_usec: (timeout.subsec_nanos() / 1000) as c_long,
};
diff --git a/library/std/src/sys/windows/os_str.rs b/library/std/src/sys/windows/os_str.rs
index 2f2b0e56e..16c4f55c6 100644
--- a/library/std/src/sys/windows/os_str.rs
+++ b/library/std/src/sys/windows/os_str.rs
@@ -152,11 +152,21 @@ impl Buf {
impl Slice {
#[inline]
+ pub fn as_os_str_bytes(&self) -> &[u8] {
+ self.inner.as_bytes()
+ }
+
+ #[inline]
+ pub unsafe fn from_os_str_bytes_unchecked(s: &[u8]) -> &Slice {
+ mem::transmute(Wtf8::from_bytes_unchecked(s))
+ }
+
+ #[inline]
pub fn from_str(s: &str) -> &Slice {
unsafe { mem::transmute(Wtf8::from_str(s)) }
}
- pub fn to_str(&self) -> Option<&str> {
+ pub fn to_str(&self) -> Result<&str, crate::str::Utf8Error> {
self.inner.as_str()
}
diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs
index c3573d14c..c9c2d10e6 100644
--- a/library/std/src/sys/windows/path.rs
+++ b/library/std/src/sys/windows/path.rs
@@ -1,7 +1,6 @@
use super::{c, fill_utf16_buf, to_u16s};
use crate::ffi::{OsStr, OsString};
use crate::io;
-use crate::mem;
use crate::path::{Path, PathBuf, Prefix};
use crate::ptr;
@@ -11,16 +10,6 @@ mod tests;
pub const MAIN_SEP_STR: &str = "\\";
pub const MAIN_SEP: char = '\\';
-/// # Safety
-///
-/// `bytes` must be a valid wtf8 encoded slice
-#[inline]
-unsafe fn bytes_as_os_str(bytes: &[u8]) -> &OsStr {
- // &OsStr is layout compatible with &Slice, which is compatible with &Wtf8,
- // which is compatible with &[u8].
- mem::transmute(bytes)
-}
-
#[inline]
pub fn is_sep_byte(b: u8) -> bool {
b == b'/' || b == b'\\'
@@ -33,12 +22,12 @@ pub fn is_verbatim_sep(b: u8) -> bool {
/// Returns true if `path` looks like a lone filename.
pub(crate) fn is_file_name(path: &OsStr) -> bool {
- !path.bytes().iter().copied().any(is_sep_byte)
+ !path.as_os_str_bytes().iter().copied().any(is_sep_byte)
}
pub(crate) fn has_trailing_slash(path: &OsStr) -> bool {
- let is_verbatim = path.bytes().starts_with(br"\\?\");
+ let is_verbatim = path.as_os_str_bytes().starts_with(br"\\?\");
let is_separator = if is_verbatim { is_verbatim_sep } else { is_sep_byte };
- if let Some(&c) = path.bytes().last() { is_separator(c) } else { false }
+ if let Some(&c) = path.as_os_str_bytes().last() { is_separator(c) } else { false }
}
/// Appends a suffix to a path.
@@ -60,7 +49,7 @@ impl<'a, const LEN: usize> PrefixParser<'a, LEN> {
fn get_prefix(path: &OsStr) -> [u8; LEN] {
let mut prefix = [0; LEN];
// SAFETY: Only ASCII characters are modified.
- for (i, &ch) in path.bytes().iter().take(LEN).enumerate() {
+ for (i, &ch) in path.as_os_str_bytes().iter().take(LEN).enumerate() {
prefix[i] = if ch == b'/' { b'\\' } else { ch };
}
prefix
@@ -93,7 +82,7 @@ impl<'a> PrefixParserSlice<'a, '_> {
}
fn prefix_bytes(&self) -> &'a [u8] {
- &self.path.bytes()[..self.index]
+ &self.path.as_os_str_bytes()[..self.index]
}
fn finish(self) -> &'a OsStr {
@@ -101,7 +90,7 @@ impl<'a> PrefixParserSlice<'a, '_> {
// &[u8] and back. This is safe to do because (1) we only look at ASCII
// contents of the encoding and (2) new &OsStr values are produced only
// from ASCII-bounded slices of existing &OsStr values.
- unsafe { bytes_as_os_str(&self.path.bytes()[self.index..]) }
+ unsafe { OsStr::from_os_str_bytes_unchecked(&self.path.as_os_str_bytes()[self.index..]) }
}
}
@@ -173,7 +162,7 @@ fn parse_drive(path: &OsStr) -> Option<u8> {
drive.is_ascii_alphabetic()
}
- match path.bytes() {
+ match path.as_os_str_bytes() {
[drive, b':', ..] if is_valid_drive_letter(drive) => Some(drive.to_ascii_uppercase()),
_ => None,
}
@@ -182,7 +171,7 @@ fn parse_drive(path: &OsStr) -> Option<u8> {
// Parses a drive prefix exactly, e.g. "C:"
fn parse_drive_exact(path: &OsStr) -> Option<u8> {
// only parse two bytes: the drive letter and the drive separator
- if path.bytes().get(2).map(|&x| is_sep_byte(x)).unwrap_or(true) {
+ if path.as_os_str_bytes().get(2).map(|&x| is_sep_byte(x)).unwrap_or(true) {
parse_drive(path)
} else {
None
@@ -196,21 +185,26 @@ fn parse_drive_exact(path: &OsStr) -> Option<u8> {
fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) {
let separator = if verbatim { is_verbatim_sep } else { is_sep_byte };
- match path.bytes().iter().position(|&x| separator(x)) {
+ match path.as_os_str_bytes().iter().position(|&x| separator(x)) {
Some(separator_start) => {
let separator_end = separator_start + 1;
- let component = &path.bytes()[..separator_start];
+ let component = &path.as_os_str_bytes()[..separator_start];
// Panic safe
// The max `separator_end` is `bytes.len()` and `bytes[bytes.len()..]` is a valid index.
- let path = &path.bytes()[separator_end..];
+ let path = &path.as_os_str_bytes()[separator_end..];
// SAFETY: `path` is a valid wtf8 encoded slice and each of the separators ('/', '\')
// is encoded in a single byte, therefore `bytes[separator_start]` and
// `bytes[separator_end]` must be code point boundaries and thus
// `bytes[..separator_start]` and `bytes[separator_end..]` are valid wtf8 slices.
- unsafe { (bytes_as_os_str(component), bytes_as_os_str(path)) }
+ unsafe {
+ (
+ OsStr::from_os_str_bytes_unchecked(component),
+ OsStr::from_os_str_bytes_unchecked(path),
+ )
+ }
}
None => (path, OsStr::new("")),
}
@@ -329,7 +323,7 @@ pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
// Verbatim paths should not be modified.
if prefix.map(|x| x.is_verbatim()).unwrap_or(false) {
// NULs in verbatim paths are rejected for consistency.
- if path.bytes().contains(&0) {
+ if path.as_os_str_bytes().contains(&0) {
return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
"strings passed to WinAPI cannot contain NULs",
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index df3667c0f..e3493cbb8 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -395,7 +395,7 @@ fn resolve_exe<'a>(
// Test if the file name has the `exe` extension.
// This does a case-insensitive `ends_with`.
let has_exe_suffix = if exe_path.len() >= EXE_SUFFIX.len() {
- exe_path.bytes()[exe_path.len() - EXE_SUFFIX.len()..]
+ exe_path.as_os_str_bytes()[exe_path.len() - EXE_SUFFIX.len()..]
.eq_ignore_ascii_case(EXE_SUFFIX.as_bytes())
} else {
false
@@ -425,7 +425,7 @@ fn resolve_exe<'a>(
// From the `CreateProcessW` docs:
// > If the file name does not contain an extension, .exe is appended.
// Note that this rule only applies when searching paths.
- let has_extension = exe_path.bytes().contains(&b'.');
+ let has_extension = exe_path.as_os_str_bytes().contains(&b'.');
// Search the directories given by `search_paths`.
let result = search_paths(parent_paths, child_paths, |mut path| {
@@ -595,7 +595,16 @@ pub struct Process {
impl Process {
pub fn kill(&mut self) -> io::Result<()> {
- cvt(unsafe { c::TerminateProcess(self.handle.as_raw_handle(), 1) })?;
+ let result = unsafe { c::TerminateProcess(self.handle.as_raw_handle(), 1) };
+ if result == c::FALSE {
+ let error = unsafe { c::GetLastError() };
+ // TerminateProcess returns ERROR_ACCESS_DENIED if the process has already been
+ // terminated (by us, or for any other reason). So check if the process was actually
+ // terminated, and if so, do not return an error.
+ if error != c::ERROR_ACCESS_DENIED || self.try_wait().is_err() {
+ return Err(crate::io::Error::from_raw_os_error(error as i32));
+ }
+ }
Ok(())
}
diff --git a/library/std/src/sys/windows/rand.rs b/library/std/src/sys/windows/rand.rs
index bca4e38d9..5d8fd1378 100644
--- a/library/std/src/sys/windows/rand.rs
+++ b/library/std/src/sys/windows/rand.rs
@@ -1,5 +1,3 @@
-use crate::ffi::c_void;
-use crate::io;
use crate::mem;
use crate::ptr;
use crate::sys::c;
@@ -25,6 +23,9 @@ pub fn hashmap_random_keys() -> (u64, u64) {
#[cfg(not(target_vendor = "uwp"))]
#[inline(never)]
fn fallback_rng() -> (u64, u64) {
+ use crate::ffi::c_void;
+ use crate::io;
+
let mut v = (0, 0);
let ret = unsafe {
c::RtlGenRandom(&mut v as *mut _ as *mut c_void, mem::size_of_val(&v) as c::ULONG)
diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs
index 2e3e0859d..3fcaaa508 100644
--- a/library/std/src/sys/windows/stdio.rs
+++ b/library/std/src/sys/windows/stdio.rs
@@ -11,6 +11,9 @@ use crate::sys::cvt;
use crate::sys::handle::Handle;
use core::str::utf8_char_width;
+#[cfg(test)]
+mod tests;
+
// Don't cache handles but get them fresh for every read/write. This allows us to track changes to
// the value over time (such as if a process calls `SetStdHandle` while it's running). See #40490.
pub struct Stdin {
@@ -383,6 +386,10 @@ fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result<usize> {
debug_assert!(utf16.len() <= c::c_int::MAX as usize);
debug_assert!(utf8.len() <= c::c_int::MAX as usize);
+ if utf16.is_empty() {
+ return Ok(0);
+ }
+
let result = unsafe {
c::WideCharToMultiByte(
c::CP_UTF8, // CodePage
diff --git a/library/std/src/sys/windows/stdio/tests.rs b/library/std/src/sys/windows/stdio/tests.rs
new file mode 100644
index 000000000..1e53e0bee
--- /dev/null
+++ b/library/std/src/sys/windows/stdio/tests.rs
@@ -0,0 +1,6 @@
+use super::utf16_to_utf8;
+
+#[test]
+fn zero_size_read() {
+ assert_eq!(utf16_to_utf8(&[], &mut []).unwrap(), 0);
+}
diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs
index 652c695fc..2976a9f57 100644
--- a/library/std/src/sys_common/net.rs
+++ b/library/std/src/sys_common/net.rs
@@ -18,7 +18,7 @@ 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 = "ios", target_os = "tvos", 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 = "nto"))] {
use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs
index ff96c35fb..c9d3e13cf 100644
--- a/library/std/src/sys_common/wtf8.rs
+++ b/library/std/src/sys_common/wtf8.rs
@@ -570,7 +570,7 @@ impl Wtf8 {
/// Since the byte slice is not checked for valid WTF-8, this functions is
/// marked unsafe.
#[inline]
- unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 {
+ pub unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 {
mem::transmute(value)
}
@@ -614,19 +614,20 @@ impl Wtf8 {
Wtf8CodePoints { bytes: self.bytes.iter() }
}
+ /// Access raw bytes of WTF-8 data
+ #[inline]
+ pub fn as_bytes(&self) -> &[u8] {
+ &self.bytes
+ }
+
/// Tries to convert the string to UTF-8 and return a `&str` slice.
///
/// Returns `None` if the string contains surrogates.
///
/// This does not copy the data.
#[inline]
- pub fn as_str(&self) -> Option<&str> {
- // Well-formed WTF-8 is also well-formed UTF-8
- // if and only if it contains no surrogate.
- match self.next_surrogate(0) {
- None => Some(unsafe { str::from_utf8_unchecked(&self.bytes) }),
- Some(_) => None,
- }
+ pub fn as_str(&self) -> Result<&str, str::Utf8Error> {
+ str::from_utf8(&self.bytes)
}
/// Creates an owned `Wtf8Buf` from a borrowed `Wtf8`.
diff --git a/library/std/src/sys_common/wtf8/tests.rs b/library/std/src/sys_common/wtf8/tests.rs
index 1a302d646..a07bbe6d7 100644
--- a/library/std/src/sys_common/wtf8/tests.rs
+++ b/library/std/src/sys_common/wtf8/tests.rs
@@ -521,11 +521,11 @@ fn wtf8_code_points() {
#[test]
fn wtf8_as_str() {
- assert_eq!(Wtf8::from_str("").as_str(), Some(""));
- assert_eq!(Wtf8::from_str("aé 💩").as_str(), Some("aé 💩"));
+ assert_eq!(Wtf8::from_str("").as_str(), Ok(""));
+ assert_eq!(Wtf8::from_str("aé 💩").as_str(), Ok("aé 💩"));
let mut string = Wtf8Buf::new();
string.push(CodePoint::from_u32(0xD800).unwrap());
- assert_eq!(string.as_str(), None);
+ assert!(string.as_str().is_err());
}
#[test]
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index f712c8727..e4581c2de 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -195,7 +195,7 @@ mod local;
cfg_if::cfg_if! {
if #[cfg(test)] {
- // Avoid duplicating the global state assoicated with thread-locals between this crate and
+ // Avoid duplicating the global state associated with thread-locals between this crate and
// realstd. Miri relies on this.
pub use realstd::thread::{local_impl, AccessError, LocalKey};
} else {
@@ -206,7 +206,7 @@ cfg_if::cfg_if! {
#[doc(hidden)]
#[unstable(feature = "thread_local_internals", issue = "none")]
pub mod local_impl {
- pub use crate::sys::common::thread_local::{thread_local_inner, Key};
+ pub use crate::sys::common::thread_local::{thread_local_inner, Key, abort_on_dtor_unwind};
}
}
}
@@ -889,7 +889,7 @@ impl Drop for PanicGuard {
/// it is guaranteed that this function will not panic (it may abort the
/// process if the implementation encounters some rare errors).
///
-/// # park and unpark
+/// # `park` and `unpark`
///
/// Every thread is equipped with some basic low-level blocking support, via the
/// [`thread::park`][`park`] function and [`thread::Thread::unpark`][`unpark`]
@@ -910,14 +910,6 @@ impl Drop for PanicGuard {
/// if it wasn't already. Because the token is initially absent, [`unpark`]
/// followed by [`park`] will result in the second call returning immediately.
///
-/// In other words, each [`Thread`] acts a bit like a spinlock that can be
-/// locked and unlocked using `park` and `unpark`.
-///
-/// Notice that being unblocked does not imply any synchronization with someone
-/// that unparked this thread, it could also be spurious.
-/// For example, it would be a valid, but inefficient, implementation to make both [`park`] and
-/// [`unpark`] return immediately without doing anything.
-///
/// The API is typically used by acquiring a handle to the current thread,
/// placing that handle in a shared data structure so that other threads can
/// find it, and then `park`ing in a loop. When some desired condition is met, another
@@ -931,6 +923,23 @@ impl Drop for PanicGuard {
///
/// * It can be implemented very efficiently on many platforms.
///
+/// # Memory Ordering
+///
+/// Calls to `park` _synchronize-with_ calls to `unpark`, meaning that memory
+/// operations performed before a call to `unpark` are made visible to the thread that
+/// consumes the token and returns from `park`. Note that all `park` and `unpark`
+/// operations for a given thread form a total order and `park` synchronizes-with
+/// _all_ prior `unpark` operations.
+///
+/// In atomic ordering terms, `unpark` performs a `Release` operation and `park`
+/// performs the corresponding `Acquire` operation. Calls to `unpark` for the same
+/// thread form a [release sequence].
+///
+/// Note that being unblocked does not imply a call was made to `unpark`, because
+/// wakeups can also be spurious. For example, a valid, but inefficient,
+/// implementation could have `park` and `unpark` return immediately without doing anything,
+/// making *all* wakeups spurious.
+///
/// # Examples
///
/// ```
@@ -944,7 +953,7 @@ impl Drop for PanicGuard {
/// let parked_thread = thread::spawn(move || {
/// // We want to wait until the flag is set. We *could* just spin, but using
/// // park/unpark is more efficient.
-/// while !flag2.load(Ordering::Acquire) {
+/// while !flag2.load(Ordering::Relaxed) {
/// println!("Parking thread");
/// thread::park();
/// // We *could* get here spuriously, i.e., way before the 10ms below are over!
@@ -961,7 +970,7 @@ impl Drop for PanicGuard {
/// // There is no race condition here, if `unpark`
/// // happens first, `park` will return immediately.
/// // Hence there is no risk of a deadlock.
-/// flag.store(true, Ordering::Release);
+/// flag.store(true, Ordering::Relaxed);
/// println!("Unpark the thread");
/// parked_thread.thread().unpark();
///
@@ -970,6 +979,7 @@ impl Drop for PanicGuard {
///
/// [`unpark`]: Thread::unpark
/// [`thread::park_timeout`]: park_timeout
+/// [release sequence]: https://en.cppreference.com/w/cpp/atomic/memory_order#Release_sequence
#[stable(feature = "rust1", since = "1.0.0")]
pub fn park() {
let guard = PanicGuard;
diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs
index b65e2572c..5d6b9e94e 100644
--- a/library/std/src/thread/tests.rs
+++ b/library/std/src/thread/tests.rs
@@ -42,6 +42,7 @@ fn test_named_thread() {
all(target_os = "linux", target_env = "gnu"),
target_os = "macos",
target_os = "ios",
+ target_os = "tvos",
target_os = "watchos"
))]
#[test]
diff --git a/library/std/tests/common/mod.rs b/library/std/tests/common/mod.rs
index fce220223..358c2c3f9 100644
--- a/library/std/tests/common/mod.rs
+++ b/library/std/tests/common/mod.rs
@@ -20,15 +20,15 @@ pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
}
// Copied from std::sys_common::io
-pub struct TempDir(PathBuf);
+pub(crate) struct TempDir(PathBuf);
impl TempDir {
- pub fn join(&self, path: &str) -> PathBuf {
+ pub(crate) fn join(&self, path: &str) -> PathBuf {
let TempDir(ref p) = *self;
p.join(path)
}
- pub fn path(&self) -> &Path {
+ pub(crate) fn path(&self) -> &Path {
let TempDir(ref p) = *self;
p
}
@@ -49,7 +49,7 @@ impl Drop for TempDir {
}
#[track_caller] // for `test_rng`
-pub fn tmpdir() -> TempDir {
+pub(crate) fn tmpdir() -> TempDir {
let p = env::temp_dir();
let mut r = test_rng();
let ret = p.join(&format!("rust-{}", r.next_u32()));